Пакеты(packages) в Fuelphp

    В данной статье я бы хотел поделиться знаниями о том, как устроены, для чего нужны и что из себя представляют packages(далее пакеты) в Fuelphp. Прошу помочь сравнить реализацию и возможности пакетов Fuelphp с аналогами из других фреймворков. Думаю всем будет интересно узнать мнение адептов Simfony2 и Yii по этому поводу, милости просим, кидайте свои выкладки в комменты. Далее в примерах будет рассмотрен пакет fuel-ninjauth

    Назначение пакетов в контексте Fuelphp

    Для выполнения тех или иных повторяющихся глобальных задач, в приложении, уже давно применяется подход с использованием сервисов или же служб, что по сути одно и то же. Если просто, то сервис это объект, который выполняет какую-то глобальную задачу в контексте приложения. В Fuelphp роль таких сервисов выполняют пакеты.

    Установка пакета

    Пакетами можно делиться с сообществом. Есть несколько путей инсталляции пакетов, можно просто скопировать содержимое репозитория к себе в проект, использовать composer или воспользоваться утилитой oil.

    Обратимся к oil с командой:
    $ php oil package install ninjauth

    Выполним миграцию, так как данный пакет использует данные из бд:
    # Создадим таблицу users если таковой ещё нет
    $ oil g migration create_users username:varchar[50] password:string group:int email:string last_login:integer login_hash:string profile_fields:text created_at:int
    $ oil refine migrate
    
    # Запустим миграцию для создания в бд таблицы "authentications"
    $ oil refine migrate --packages=ninjauth
    

    Структура пакета

    Рассмотрим возможную структуру на примере пакета fuel-ninjauth
    image
    1. Классы пакета
    В папке classes находятся классы пакета. Пример

    1.1 Модели пакета
    Модели также могут входить в состав классов пакета, когда пакет использует бд. Пример

    1.2. Контроллеры
    Контроллеры в пакетах используются реже и в основном служат для формирования представлений внутри пакета. Пример В итоге вся логика контроллера может сводится к чему то подобному:
    return View::forge('register', array( //register - имя представления из папки №4 views 
    			'user' => (object) compact('username', 'full_name', 'email', 'password')
    		));
    

    2. Конфигурация
    Конфигурация или файл с настройками пакета. Пример
    Пример обращения к настройкам:
    \Config::get('ninjauth.default_group');
    

    3. Миграции
    В данной папке расположены классы миграций, которые нужны для быстрой сборки структуры данных в бд, создания необходимых таблиц и т.д.

    4. Представления
    В пакете могут использоваться представления. Как правило пакет обрабатывает логику и не связан с формированием представления напрямую, но иногда может оказаться, что формирование представления внутри пакета будет хорошим решением.
    Пример представления:
    <?php echo Form::open(null, array('id' => 'register')); ?>
    
    	<?php if (isset($error)): ?>
    		<span class="error"><?php echo $error; ?></span>
    	<?php endif; ?>
    
    	<p>
    		<label for="username">Username</label>
    		<?php echo Form::input('username', $user->username) ?>
    	</p>
    	<p>
    		<label for="full_name">Full Name</label>
    		<?php echo Form::input('full_name', $user->full_name) ?>
    	</p>
    	<p>
    		<label for="email">Email</label>
    		<?php echo Form::input('email', $user->email) ?>
    	</p>
    	<p>
    		<label for="password">Password</label>
    		<?php echo Form::password('password') ?>
    	</p>
    	<?php echo Form::submit('submit') ?>
    
    <?php echo Form::close() ?>
    

    5. Файл bootstrap.
    Данный файл служит для описания файловой структуры пакета для автозагрузчика.
    Autoloader::add_classes(array(
    	'NinjAuth\\Controller'               	        => __DIR__.'/classes/controller.php',
    	'NinjAuth\\Exception'  				=> __DIR__.'/classes/exception.php',
    	'NinjAuth\\CancelException'  		=> __DIR__.'/classes/exception.php',
    	'NinjAuth\\ResponseException'  	=> __DIR__.'/classes/exception.php',
    	'NinjAuth\\Model_Authentication'  	=> __DIR__.'/classes/model/authentication.php',
    
    	'NinjAuth\\Strategy'  				=> __DIR__.'/classes/strategy.php',
    	'NinjAuth\\Adapter'  				=> __DIR__.'/classes/adapter.php',
    	'NinjAuth\\Adapter_SimpleAuth'  	=> __DIR__.'/classes/adapter/simpleauth.php',
    	'NinjAuth\\Adapter_Sentry'  		=> __DIR__.'/classes/adapter/sentry.php',
    	'NinjAuth\\Adapter_Warden'  		=> __DIR__.'/classes/adapter/warden.php',
    
    	'NinjAuth\\Strategy_OAuth'  		=> __DIR__.'/classes/strategy/oauth.php',
    	'NinjAuth\\Strategy_OAuth2'  		=> __DIR__.'/classes/strategy/oauth2.php',
    	'NinjAuth\\Strategy_OpenId'  		=> __DIR__.'/classes/strategy/openid.php',
    ));
    

    Важно понимать, что файлы загружаются автоматически, и только в случае использования методов пакета. Иными словами, если нигде в отработке скрипта не использовались методы пакета, то и его классы загружены не будут. Это делает ваше приложение легче и быстрее. Единственное о чем всегда знает приложение это о расположении файлов bootstrap.php:
    image

    Примеры использования

    Пакет NinjAuth является адаптером для стандартного пакета автроизации и сделать простой пример его работы будет сложновато. Поэтому возьмем пакет fueltools. Он нужен для отладки кода, когда нужно быстро посмотреть что возвращает метод или переменная. Итак, допустим мы пишем сотый метод нашего приложения:
    public function action_save()
        {
            $var1 = 'var1';
            $var2 = 'var2';
            
            $orm = Model_Test::forge()->set('one', $var1)->set('two',$var2);
    
            \Fueltools\FB::info($var1);
            \Fueltools\FB::info($var2);
            \Fueltools\FB::info($orm->save());
        }
    

    Смотрим результат выполнения данного метода в консоли Firefox:image
    Fuelphp загрузил только те классы пакетов ORM и FuelTools, которые требовались для отработки сценария:
    image

    Итоги

    Fuelphp предоставляет в виде пакетов довольно широкие возможности:
    — формирование упорядоченной и понятной архитектуры приложения
    — применение сервисов, как в примере с fueltools
    — применение паттернов и подключение дополнительного функционала к уже имеющимся пакетам, как в пакете fuel-ninjauth который является адаптером к стандартному пакету Auth.
    — пакеты позволяют брать на себя функции формирования представлений, а при желании в обычных контроллерах можно оставить только проверки и ввод-вывод, перенеся все остальное в пакеты.
    — пакеты позволяют абстрагироваться от другого кода в приложении, его проще тестировать и подключать в другом проекте
    — объекты и методы пакета становятся доступными в контексте всего приложения
    — использование пакетов делает ваше приложение легче и быстрее

    Src

    — пакет fuel-ninjauth
    — пакет fueltools
    — официальный репозиторий пакетов для Fuelphp github.com
    — репозиторий на форуме fuel-packages
    Поделиться публикацией
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама

    Комментарии 30

      +2
      Symfony — следует PSR-0 и использует composer.
      Yii — следует PSR-0. composer, вполне вероятно, появится во второй версии.

      FuelPHP пошел своим путём. PHP-style. Тем не менее удачи.
        0
        Не совсем, packagist.org Пакеты через composer можно грузить уже сейчас, в коробке composer будет в 2.0
          0
          Хм, действительно. Возможно в статье стоило уделить больше внимания composer? Я, если честно, его проглядел и решил что у вас только oil.
          0
          Дополнение с нашего форума — Fuelphp переходит на psr-2 во второй версии и один из разрабов является действующим членом PSR (с правом голоса). Ответьте плиз, а то как-то в говно незаслуженно макают нас…
          0
          Возможно вы правы, composer не идет из коробки, поэтому не стал заострять внимание на этом моменте. Скажите проводите ли вы аналогию возможностей пакетов с DIC в Symfony2? Как считаете на сколько удобна реализация DIC в Symfony2?
            0
            Не могу объективно оценить Symfony 2 т.к. практически не работал с ним.
            Судя по впечатлениям от Silex, библиотек SensioLabs и взаимодействия с ними это должно быть достаточно удобно.
              0
              Благодарю, но хотелось бы услышать мнение человека, который пишет код на Symfony2
                +1
                Я пишу, только на Symfony2. Там это очень и очень удобно. Собственно, чего вы ожидали? :)
                  0
                  Ожидал более развернутого ответа.) Можете рассказать о плюсах и минусах более подробно?
                    0
                    О минусах не расскажу — я кроме DIC в Symfony больше с ним нигде не работал, но плюсов много. Когда перешел на службы — сразу десятки багов ушли, т.к. они были уже принципиально невозможны. Псоле переработки кода его стало возможно выносить в бандлы, т.к. зависимости прописаны. Сам код чище, т.к. часть сквозного функционала (но далеко не весь) уходит во вспомогательные сервисы.
            0
            Уточню — DIC в Symfony2
              0
              А умеет ли FuelPHP компилировать контейнер?
                0
                Package DIC вроде умеет, но я не пользовался. Просто в bootstrap.php прописаны все загрузчики и службу не нужно предварительно загружать перед использованием, как в Symfony2
                <?php
                class HelloController extends Controller
                {
                    // ...
                
                    public function sendEmailAction()
                    {
                        // ...
                        $mailer = $this->get('my_mailer');
                        $mailer->send('ryan@foobar.net', ... );
                    }
                }
                

                В Fuel тоже самое было бы так
                <?php
                class HelloController extends Controller
                {
                    // ...
                
                    public function sendEmailAction()
                    {
                        // ...
                        \Namesp\My_mailer::forge()->send('ryan@foobar.net', ... );
                    }
                }
                
                  0
                  Простите, что? В Symfony2 не нужно загружать службу перед использованием. Причем, даже в вашем примере это видно:
                  $this->get('my_mailer')->send('ryan@foobar.net', ... );
                    0
                    Пример взят из документации, но вы правы, действительно можно и не загружать, как то не обратил внимания по началу. И все равно хотелось бы для себя прояснить преимущества DIC. Перешел на пакетно-ориентированную разработку недавно, и DIC не пользуюсь, а главное не вижу причин начинать. Можете для меня прояснить преимущества использования DIC? Может я чего то ещё не вижу, направьте хотябы, какие потенциальные проблемы могут ждать, если не использовать DIC?
                      0
                      Ну, скажем, легко находятся циркулярные зависимости (что есть плохо). Без DIC, мне кажется, это почти невозможно.
                        0
                        Не знаком с термином «циркулярные зависимости», в гугле тоже не обнаружил. Можно пример или как-то на пальцах рассказать, что это такое?
                          0
                          tinyurl.com/9l5glod

                          Это когда службы по цепочке зависят «циркулярно»: A -> B ->… -> A.
                            0
                            Понял теперь. Да, действительно штука полезная. Только наверное точнее будет «циклично» чем «циркулярно») Благодарю за ответы.
                0
                Реализация DIC в FuelPHP очень наивна, я бы даже сказал что это не DIC, а простой Service Locator.
                — Не решает циркулярных зависимостей
                — Не компилирует на ходу
                — Не поддерживает вложенные зависимости
                — Не поддерживает удобную конфигурацию, подмену зависимостей на ходу

                Главный минус FuelPHP — когда их конкуренты вроде Laravel заимствуют сложные компоненты у старших братьев, разработчики FuelPHP все еще испытывают необходимость писать свой велосипед, вместо того чтобы концентрировать все внимание на какой-нибудь киллер фиче.
                  0
                  Его «киллер-фича» это главным образом простота и расширяемость. Когда нужен дополнительный функционал или замена существующему в виде давно придуманных велосипедов, то идем в google, ищем, выбираем по душе и через 10 минут имеем пакет для Fuelphp.

                  DIC в текущей версии Fuel — нет, следовательно и о реализации говорить пока рано. DIC «анонсирована» в альфа версии 2.0, её реализация может поменяться сто раз до выхода stable версии.
                0
                'NinjAuth\\Controller' — можно не дублировать бекслеши
                  0
                  это вопрос?
                    0
                    Да нет, просто заметил.
                    0
                    да работает и без дублирования, надо уточнить этот момент у разработчиков, возможно у них были какие то на то причины
                      0
                      Причина только в том, что двойные слэши ведут себя одинаково и в одинарных и в двойных кавычках
                        0
                        Это понятно, просто даже при двойных кавычках один бекслеш в такой строке
                        "NinjAuth\Controller"
                        будет вести себя также как и при двойном. Задал вопрос на форуме) Интересно же. Но я думаю причиной двойных бекслешей является желание сделать «понадежнее».
                          0
                          Вот ответ от Harro Verton:
                          In PHP strings, the backslash is an escape character, so you need to use two backslashes of you want to use a backslash in your string.

                          Now officially you only have to do this with strings in double quotes, and not for strings in single quotes.

                          However, it is our coding convention to do it everywhere to avoid confusion and mistakes.
                    0
                    А что насчет зависимостей в FuelPHP? Все через синглетоны и стат. методы?
                      0
                      Зависимостей нет и судя по roadmap разработчики обойдут их стороной даже в 2.0

                    Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                    Самое читаемое