Пакеты (packages) - основной способ добавления нового функционала в Laravel. Пакеты могут быть всем, чем угодно - от классов для удобной работы с датами типа Carbon до целых библиотек BDD-тестирования, наподобие Behat.
Конечно, всё это разные типы пакетов. Некоторые пакеты самостоятельны, что позволяет им работать в составе любого фреймворка, а не только Laravel. Примерами таких отдельных пакетов являются Carbon и Behat. Любой из них может быть использован в Laravel после простого указания его в файле composer.json.
С другой стороны, некоторые пакеты разработаны специально для использования в Laravel. В предыдущей версии Laravel такие пакеты назывались "bundles". Они могли содержать роуты, контроллеры, шаблоны, настройки и миграции, специально рассчитанные для улучшения приложения на Laravel. Так как для разработки самостоятельных пакетов нет особенных правил, этот раздел документации в основном посвящён разработке именно пакетов для Laravel.
Все пакеты Laravel распространяются через Packagist и Composer, поэтому нужно изучить эти прекрасные средства распространения кода для PHP.
Простейший способ создать пакет для использования в Laravel - с помощью команды workbench инструмента командной строки Artisan. Сперва вам нужно установить несколько параметров в файле app/config/workbench.php. Там вы найдёте такие настройки, как name и email. Их значения будут использованы при генерации composer.json для вашего нового пакета. Когда вы заполнили эти значения, то всё готово для создания заготовки.
Использование команды workbench. Листинг 30.1 |
php artisan workbench vendor/package --resources |
Где vendor - имя поставщика услуг, package - это имя создаваемого вами пакета.
К примеру, мой логин на github — mikhalkevich, а создаваемый пакет я хочу назвать obmenka, соответственно, я должен выполнить команду:
Создание пакета mikhalkevich/obmenka. Листинг 30.2 |
php artisan workbench --resources mikhalkevich/obmenka |
Где флаг resourses говорит, что необходимо так же создать специфичные для Laravel папки: migrations, views, config и тд.
Чтобы Laravel при запуске приложения автоматически подгружал наш пакет, нам необходимо в файл app/config/app.php в массив providers добавить строчку:
Добавление пакета в массив providers конфигурационного файлаapp.php. Листинг 30.3 |
'Mikhalkevich\Obmenka\ObmenkaServiceProvider', |
Имена классов поставщика услуг следуют схеме [Package]ServiceProvider, но перед этим указывается полный namespace класса.
Структура пакета
В папке src мы можем видеть знакомую структуру папок, названия которых говорят сами за себя.
Заметим, что в папке src/Mikhalkevich/Obmenka/ хранится класс нашего поставщика услуг, а также туда стоит класть все вспомогательные классы нашего пакета.
Посмотрим на класс ObmenkaServiceProvider. Метод register будет вызван, как только пакет был зарегистрирован, а метод boot вызывается каждый раз перед обработкой запроса.
Создадим в папке src нашего пакета файл routes.php с двумя роутами:
Роуты файла routes.phpсоздаваемого пакета. Листинг 30.4 |
Route::get('/blog/', array( 'as' => 'posts_list', 'uses' => 'Cherryoff\Nbblog\NbblogController@showList' )); Route::get('/blog/{link}', array( 'as' => 'post', 'uses' => 'Cherryoff\Nbblog\NbblogController@showPost' ))->where('link', '[A-Za-z-_]+'); |
Где в качестве контроллера указываем полный путь до нашего еще не созданного контроллера. Далее в папке controllers создадим контроллер ObmenkaController со следующим содержимым:
Содержимое ObmenkaController. Листинг 30.5 |
use Illuminate\Support\Facades\App; use Illuminate\Support\Facades\Config; use Illuminate\Routing\Controller; use Illuminate\Support\Facades\Redirect; use Illuminate\Support\Facades\Response; use Illuminate\Support\Facades\Request; use Illuminate\Support\Facades\View; use Illuminate\Support\Facades\Input; use Illuminate\Support\Facades\File; use Illuminate\Support\Facades\Session; use Illuminate\Support\Facades\URL; class ObmenkaController extends Controller { public function showList() { return 'Posts list'; } public function showPost($link) { return 'Get post:'.$link; } } |
Теперь у нас прописаны пути и контроллер должен отвечать нам простыми сообщениями. Но если мы перейдем по ссылке sandbox.local/blog/, то получим исключение о том, что страница не найдена. Все дело в том, что приложение не знает о том, что у нашего пакета есть свои пути, и, чтобы исправить это, подключим файл routes.php в конце метода boot класса ObmenkaServiceProvider:
Подключение маршрутов пакета. Листинг 30.6 |
include __DIR__.'/../../routes.php'; |
Чтобы показать composer где искать необходимые файлы, добавим в composer.json (нашего пакета!!!) в секцию classmap строчку «src/controllers», после чего выполним:
Обновление классов автозагрузок. Листинг 30.7 |
composer dump-autoload |
Теперь роуты должны работать.
Далее, создадим папку models и файл Post.php в ней. Листинг файла представлен ниже:
Модель Post. Листинг 30.8 |
Cherryoff\Obmenka;
use
use
use
/** * Модель записи в блоге */ classPostextendsModel { protected$table //Добавляем в выдачу вычисляемое поле protected$appends //Делаем поля доступными для автозаполнения protected$fillable //Некоторые правила валидиции publicstatic$rules 'header' 'link'
'article'
publicfunctiongetCutAttribute(){ return
|
Теперь необходимо добавить папку models в секцию автозагрузки composer.json (нужно добавить выше строчки "src/controllers") нашего проекта и выполнить composer dump-autoload так же, как мы это делали в случае с контроллером.
Строкой в консоли создадим миграцию для нашего пакета:
Создаем миграцию для пакета. Листинг 30.9 |
php artisan migrate:make create_obmenka_posts_table --bench="mikhalkevich/obmenka" |
В папке src/migrations/ появился класс только что созданной миграции. В его методе up пропишем:
Файл миграции. Листинг 30.10 |
Schema::create('posts', function (Blueprint $table) { $table->increments('id'); $table->string('link', 32); $table->string('header', 256); $table->text('article'); $table->timestamps(); $table->softDeletes(); }); |
В методе down():
Содержимое метода down(). Листинг 30.11 |
Schema::dropIfExists('posts'); |
Выполняем миграцию:
Выполнение миграции. Листинг 30.12 |
php artisan migrate --bench="mikhalkevich/obmenka" |
Теперь заполним только что созданную таблицу начальными данными. Для этого в папке src создадим папку seeds с файлом ObmenkaSeeder.php со следующим содержимым:
Seeds. Листинг 30.13 |
use Illuminate\Database\Seeder; class NbblogSeeder extends Seeder { public function run() { $posts = [ [ 'header'=>'Header post number one', 'link'=>'one', 'article'=>'Body text', ], [ 'header'=>'Very important news', 'link'=>'news', 'article'=>'Body text', ], ]; foreach ($posts as $post){ Post::create($post); } } } |
Добавим папку seeds в секцию автозагрузки composer.json и снова выполним dump-autoload.
Теперь загрузим начальные данные командой:
Загрузка начальных данных. Листинг 30.14 |
php artisan db:seed --class="\Mikhalkevich\Obmenka\ObmenkaSeeder" |
Создадим шаблоны видов для нашего блога, разместив их в папке src/views:
@yield('title')
Just blog package for Laravel
@yield('content')
Базовый шаблон. Листинг 30.15 |
|
В контроллере будем подключать такой подшаблон:
List.blade.php. Листинг 30.16 |
@section('title') List @stop @section('content') Number of posts in the blog: {{$count}} @forelse($posts as $post) @include('nbblog::preview') @empty
@endforelse @stop |
Preview.blade.php
Preview.blade.php. Листинг 30.17 |
{{$post->created_at}}
{{$post->header}}{{$post->cut}} |
Еще один файл подшаблона, post.blade.php
Post.blade.php. Листинг 30.18 |
@section('title') {{$header}} @stop @section('content')
{{$created_at}}
{{$header}}
{{$article}}
@stop |
Итак, с шаблонами закончено, теперь можно приступить к наполнению их данными. Для этого создадим файл viewComposers.php прямо в папке src. (Мы можем создать этот файл в любом месте нашего пакета, главное, не забыть его подключить).
ViewComposers.php. Листинг 30.19 |
/** * Не забываем использовать имя своего пакета перед названием вида */ View::composer(array('obmenka::list', 'obmenka::post'), function($view){ $view->with('uri', 'blog'); }); View::composer('obmenka::list', function ($view) { $view->with('count', \Mikhalkevich\Obmenka\Post::count())->with('posts', \Mikhalkevich\Obmenka\Post::all()); }); |
Мы только что привязали переменную uri к шаблону списка постов и шаблону поста (в дальнейшем, когда мы будем получать эту переменную из настроек, нам будет удобнее передавать ее в виды в одном месте), и вместе с шаблоном списка постов мы отдаем сразу все записи.
Теперь необходимо подключить созданный файл в классе нашего поставщика услуг (src/Cherryoff/Nbblog/NbblogServiceProvider.php) так же, как мы это делали с файлом route.php.
Подключение файла ViewComposers. Листинг 30.20 |
include __DIR__.'/../../viewComposers.php'; |
Меняем класс нашего контроллера
Конроллер NbblogController. Листинг 30.21 |
class NbblogController extends Controller { public function __construct(){ $this->layout = View::make('nbblog::layout'); } public function showList() { $this->layout->content = View::make('nbblog::list'); } public function showPost($link) { $post = Post::where('link', '=', $link)->firstOrFail(); $this->layout->content = View::make('nbblog::post', $post); } } |
В папке public нашего пакета создадим папку css и добавим туда файл main.css.
Опубликуем внешние ресурсы нашего пакета командой:
Публикация внешних ресурсов пакета. Листинг 30.22 |
php artisan asset:publish --bench="mikhalkevich/obmenka" |
В папке public нашего приложения появился файл main.css, который расположился в папке packages/cherryoff/nbblog/css/. Так laravel делает со всеми внешними ресурсами пакетов. А значит, что это соглашение об именовании внешних ресурсов поможет нам обратится к этому файлу из нашего шаблона.
Путь к таблице стилей нашего пакета. Листинг 30.23 |
/packages/mikhalkevich/obmenka/css/main.css |