Статьи

Фрактал: практическое прохождение

Если вы когда-либо разрабатывали API, у вас могли возникнуть проблемы с изменениями схемы базы данных. Если у вас не было хорошей реализации, вам пришлось переделывать всю модель при изменении имен некоторых столбцов. В этой статье я покажу, как вы можете использовать Fractal в качестве слоя между вашими моделями и выводом JSON. Этот пост покажет вам, как этот пакет облегчит разработку API.

Фрактал как пакет

Fractal – это проект, написанный на PHP и являющийся частью Лиги выдающихся пакетов . Все эти пакеты соответствуют нескольким требованиям, таким как использование PHP-FIG и покрытие Unit Test. Фрактал в основном разработан Филом Стердженом и до сих пор регулярно совершенствуется. Он также может быть использован с Composer .

Настройка среды

В демонстрационных целях я сейчас настрою фреймворк, используя Silex и Illuminate / Database (компонент ORM в Laravel). Неважно, если у вас нет опыта с одним из них. То, что я сделаю, очень просто, и я объясню их настолько, насколько смогу. Если что-то неясно, не стесняйтесь оставлять комментарии.

Я сейчас настрою рамки. Обратите внимание, что если вы не хотите следовать инструкциям, вы можете загрузить весь код в конце статьи . Теперь начните с создания новой папки внутри корневой папки. Мы начнем с создания нашего файла composer.json со всеми необходимыми нам зависимостями. В нашем случае: Silex and Illuminate \ Database. Создайте файл composer.json следующим образом:

 { "require": { "silex/silex": "~1.2", "illuminate/database": "*" }, } 

Установите пакеты с помощью composer install .

База данных

Я возьму пример онлайновой музыкальной базы данных. База данных предоставит информацию для нескольких песен: название песни, имя исполнителя, сайт исполнителя, название альбома, дата выпуска и музыкальный лейбл. В начале все это будет в одной таблице. Если вы хотите попробовать сами, загрузите файл 1.sql из репозитория этой статьи и запустите его в своей базе данных.

Код

Чтобы использовать Silex с Illuminate \ Database, нам понадобится код. Внутри app folder создайте новый файл index.php . Здесь мы запустим Silex, подключимся к базе данных и определим маршруты:

 <?php require("../vendor/autoload.php"); $app = new Silex\Application(); $app['database'] = require("database.php"); $app->mount('/tracks', include 'controllers/tracks.php'); $app->run(); 

В первой строке нам нужен файл автозагрузки для композитора. Затем мы создаем новое приложение Silex и загружаем в Illuminate/Database . Затем мы создаем контроллер для /tracks чтобы все URL, начинающиеся с controllers/tracks.php были обработаны controllers/tracks.php . Файл database.php выглядит следующим образом, не забудьте изменить настройки соединения:

 <?php use Illuminate\Database\Capsule\Manager as Capsule; $capsule = new Capsule; $capsule->addConnection([ 'driver' => 'mysql', 'host' => 'localhost', 'database' => 'musicstore', 'username' => 'root', 'password' => '', 'charset' => 'utf8', 'collation' => 'utf8_unicode_ci', 'prefix' => '', ]); use Illuminate\Events\Dispatcher; use Illuminate\Container\Container; $capsule->setEventDispatcher(new Dispatcher(new Container)); $capsule->setAsGlobal(); $capsule->bootEloquent(); return $capsule; 

Первая версия API

Первоначально база данных содержит только одну таблицу (импорт 1.sql ). Эта таблица содержит информацию о самом треке (название, музыкальный лейбл), альбоме (название и дата выпуска) и исполнителе (название и веб-сайт). Наш API предоставит две вещи: при переходе к /tracks он выведет список json с идентификаторами дорожек, их заголовком и исполнителем. При переходе к /tracks/$id track /tracks/$id он выводит всю информацию о дорожке в виде объекта json.

Отслеживание

Начнем со списка треков. Поместите этот код в /controllers/tracks.php :

 <?php $tracks = $app['controllers_factory']; $tracks->get('/', function() use ($app) { $tracklist = Track::getTrackList(); $output = array("data" => $tracklist); return json_encode($output); }); return $tracks; 

и этот код для модели, /models/Track.php :

 public static function getTrackList() { return Track::select('id','name','artist_name')->get(); } 

При этом используется запросщик Illuminate \ Database, чтобы получить список идентификаторов, имен и статей, а затем вывести их. Вывод будет иметь такой формат:

 { data: [ { id: 1, name: "Song 1", artist_name: "Artist 1" }, { id: 2, name: "Song 2", artist_name: "Artist 2" } ] } 

Это работает, как и ожидалось, но если схема таблицы изменится, изменится и вывод JSON. Теперь мы будем использовать фрактальный трансформатор для форсирования определенной структуры производства. Этот Transformer является классом, расширяющим Fractal\TransformerAbstract . Создайте новую папку для преобразователей в папке вашего приложения с именем transformers . Первым преобразователем является TracklistTransformer.php который мы будем использовать исключительно для /tracks , и он выглядит так:

 <?php namespace Musicstore; class TracklistTransformer extends \League\Fractal\TransformerAbstract { public function transform(Track $track) { return [ 'id' => (int) $track->id, 'title' => $track->title, 'artist' => $track->artist_name ]; } } 

Каждому преобразователю требуется метод transform() , аргументом которого является объект, который вы хотите преобразовать, в нашем случае это экземпляр класса Track . В операторе return структура определяется как ассоциативный массив.

Теперь мы применим преобразование и создадим выходной массив с использованием сериализатора . Мы собираемся использовать DataArraySerializer потому что это поместит наши данные под data-key в объекте JSON. Это позволяет вам иметь в своем ответе другую информацию, такую ​​как коды состояния или сообщения об ошибках. Чтобы использовать этот сериализатор, нам понадобится экземпляр класса manager. Для этого я буду использовать DI-контейнер, чтобы нам не приходилось каждый раз переписывать шаблонный код. Новый файл /controllers/tracks.php выглядит следующим образом:

 <?php $tracks = $app['controllers_factory']; $tracks->get('/', function() use ($app) { $tracks = Track::getTrackList(); $tracklist = new \League\Fractal\Resource\Collection($tracks, new TracklistTransformer); $output = $app['serializer']->createData($tracklist)->toArray(); return json_encode($output); }); return $tracks; 

Мы используем $tracklist = new \League\Fractal\Resource\Collection($tracks, new TracklistTransformer); применить преобразование. В этом маршруте мы используем коллекцию треков: наша переменная $tracks является объектом класса Illuminate \ Database \ Eloquent \ Collection . Этот класс совместим с Fractal и его преобразователями. Для другого маршрута мы будем использовать трансформатор для одного элемента таблицы. Но об этом чуть позже.

Для использования $app['serializer'] поместите этот код в index.php , прямо под оператором app['database'] :

 $app['serializer'] = $app->share(function() { $manager = new \League\Fractal\Manager(); $manager->setSerializer(new League\Fractal\Serializer\DataArraySerializer()); return $manager; }); 

Теперь у вас есть рабочий треклист.

Отслеживать информацию

Теперь я быстро продемонстрирую, как отображать информацию о конкретных дорожках, а затем вносить изменения в схему данных с помощью Fractal. Откройте controllers/tracks.php и добавьте следующий код над оператором возврата:

 <?php $tracks->get('/{id}', function($id) use ($app) { return Track::find($id); }); 

Track::find($id) возвращает объект класса Track с идентификатором, соответствующим URL. Опять же, это работает, но это не очень хороший способ, поэтому мы будем внедрять Fractal. Создайте новый трансформатор transformers/TrackTransformer.php :

 <?php namespace Musicstore; class TrackTransformer extends \League\Fractal\TransformerAbstract { public function transform(Track $track) { return [ 'id' => (int) $track->id, 'title' => $track->title, 'artist_name' => $track->artist_name, 'artist_website' => $track->artist_website, 'album_name' => $track->album_name, 'album_release' => $track->album_release, 'album_label' => $track->album_label ]; } } 

В вашем контроллере отредактируйте маршрут к этому:

 $tracks->get('/{id}', function($id) use ($app) { $track = Track::find($id); $track = new \League\Fractal\Resource\Item($track, new TrackTransformer); $output = $app['serializer']->createData($track)->toArray(); return json_encode($output); }); 

Как вы можете видеть, он довольно похож на предыдущий маршрут, за исключением того, что в данном случае мы имеем дело не с Collection а с одним Item . Если вы используете 1.sql вы можете перейти к localhost/app/tracks/1 1.sql localhost/app/tracks/1 и посмотреть некоторые примеры данных.

Обновленная версия API

Наш музыкальный магазин хочет расширяться и предоставлять больше информации об артистах и ​​альбомах. В новой схеме базы данных есть отдельные таблицы для художников и альбомов. Вы можете скачать 2.sql чтобы использовать новую схему. Таблицы выглядят так:

СЛЕДЫ:

  • Я бы
  • заглавие
  • artist_id
  • album_id

ХУДОЖНИКИ:

  • Я бы
  • имя
  • интернет сайт

АЛЬБОМЫ:

  • Я бы
  • имя
  • выпуск
  • метка

В таблице дорожек столбцы исполнителя и альбома представляют собой целые числа, которые соответствуют строкам в соответствующих таблицах. Мы будем использовать трансформеры, чтобы сохранить нашу структуру вывода одинаковой. Чтобы упростить задачу, мы будем использовать некоторые функции Illuminate\Database . Зайдите в models/Track.php и добавьте еще два метода:

 public function artist() { return $this->belongsTo('\Musicstore\Artist'); } public function album() { return $this->belongsTo('\Musicstore\Album'); } 

Если у нас есть объект Track мы можем получить доступ к его Album и Artist , используя $track->album и $track->artist . Сначала нам нужно создать эти модели, поэтому создайте два файла models/Artist.php и models/Album.php :

 // models/Artist.php <?php namespace Musicstore; class Artist extends \Illuminate\Database\Eloquent\Model { public function tracks() { return $this->hasMany('\Musicstore\Track'); } } // models/Album.php <?php namespace Musicstore; class Album extends \Illuminate\Database\Eloquent\Model { public function tracks() { return $this->hasMany('\Musicstore\Track'); } } 

Последнее, что нам нужно сделать, это отредактировать наши трансформеры:

 // transformers/TrackTransformer.php return [ 'id' => (int) $track->id, 'title' => $track->title, 'artist_name' => $track->artist->name, 'artist_website' => $track->artist->website, 'album_name' => $track->album->name, 'album_release' => $track->album->release, 'album_label' => $track->album->label ]; // transformers/TracklistTransformer.php return [ 'id' => (int) $track->id, 'title' => $track->title, 'artist' => $track->artist->name ]; 

Если вы все протестируете, вы увидите, что это работает.

Вывод

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