Niezalogowany [ logowanie ]
Subskrybuj kanał ATOM Kanał ATOM    Subskrybuj kanał ATOM dla tagu zend_framework Kanał ATOM (tag: zend_framework)

Autor wpisu: singles, dodany: 11.06.2011 12:33, tagi: php, zend_framework

Kolejny wpis z serii Zend Framework Quick Tip

Podstawowym elementem sporej liczby aplikacji internetowych jest datagrid – tabela, której zawartość można filtrować, sortować, z pagerem. W ostatnio wykonywanej aplikacji natrafiliśmy na potrzebę wykorzystania tych samych datagridów w kilku miejsach.

Potrzeba

Do stworzenia gridów wykorzystaliśmy do tego celu bibliotekę ZFDataGrid (która wymagała kilkunastu poprawek, ale i tak nie znaleźliśmy niczego lepszego). Utworzyliśmy jedną bazową klasę Grid i po niej dziedziczyły wszystkie gridy zawarte w aplikacji, definiując własne źródła danych, filtry czy też akcje. Do pełni szczęścia brakowało, aby ładowane były na żądanie, wykorzystując domyślny Zendowy autoloader. Okazało się, że jest bardzo prosty sposób na osiągnięcie takiej funkcjonalności.

Implementacja

ZF domyślnie mapuje kilka rodzajów zasobów (resources) na ścieżkę w strukurze plików. Należą do nich:

Zend Framework Base Resources

Lista domyślnie zdefiniowanych ścieżek w ZF - na bazie " Getting Started with Zend Framework 1.11" Roba Allen'a

Nam brakowało jeszcze prefixu Grid, który mapowałby na ścieżkę grids. Szybkie spojrzenie do manuala i mamy rozwiązanie. Wszystko ogranicziło się do dodania następującego kodu do Bootstrap.php:

/**
 * Register 'Grid', so they could be created the same way like forms, models, etc.
 */
protected function _initGridsAutoload()
{
    $this->getResourceLoader()
         ->addResourceType('grid', 'grids', 'Grid');
 
    //or for many custom resources
    /*
    $this->getResourceLoader()->addResourceTypes(array(
        'item' => array(
            'path'      => 'items/',
            'namespace' => 'Item',
        ),
        'task' => array(
            'path'      => 'some/deep/folder/tasks',
            'namespace' => 'Task'
        )
    ));
    */
}

Pierwszy parametr to wewnętrzny klucz dla loadera, drugi to ścieżka, pod jaką mają być szukane pliki – zaczynając od `application/’, a trzeci to prefix jakiego będziemy używać w aplikacji. I tyle :) Od tego momenu w można wykorzystywać konstrukcję:

$grid = new Grid_Users(); // autoload files application/grids/User.php

Podany przykład dla applicationNamespace = ” – w przypadku kiedy wykorzystujecie namespace powiedzmy My, albo App, będzie to oczywście `App_Grid_Users_.

Autor wpisu: sokzzuka, dodany: 30.05.2011 14:29, tagi: php, zend_framework

Każdy używający Zend Frameworka wcześniej czy później natknie się na klasę służącą do tworzenia formularzy – Zend Form. Jest to całkiem przydatna klasa i znakomicie się sprawdza. Sprawdza się świetnie do momentu, kiedy nasz webmaster stwierdzi, że jednak ubranie formularza w dl/dt/dd jest już passe i przydało by się np. ubrać go w tagi ul/li. Mnie właśnie dzisiaj przydarzyła się taka sytuacja, a więc ku pamięci wrzucam rozwiązanie:


class Form extends Zend_Form
public function init() {

        $email = new Zend_Form_Element_Text('email');
        $email->setLabel('Email:');
        $email->addValidator(new Zend_Validate_EmailAddress());
        $email->setRequired();

        $firstName = new Zend_Form_Element_Text('first_name');
        $firstName->setLabel('First name:');
        $firstName->setRequired();

        $lastName = new Zend_Form_Element_Text('last_name');
        $lastName->setLabel('Last name');
        $lastName->setRequired();

        $this->addElements(array($email, $firstName, $lastName));
}

 public function loadDefaultDecorators() {
        parent::loadDefaultDecorators();

        $this->_decorators['HtmlTag']['options']['tag'] = 'ul';

        foreach ($this->_elements as $el) {
            if ($el instanceof Zend_Form_Element_Text) {
                $el->removeDecorator('HtmlTag');
                $el->removeDecorator('Label');

                $el->addDecorator('Label', array('tag' => null));
                $el->addDecorator('HtmlTag', array('tag' => 'li'));
            }

            if ($el instanceof Zend_Form_Element_Submit) {
                $el->removeDecorator('Label');
                $el->removeDecorator('DtDdWrapper');
                $el->addDecorator('HtmlTag', array('tag' => 'li'));
            }
        }
    }

}

Co jak i dlaczego ?

Pierwsze na co należy zwrócić uwagę to miejsce modyfikacji dekoratorów – robimy to w metodzie loadDefaultDecorators(). Jest ona wywoływana jako ostatnia metoda w konstruktorze klasy Zend_Form i dzięki temu mamy już dostęp do wszystkich koniecznych obiektów i pól.

Kolejna kwestia na która trzeba zwrócić uwagę to rozróżnienie pomiędzy różnymi rodzajami elementów formularza. Różne klasy mają różne dekoratory w standardzie.

Najbardziej zastanawiający fragment tego kodu to:

                $el->removeDecorator('HtmlTag');
                $el->removeDecorator('Label');

                $el->addDecorator('Label', array('tag' => null));
                $el->addDecorator('HtmlTag', array('tag' => 'li'));

Po co najpierw usuwać a następnie ponownie dodawać te same dekoratory ? Ano po to by zamienić je miejscami ;) . Flow dekoratorów jest taki, że każdy dekorator dodany później dostaje cały kontent wygenerowany przez te, które były dodane wcześniej. Dzięki temu możemy hierarchicznie budować strukturę HTML-a.

Btw. Powyższy kod jest z takiej niezbyt świeżej wersji frameworka. Także, jeżeli coś się zmieniło to z góry przepraszam i chętnie przyjmę kod na nowszej wersji ;)

Autor wpisu: batman, dodany: 19.05.2011 18:00, tagi: zend_framework

Zend_Acl jest jednym z komponentów Zend Frameworka, bez których tworzenie rozbudowanych aplikacji byłoby znacznie trudniejsze. W skrócie Zend_Acl dostarcza informację o tym, czy rola ma dostęp do zasobu. Utworzenie zależności między rolami oraz zasobami spoczywa na naszych barkach, podobnie jak wykonanie odpowiedniej akcji w przypadku braku dostępu. Manual świetnie opisuje sposoby dodawania ról, zasobów oraz zależności między nimi. Niestety ani słowem nie wspomina o sposobie wykorzystania tej wiedzy w prawdziwej aplikacji.

Definiowanie zasobów i ról

Pierwszym etapem w tworzeniu aplikacji korzystającej z Zend_Acl jest określenie ról oraz zasobów występujących w aplikacji. Sposobów przechowywania tych informacji jest kilka, od plików ini począwszy, na bazie danych kończąc. Ponieważ sposoby te różnią się od siebie tylko sposobem przechowywania danych, do przykładów będę stosował pliki ini.

Zdefiniujmy najpierw zasoby.

acl.resources[] = "index_index"
acl.resources[] = "user_list"
acl.resources[] = "user_edit"
acl.resources[] = "user_add"
acl.resources[] = "user_delete"

Jak zapewne się domyślacie, pierwszy człon nazwy zasobu określa nazwę kontrolera, drugi nazwę akcji. Jeśli w aplikacji występują moduły, przez nazwą kontrolera można dodać kolejny człon oznaczający nazwę modułu.

Role definiujemy w podobny sposób.

acl.roles[] = "admin"
acl.roles[] = "user"
acl.roles[] = "guest"

Na koniec pozostaje zdefiniowanie praw dostępu

acl.privileges.admin[] = "index_index"
acl.privileges.admin[] = "user_list"
acl.privileges.admin[] = "user_edit"
acl.privileges.admin[] = "user_add"
acl.privileges.admin[] = "user_delete"
acl.privileges.user[] = "index_index"
acl.privileges.user[] = "user_list"
acl.privileges.guest[] = "index_index"

Powyższy schemat dodawania ról, zasobów oraz uprawnień ma ta zaletę, iż w przypadku szybko rosnącej aplikacji można go bez problemowo przenieść np. do bazy danych, napisać prosty panel do zarządzania i zapomnieć o uzupełnianiu danych “z palca”.

Tworzymy ACL

Najlepszym miejscem do utworzenia Zend_Acl jest bootstrap.

class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
{
    protected function _initAcl()
    {
        $acl = new Zend_Acl();
        $aclOptions = $this->getOption('acl');

        foreach($aclOptions['roles'] as $role) {
            $acl->addRole(new Zend_Acl_Role($role));
        }

        foreach($aclOptions['resources'] as $resource) {
            $acl->addResource(new Zend_Acl_Resource($resource));
        }

        foreach($aclOptions['privileges'] as $role => $resource) {
            $acl->allow($role, $resource);
        }

        return $acl;
    }
}

Dlaczego właśnie bootstrap? Ponieważ w prosty sposób bez konieczności korzystania z rejestru możemy dostać się do obiektu Zend_Acl oraz bootstrap wykonuje się zawsze wykonuje jako pierwszy.

Warto wykorzystać tutaj cache, ponieważ generowanie całej listy ACL przy każdym żądaniu może mieć wpływ na wydajność aplikacji.

Czytaj dalej tutaj (rozwija treść wpisu)
Czytaj dalej na blogu autora...

Autor wpisu: singles, dodany: 09.04.2011 23:18, tagi: php, zend_framework, doctrine

Zend Framework składa się z wielu komponentów, a jednym z nich jest ten odpowiedzialny za komunikację z bazą danych – Zend_Db. Jednakże, celem tego wpisu nie jest opisywanie Zend_Db – to zostało zrobione już w dokumentacji. Celem tego wpisu jest wyrażenie mojej opinii na temat tego co mi się w Zend_Db podoba, a co nie – jest to oczywiście wpis czysto subiektywny. Traktuje ten wpis także jako przyczynek do dyskusji na temat, czy Zend_Db jest naprawdę tak złym komponentem, za jakiego ma go wielu programistów PHP – m.in patrz komentarze do wpisu u batmana. Chciałbym się także odnieść do podanych tam „zarzutów”. Niektóre z przedstawionych przeze mnie zalet bądź wad mogą Wam się wydawać śmieszne bądź banalne, ale kilka takich rzeczy połączonych ze sobą wpływa na wygodę korzystania z danego rozwiązania. Tak więc zaczynamy!

Zalety

Oparty głównie na PDO

Coraz więcej frameworków idzie tą drogą, co uważam za niewątpliwy plus. PDO de facto jest standardem w PHP i bardzo dobrze, że twórcy zdecydowanej większości frameworków się tego trzymają. Dzięki temu, kiedy przychodzi potrzeba napisania bardziej zaawansowanego zapytania możemy skorzystać ze znanych nam metod i oczekiwać tego samego, czego oczekiwaliśmy korzystając z czystego PDO.

Wygoda podczas stosowania klauzuli WHERE

Kwestia oczywiście w pełni subiektywna. Mam na myśli korzystanie głównie z metody fetchAll i automatycznego bindowania parametrów jako odpowiedni typ danych. Przykład:

$model->fetchAll(array(
    'item_id = ?' => 12, //bind as PDO::PARAM_INT, cast it using (string)12 to automatically bind as PDO::PARAM_STR
    'name = ?' => 'foobar', //PDO::PARAM_STR
    'category_id IN (?)' => arrray(1, 2, 4, 7) // bind each array element separately as PDO::PARAM_INT -> gives you: category_id IN (?, ?, ?, ?)
));

Stosunkowo mała liczba plików

Zend_Db w obecnej wersji frameworka (1.11.5) waży ok. 600KB i mieści się w 53 plikach – z czego 17 z nich to puste klasy wyjątków Exception.php. Dla porównania – Doctrine2 DBAL (czyli sama warstwa abstrakcji bazy danych) to 144 pliki, w tym 10 od wyjątków. Oczywiście, w obu przypadkach można te liczby jeszcze bardziej zmniejszyć, wyrzucając niepotrzebne adaptery.

ActiveRecord

Podoba mi się fakt, że mogę zdefiniować własne metody odnoszące się bezpośrednio do rekordu O ile twórcy ZF piszą o Zend_Db_Table_Row jako o implementacji Row Data Gateway, jednakże z punktu widzenia używającego go programisty niedaleko mu do ActiveRecord. Mam na myśli możliwość definiowania własnych metod odnoszących się do konkretnego rekordu. Banalny przykład:

// /application/models/Product.php
class Model_Product extends Zend_Db_Table_Abstract
{
    protected $_name = 'product';
    protected $_rowClass= 'Model_ProductRow'; //use Model_ProductRow instead Zend_Db_Table_Row
}
 
// application/models/ProductRow.php
class Model_ProductRow extends Zend_Db_Table_Row_Abstract
{
    public function getPriceWithTax()
    {
        return $this->price * 0.23; //where price is column in database defining price without VAT tax rate
    }
}

To samo tyczy się obiektów kolekcji – w przypadku Zend Frameworka dziedziczących po klasie Zend_Db_Table_Rowset. Mogę ustawić własną klasę, gdzie zaimplementuje potrzebne mi metody kolekcji.

Wspracie dla interfejsów ArrayAccess oraz Iterable w przypadku obiektów i kolekcji

Kolejna rzecz, która wpływa na wygodę. Mogę odnosić się do właściwości obiektu używając notacji tablicowej. Mogę także iterować po obiekcie kolekcji używając foreach, bez wykonywania za każdym razem toArray().

Zend_Db_Select == QueryBuilder

O ile na początku korzystanie z Zend_Db_Select sprawiało mi sporą trudność (moim kolegom z zespołu także), tak po pewnym czasie jest to dla nas natywny sposób pisania bardziej skomplikowanych zapytań podczas korzystania z ZF. Właśnie dzięki jego obiektowej naturze i wykorzystaniu fluent interface mogę dowolnie łączyć warunki zapytania bądź zmieniać je korzystając z metody reset(). Przykład:

class Model_Foo extends Zend_Db_Table_Abstract
{
    private $_name = 'foo';
 
    // use fluent interface and add condition
    public function fetchWithLeftJoinWhereBarIsntNull()
    {
        $select = $this->_getBaseSelect();
        $select->where('bar IS NOT NULL');
        return parent::fetchAll();
    }
 
    // user reset() and remove LEFT JOIN
    public function fetchWithoutLeftJoin()
    {
        $select = $this->_getBaseSelect();
        $select->reset(Zend_Db_Select::LEFT_JOIN);
        return parent::fetchAll($select);
    }
 
    private function _getBaseSelect()
    {
        $select = $this->select();
        $select->from('table1')
               ->setIntegrityCheck(false) // allow to join another tables
               ->joinInner('table2', 'table1.id = table2.table1_id')
               ->joinLeft('table3', 'table1.id = table3.table1_id');
 
        return $select;
    }
}

Wady

Brak nazwanych relacji

O używaniu relacji w Zend Framework pisał już batman we wpisie Zend_Db i relacje. Jednak mi nie odpowiada fakt, że korzystając domyślnej metody opisywanej praktycznie wszędzie muszę odnosić się do rekordów podrzędnych po nazwie klasy, a nie nazwie zdefiniowanej relacji. Chciałbym, abym mógł napisać tak:

$params = $userRow->findDependentRowset('UserParamsRelationWithCustomName'); //instead of specifying model class

Nazwa klasy zawsze może się zmienić, a to ułatwia refactoring. Dodatkowo, chciałbym móc w ramach relacji zdefiniować dodatkowe parametry dotyczące połączenia – nie tylko kolumnę, po jakiej ma się ono odbyć, ale także warunki do kolumn dodatkowych. Istnieje co prawda Zend_Db_Table_Definition, jednak rozwiązanie to ma dwie wady. Po pierwsze wymaga osobnej definicji dla każdej klasy modelu, co jest niewygodne. Po drugie, nadal nie pozwala na definiowanie dodatkowych warunków dla połączeń.

Czytaj dalej tutaj (rozwija treść wpisu)
Czytaj dalej na blogu autora...

Autor wpisu: batman, dodany: 08.04.2011 08:00, tagi: zend_framework

Mimo iż Zend Framework 2 zostanie wydany lada moment, prace nad bieżącą wersją nie zostały ograniczone do łatania dziur. Ostatnie wydanie frameworka, obok kilkunastu bug fixów, wprowadza trzy nowe funkcjonalności, z których jedną przywitałem ze sporym entuzjazmem.

Chodzi o możliwość tworzenia plików konfiguracyjnych z rozszerzeniem .dist (np. application.ini.dist), dedykowanych dla konkretnego programisty/środowiska. Oznacza to, że od wersji 1.11.5 mamy możliwość dodania do konfiguracji specyficznych ustawień, które nie powinny znaleźć się w repozytorium projektu. Jest to niezmiernie potrzebne w przypadku projektów, nad rozwojem których pracuje wiele osób.

Pozostałe nowości to aktualizacja Zend_Gdata polegająca na korzystaniu z https wszędzie tam, gdzie to możliwe oraz wygenerowanie dokumentacji API przy pomocy DocBlox. Dokładne informacje na temat wydania, znajdziecie pod adresem http://devzone.zend.com/article/13643-Zend-Framework-1.11.5-Released

Autor wpisu: singles, dodany: 07.04.2011 18:26, tagi: symfony, zend_framework

Zapraszam do drugiej edycji serii Oddam książkę za darmo. Dzisiejsza zabawa trochę różni się od poprzedniej, patrz akapit „Sponsor” ;)

Książka

Od dzisiaj możecie powalczyć o pozycję PHP5. Programowanie z wykorzystaniem Symfony, CakePHP, Zend Framework.

PHP5. Programowanie z wykorzystaniem Symfony, CakePHP, Zend Framework

Zadanie

Zadanie polega na napisania w komentarzu krótkiego quick-tipa w języku PHP. Przykłady tego, co rozumiem przez quick tip:

$value = $var ?: 0; // instead of $value = $var ? $var : 0
$data = array(
    1 => array(
        'value' => 10
    ),
    2 => array(
        'value' => 20
    )
    5 => array(
        'value' => 30
    )
)
 
$sum = array_sum(array_map('array_pop', $data))); // = 60
 
//instead of
$sum = 0;
foreach($data as $el) {
    $sum += $el['value'];
}

Od siebie zachęcam do pisania kodu w komentarzach w ramach znacznika <pre lang="PHP">.

Koniec konkursu

Konkurs kończy się w poniedziałek 11 marca o godzinie 00:01. Wygrywa ta osoba, której php quick tip okaże się najciekawszy.

Sponsor ;)

Dzisiejszy konkurs „sponsorowany” jest przez @uolot‘a – książka jest jego – chciał ją oddać. On także wymyślił pytanie, tak więc wyrazy uznania kierujcie w jego stronę :)

Autor wpisu: singles, dodany: 05.04.2011 09:03, tagi: php, zend_framework

Jest poniedziałek, 4 kwietnia, godzina 18:50. Siedzę w pociągu powrotnym do Poznania, a z racji że czekają mnie prawie 3h jazdy (a za plecami mam gniazdko elektryczne;), stwierdziłem, że poświęcę ten czas na przedstawienie Wam mojej krótkiej relacji z konferencji 4Developers.

Miejsce

Organizatorzy konferencji przygotowali 4 ścieżki tematyczne – PHP, Java, Zarządzanie projektami IT oraz Wydajność i skalowalność + 4 panele dyskusyjne – dokładniejsze informacje na temat agendy znajdziecie na stronie konferencji. Wybrana lokalizacja także się sprawdziła – bardzo blisko Dworca Wschodniego, pętli autobusowej oraz tramwajowej. Sale Wyższej Szkoły Menadżerskiej były wystarczająco duże (aczkolwiek z technicznymi problemami, ale o tym później), jednakże lobby jak dla mnie trochę za małe – momentami bywało naprawdę ciasno. W lobby kilka stanowisk zajmowali sponsorzy konferencji – w tym jeden z nich chwalił się na swoim stoisku niebieskimi maskotkami słoni z logiem PHP – niestety nie chcieli się podzielić ;P Można było także pograć na konsolach Xbox360 + Kinect oraz PS3 + PSMove. Obok konsol znajdowała się duża tablica, z którą związany był konkurs – a opiszę go, ponieważ uważam, że pomysł był bardzo udany.

Konkursy i gadżety

Otóż to, każdy z odwiedzających dostawał w ramach zestawu powitalnego mały kartonik z literą. Dodatkowe litery można było podchodząc do stanowisk sponsorów. Nagrodą dla osoby, która ułożyła największe słowo była konsola PSP. Jednak uwaga – układane słowa musiały być powiązane z programowaniem. Chciałbym jednak wytknąć organizatorom pewien błąd – otóż to w broszurze, którą otrzymaliśmy napisane było, że zwycięzca tego konkursu otrzyma PS3, a nie PSP. Za to obok tablicy było już PSP. Mała nieścisłość, aczkolwiek nie zmienia to faktu, że nagroda nadal bardzo fajna. A jakie hasła wymyślili uczestnicy? Patrzcie tutaj.

Dodatkowo, sporo gadżetów wszelkiej maści – koszulek (sam wiozę w plecaku 4 rożne – w tym najlepszą :D), kubków, smyczy, przypinek, notatników i tym podobnych. No i oczywiście nie można zapomnieć o uroczych hostessach :)

Organizacja

Samą organizację konferencji oceniam dobrze, aczkolwiek były dwie wpadki. Przy samym wejściu, kiedy podałem swoje dane osobowe, zostałem poproszony o okazanie dowodu wpłaty – nikt inny tego nie robił, z tego co zauważyłem. Możliwe, że to dlatego, że płaciłem PayPalem praktycznie na samym początku rejestracji. Kilka dni później dostałem informację o fakturze do zapłaty. Mocno się zdziwiłem, bo przecież zapłaciłem. Całe szczęście, sprawę udało się wyjaśnić mailowo i poinformowano mnie, że z mojej strony nie są potrzebne dodatkowe kroki. A na miejscu okazało się, że to nieprawda. Skończyło się na pokazywaniu uprzejmym Paniom w rejestracji wspomnianego wcześniejszego maila i tekstem: „Dobrze, wierzymy”. Pomyślałem tylko: „Cieszę się bardzo:)”.

Teraz sprawy techniczne. Otóż to, ekipa techniczna odpowiedzialna za obraz i dźwięk nie pokazała się z najlepszej strony – lekko mówiąc. Pierwsza prezentacja zaczęła się z 20 minutowym opóźnieniem, ponieważ był jakiś problem z rzutnikiem przymocowanym do sufitu. Skończyło się na tym, że prezentacje w jednej sali (PHP) wyświetlane były za pomocą rzutnika leżącego na krześle stojącym na schodach, w którym to rzutniku panowie technicy przez 3 minuty zastanawiali się jak przestawić obraz, który był odwrócony do góry nogami – w końcu rzutnik wisiał wcześniej na suficie. Nie wiem dokładnie, co działo się w innych salach, ale Pani hostessa poinformowała nas, że z racji tego opóźnienia wszystkie prezentacje zostaną przesunięte o te 20-30 minut. A finalnie i tak były przesunięte tylko o 10 minut, bo pierwszy prelegent szybko uwinął się ze swoją prezentacją, co pasowało także pozostałym wykładającym. Jeśli chodzi o techników, dochodziły także problemy z dźwiękiem – nie działające mikrofony, momentami okropne sprzężenia. Natomiast wielki plus należy się za WiFi na miejscu. To była pierwsza konferencja, na której byłem, gdzie WiFi po prostu działało! – nie odczułem żadnych niedogodności podczas korzystania.

Jeśli chodzi o jedzenie – standard na konferencjach. Kawa, herbata, soki i ciastka dostępne cały czas oraz przerwa na godzinny ciepły obiad w specjalnie przygotowanej do tego celu sali – w której jak to zwykle bywa, i tak zabrakło miejsc. Jedzenie bardzo smaczne, aczkolwiek rogaliki były oszukane, bo bez nadzienia!

Skrót prezentacji

Opiszę teraz pokrótce prezentacje, których wysłuchałem.

Uprość zarządzanie zależnościami między aplikacjami trzecimi a swoim projektemStephan Hochdoerfer

Jak sama nazwa mówi, prezentacja tyczyła się sposobów zarządzania zewnętrznymi bibliotekami w naszym projekcie. Jak poradzić sobie z uaktualnianiem kodu, który jest używany przez kilka aplikacji, a przychodzi potrzeba poprawienia jakiegoś buga bądź dodania nowego feature’a? Na te pytania starał się odpowiedzieć prowadzący. Zaczęło się od svn:externals i krótkiego opisu jak tego używać. Stephan wymienił zalety i wady tego rozwiązania (m.in. możemy korzystać z kodu znajdującego się tylko w repozytorium SVN) oraz podzielił się „pro-tipem”, który może nie być taki oczywisty dla wszystkich. Otóż to, kiedy używacie svn:externals, linkujcie do tagów albo branchy, a nie do trunka, ponieważ w trunku czasami mogą pojawić się zmiany, które potrafią posypać Wasz kod. Następnie była mowa o systemie kontroli wersji Git (Git’cie?) i jego submodułach, które to działają w podobny sposób jak svn:externals. Kolejnymi przedstawionymi sposobami były: pakiety .deb, Phing oraz PEAR wraz z krótką instrukcją, jak tego używać. Jako ciekawostkę podam, że w przypadku PEAR’a padło hasło: Pearhub. Jest to serwis, który pozwala na łatwiejsze publikowanie oraz instalację pakietów – więcej informacji znajdziecie na stronie projektu Jednak cała prezentacja zmierzała do jednego uniwersalnego narzędzia – pozwolę sobie zacytować prowadzącego:

Czytaj dalej tutaj (rozwija treść wpisu)
Czytaj dalej na blogu autora...

Wszystkie wpisy należą do ich twórców. PHP.pl nie ponosi odpowiedzialności za treść wpisów.