Laravel Scout теперь доступен разработчикам для тестирования



enter image description here
Laravel Scout - это драйвер для Eloquent, основанный для полнотекстового поиска, который будет доступен с момента запуска Laravel 5.3.

Официально драйвер пока не вышел, однако его репозиторий доступен для всех, кто желает “поиграться” с его возможностями.

Тейлор сказал, что на этой неделе он, в преддверии официального релиза версии 5.3, будет работать над документацией, и советует использовать этот первый релиз исключительно для тестирования, пока он не выйдет официально.

Для тех, кто не знаком со Scout, это пакет, облегчающий создание полнотекстового поиска в вашем проекте.

Scout работает путем внедрения трейта “Searchable” в существующие модели. Это простое решение для синхронизации данных с поисковым сервисом, например следующим образом:
php artisan scout:import App\\Post

После этого вы можете использовать поиск в своих моделях:
Post::search('Alice')->get();

И даже использовать постраничную разбивку:
Post::search('Alice')->paginate()

Вы даже можете делать выборку:
Post::search(‘Alice’)—>where('acount_id', '>', 1)->paginate()

Репозиторий уже содержит несколько пулл-реквестов на добавление дополнительных поисковых систем и Тейлор рекомендует разработчикам создавать свои собственные пакеты, как это произошло с Laravel Notifications.

После выхода 5.3 официальная документация для Scout будет доступна для чтения всем желающим.

Официальная статья

Разработка на Laravel с Docker. Часть 1



enter image description here
Одна из проблем, с которыми сталкивается каждая команда разработчиков - управление локальной средой разработки. Такие инструменты, как Vagrant в прошлом облегчили этот процесс, но работая с тяжелой ВМ они могут отнять много времени и ресурсов вашего компьютера.

Laravel является отличным PHP фреймворком для создания веб-приложений, кроме того он обеспечивает официальную поддержку некоторых решений, таких как Homestead и Valet. Но что, если вы хотите получить более тотальный контроль над локальным окружением, не обременяя себя управлением виртуальными машинами?
Вот здесь то нам и понадобится Docker!

Docker обеспечивает возможность создания и запуска легковесных контейнеров для любой службы, которая вам потребуется. Необходимо внести изменения в конфигурации PHP-FPM? Хотите изменить используемую версию PHP?
С Docker вы можете уничтожить всю локальную среду, перенастроить её и вернуть всё обратно в считанные секунды. tldr; Если вы просто хотите увидеть работающий пример кода на базе Laravel с установленным Docker - вот ссылка на репозиторий. В конце статьи есть GIF с примером того, как быстро вы можете уничтожить и восстановить всё окружение :)

Из-за интеграции Laravel со многими другими технологиями (MySQL, Redis, Memcached и т.д.), начальное конфигурирование может оказаться немного сложнее. Моя цель заключается в том, чтобы обеспечить высокий уровень понимания запуска приложений с Docker.

Установка Laravel

Для нашей цели подойдет установленный Laravel или Lumen. Если у вас уже есть приложение, вы можете пропустить этот шаг. Мы будем использовать установщик Laravel для быстрого создания нового приложения:
$ laravel new dockerApp
Application ready! Build something amazing.
Мы быстро можем проверить правильно ли установилось наше приложение с помощью встроенного сервера:
$ cd dockerApp
$ php artisan serve
enter image description here

Установка Docker

Docker доступен на платформах Mac, Windows и Linux. Выберите нужную платформу, а затем нажмите на неё, что бы чтобы установить определенную версию Docker. После этого у вас установится Docker, а также Docker Compose, который мы так же будем использовать.
После установки вы сможем запускать команды Docker:
$ docker –version
Docker version 1.12.0, build 8eab29e
$ docker-compose –version
docker-compose version 1.8.0, build f3628c7
$ docker ps
CONTAINER ID IMAGE COMMAND …
Если docker ps возвратил ошибку, убедитесь, что запущен демон Docker. Возможно, вам потребуется открыть Docker и запустить его вручную.
enter image description here

Локальная среда c Docker

Теперь самое интересное :) Скорее всего у вас есть установленная среда PHP, и, вероятно, вы знакомы с управлением веб-сервера (например, Apache или Nginx) в связке с PHP.

С Docker мы создаем контейнеры, в идеале предназначенные для какой-то единственной цели или вещи. Поэтому мы создадим один контейнер, который работает с Nginx для обработки веб-запросов, а другой контейнер для PHP-FPM, который будет обрабатывать запросы приложений. Концепция разделения двух этих вещей может показаться чем то странным, но именно она и реализует ту самую гибкость, которой славится Docker.

Вот краткий обзор того, что мы будем создавать.
enter image description here
Наши два контейнера cвязаны, таким образом они cмогут взаимодействовать друг с другом. Мы укажем точку для поступающего трафика на контейнер Nginx, который будет обрабатывать HTTP запросы, затем при необходимости связываться с PHP контейнером, который будет возвращать ответ.

Мы будем использовать Docker Compose, который облегчит задачу создания среды, что бы у нас не было необходимости каждый раз вручную создавать контейнеры. В корневом каталоге проекта добавим файл с названием docker-compose.yml:
    version: '2'
    services:
        web:
            build:
                context: ./
                dockerfile: web.docker
            volumes:
                - ./:/var/www
            ports:
                - "8080:80"
            links:
                - app
        app:
            build:
                context: ./
                dockerfile: app.docker
            volumes:
                - ./:/var/www
Если в кратце, здесь происходит следующее:
  • были объявлены 2 сервиса с названиями web и app
  • эти сервисы содержат в себе build, где устанавливается корневая директория для контекста, а так же перечисляются названия Dockerfiles, которые говорят Docker, как создавать контейнеры (мы создадим эти файлы ниже)
  • оба сервиса устанавливают /var/www как директорию для
    контейнеров
  • в web мы определяем порт нашей машины 8080, а так
    же указываем порт для контейнеров 80. Через него мы будем
    подключаться к нашему приложению. Вы можете изменить 8080 на любой предпочтительный порт.
  • web контейнер содержит “ссылку” на app контейнер. Это позволит ссылаться на app, как на хост для веб-контейнера, и Докер автоматически будет маршрутизировать трафика на этот контейнер
Вы можете найти больше информации о Docker Compose здесь, если хотите глубже его изучить.

Теперь нам нужно создать Dockerfiles, о которых мы упомянули выше. Dockerfile это просто набор инструкций для создания образа. Это похоже на инициализацию и предварительную настройку сервера, за исключением того, что базовые образы облегчают процесс конфигурации/инициализации.

Мы будем следовать стандартной конвенции именования Dockerfile файлов, которая приходится мне по душе - [service].docker. Создадим два файла в корневой директории проекта:
app.docker
FROM php:7-fpm

    RUN apt-get update && apt-get install -y libmcrypt-dev mysql-client \
        && docker-php-ext-install mcrypt pdo_mysql

    WORKDIR /var/www

web.docker
FROM nginx:1.10

    ADD ./vhost.conf /etc/nginx/conf.d/default.conf
    WORKDIR /var/www
С помощью dockerfile мы создаём базовый образ app, который использует официальный образ PHP с Docker Hub. Уже здесь мы можем увидеть одну из удивительных возможностей Docker. Если вы хотите использовать другую версию PHP - просто измените её в базовом образе, к примеру: php:5.6-fpm.

Затем мы запускаем пару команд шелла для установки расширения mcrypt (который в данный момент является зависимостью Laravel) и клиент MySQL, который мы будем использовать позже для нашей базы данных.

Контейнер web просто расширяет официальный образ Nginx и добавляет к контейнеру конфигурационный Nginx файл vhost.conf в /etc/nginx/conf.d. Теперь нам нужно создать этот файл.
vhost.conf
server {
        listen 80;
        index index.php index.html;
        root /var/www/public;

        location / {
            try_files $uri /index.php?$args;
        }

        location ~ \.php$ {
            fastcgi_split_path_info ^(.+\.php)(/.+)$;
            fastcgi_pass app:9000;
            fastcgi_index index.php;
            include fastcgi_params;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            fastcgi_param PATH_INFO $fastcgi_path_info;
        }
    }
Это довольно стандартная конфигурация Nginx, которая будет обрабатывать запросы и проксировать трафик в наш PHP контейнер (через приложение name на порт 9000). Вспомните, как ранее мы назвали наш сервис app в Docker Compose и ссылались на него из контейнера web, теперь Docker просто ссылается на это имя, зная, что трафик нужно маршрутизировать в контейнер app. Довольно аккуратное решение!

Мы прошли неплохой путь. В корне проекта выполним команду:
$ docker-compose up -d
Она запускает контейнеры Docker в фоновом режиме. В первые, когда вы запускаете, загрузка двух базовых образов может занять несколько минут, потом она будет проходить намного быстрее. Теперь мы можем посмотреть на наше приложение на http://localhost:8080:
enter image description here
Ура! Вот некоторые команды, которые могут вам пригодиться, чтобы взаимодействовать с контейнерами:
$ docker-compose up -d # start containers in background
$ docker-compose kill # stop containers
$ docker-compose up -d –build # force rebuild of Dockerfiles
$ docker-compose rm # remove stopped containers
$ docker ps # see list of running containers
$ docker exec -ti [NAME] bash
Последняя команда служит для открытия SSH в ВМ. Вы можете получить имя контейнера с помощью docker ps, а затем использовать exec команду для открытия интерактивной bash сессии в контейнере.

Ссылка на оригинальную статью

Заглушки Eloquent-отношений для быстрых тестов



Когда вы пишете тесты для модели Eloquent, зачастую нужен доступ непосредственно к базе данных, что бы проверить свой код в боевых условиях.

Но иногда функциональность тестирования не зависит от особенностей базы данных. Есть ли способ тестировать данные без отправки в базу данных?

Ссылка на видео-урок

Тестирование с базой данных
Скажем так, у нас есть альбомы Albums с песнями Songs и мы хотели бы протестировать расчёт общей продолжительность каждого альбома.
Тест может выглядеть следующим образом:
class AlbumTest extends TestCase
{
    use DatabaseMigrations;

    public function test_can_calculate_total_duration()
    {
        // 1. Создаём и сохраняем альбом в базе данных
        $album = factory('Album')->create();

        // 2. Создаем несколько песен с установленной продолжительностью
        $songs = new Collection([
            factory('Song')->make(['duration' => 291]),
            factory('Song')->make(['duration' => 123]),
            factory('Song')->make(['duration' => 100]),
        ]);

        // 3. Сохраняем их через отношение `songs`
        //    для установки внешних ключей
        $album->songs()->saveMany($songs);

        // 4. Убеждаемся, что продолжительность альбома       //    равна продолжительности всех песен
        $this->assertEquals(514, $album->duration);
    }
}
Простейшая реализация $album->duration может выглядеть следующим образом:
class Album extends Model
{
    // ...

    public function getDurationAttribute()
    {
        return $this->songs->sum('duration');
    }

    // ...
}
Если мы запустим этот тест то всё пройдет гладко, на моей машине он занял примерно ~ 90 мс.

Этот вариант подходит для тестов, которым действительно необходимо соединение с базой данных, и я полностью с этим согласен.

Но в данном случае мы не пытаемся проверить определенную область запроса или убедиться, что данные успешно сохранены, мы просто хотим посчитать некоторое число!

Для этого должен существовать другой путь!

In-memory отношения

Когда вы выполняете “нетерпеливую загрузку” (eager load) отношения, использование метода $album->songs не выполняет новый запрос; вместо этого происходит извлечение сохранённого в памяти Albums свойства Songs.

Можно ссылаться на нетерпеливого загрузку отношения вручную с помощью метода setRelation:
 public function test_can_calculate_total_duration()
  {
      $album = factory('Album')->create();

      $songs = new Collection([
          factory('Song')->make(['duration' => 291]),
          factory('Song')->make(['duration' => 123]),
          factory('Song')->make(['duration' => 100]),
      ]);

-     $album->songs()->saveMany($songs);
+     $album->setRelation('songs', $songs);

      $this->assertEquals(514, $album->duration);
  }
Теперь мы можем избавиться от трейта DatabaseMigrations и использовать make для создания Album вместо create, а оставшийся тест будет выглядеть следующим образом:
class AlbumTest extends TestCase
{
    public function test_can_calculate_total_duration()
    {
        $album = factory('Album')->make();

        $songs = new Collection([
            factory('Song')->make(['duration' => 291]),
            factory('Song')->make(['duration' => 123]),
            factory('Song')->make(['duration' => 100]),
        ]);

        $album->setRelation('songs', $songs);

        $this->assertEquals(514, $album->duration);
    }
}
Выполнение этого теста все еще занимает некоторое время, но на этот раз лишь 3мс! Это в тридцать раз быстрее.

Ничто не бесплатно

У всего есть минусы, и данный подход не исключение.

Если мы изменили нашу реализацию, чтобы суммировать продолжительность песен в базе данных, наш новый тест потерпит неудачу:
class Album extends Model
{
    // ...

    public function getDurationAttribute()
    {
        // Обратите внимание на дополнительные скобки!
        return $this->songs()->sum('duration');
    }

    // ...
}
Таким образом, в то время как повышение производительности колоссально, этот подход подводит нас к определенному виду реализации, который менее гибок для рефакторинга.

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



Ссылка на оригинальную статью

Изменения роутинга в Laravel 5.3



enter image description here
В нескольких последних версиях Laravel процесс маршрутизации претерпевал некоторые изменения. Происходило это, как правило, из-за того, что каждый раз мы чувствовали, что система всё еще не идеальна. В версии 5.3, мы, возможно, нашли золотую середину.

Оглянемся назад: изменения роутинга в Laravel 5.2

В Laravel 5.2 на некоторое время в routes.php маршруты были разделены на две группы, одна для “web” и вторая для “API”, но потом эту реализацию решили откатить.
После этого разработка встала, хотя была идея создать несколько middleware групп, одна из которых для “web” роутов, а другая для “API”.
Группа “web” получила бы весь функционал, в котором нуждаются пользователи интернета: сеансы, куки, защита CSRF и т.д. Группа “API” была бы более легковесной и по умолчанию являлась “throttle” посредником, что было бы хорошим аргументом в реализации REST API.

Изменения в роутинге Laravel 5.3

В версии 5.3, файл app/HTTP/routes.php переехал в корневую директорию маршрутов routes/, кроме того, теперь он разделён на два файла: web.php и api.php. Как вы наверное догадались, маршруты в routes/web.php обернуты в middleware группу web, а маршруты в routes/api.php, соответственно, обернуты в группу API.

В этой реализации есть несколько преимуществ. Во-первых, теперь наши роуты явно разделены на web и API, что упрощает работу с маршрутизацией. Во-вторых, теперь множество файлов маршрутизации согласуются на уровне приложения, что, вероятно, даёт больше свободы разработчикам, позволяя более удобно организовывать структуру маршрутов. И в-третьих, директория роутов перемещена из app/, что не только позволяет новичкам легче находить директорию роутов, но и делает директорию app/ полностью реализованной согласно стандарту автозагрузки PSR-4.

Если вы хотите настроить маршрутизацию или добавить свои собственные файлы роутов, ознакомьтесь с App\Providers\RouteServiceProvider:
...
    public function map()
    {
        $this->mapWebRoutes();

        $this->mapApiRoutes();

        //
    }

    protected function mapWebRoutes()
    {
        Route::group([
            'namespace' => $this->namespace, 'middleware' => 'web',
        ], function ($router) {
            require base_path('routes/web.php');
        });
    }

    protected function mapApiRoutes()
    {
        Route::group([
            'middleware' => ['api', 'auth:api'],
            'namespace' => $this->namespace,
            'prefix' => 'api',
        ], function ($router) {
            require base_path('routes/api.php');
        });
    }
Как вы могли заметить, существует простой синтаксис для обертывания любых файлов-маршрутов в группу роутов, что бы затем применять к ним какие-либо префиксы или middleware, либо выполнять с ними какие-то другие действия.

Оригинальная статья

Laravel Mailable: Новый улучшенный способ отправки электронной почты в Laravel



enter image description here
Новый функционал Laravel 5.3 позволит упростить отправку электронной почты путем создания “mailable” классов, обрабатывающих настройки отправки ваших сообщений.
Лучше всего описать эту возможность получится на примере. В Laravel 5.2 обычно вы отправляли сообщения электронной почты способом, описанным в документации:
Mail::send('emails.reminder', ['user' => $user], function ($m) use ($user) {
    $m->from('hello@app.com', 'Your Application');
    $m->to($user->email, $user->name)->subject('Your Reminder!');
}); 
Многое происходит в этих четырёх строках кода. Вы описываете шаблон, данные для этого шаблона, используете анонимную функцию с user, и, наконец, настраиваете ваше сообщение.
В настоящее время в Laravel 5.3 вы можете упростить этот процесс за счёт класса mailable.
php artisan make:mail YourReminder
Откройте новый класс, как только он создастся, и вся конфигурация отправки электронной почты сразу станет доступна в методе build. Внутри него вы можете вызывать различные методы, такие как from, subject, view, для настройки отправки сообщений. Ниже приведён краткий пример:
public function build()
{
    return $this->from('example@example.com')
        ->view('emails.reminder');
}
Теперь, если вы захотите отправить сообщение по электронной почте, вы в любой момент можете воспользоваться фасадом Mail:
Mail::to($email)->send(new YourReminder);
Почти весь существующий функционал для отправки сообщений уже работает. Вам доступны очереди, добавление cc и bcc полей, прикрепление файлов и многое другое.
Вот несколько ресурсов, если вы желаете узнать больше о Laravel Mailable:

Оригинальная статья

Простая интеграция HTTP/2 Server Push с помощью Laravel Middleware


enter image description here
Как мы все знаем, технологии сменяются быстро, и если вы не оглядываетесь вокруг, вы можете упустить что-то новое. HTTP/2 является одной из таких технологий, до доклада Бена Рэмси на Лараконе я и понятия о ней не имел.
Вы можете найти его доклад с презентацией здесь, а отдельная презентация находится на его сайте. Больше всего меня поразило то, с какой легкостью можно использовать server push или предзагрузку. Вы просто посылаете специальный “Link” заголовок всем активным страницам, а затем, если его поддерживают браузер и сервер, сеть начинает работать более эффективно.

Во время доклада Бен привёл пример использования этой функции в Laravel:
return response($content, $status)
->header('Link', '; rel=preload; as=style', false)
->header('Link', '; rel=preload; as=script', false);
Конечно, делать предзагрузку таким образом для каждого ассета в проекте - затея так себе. К счастью, нам доступно аж целых два пакета в Laravel, которые могут автоматически делать это через Middleware.

Первый пакет создал Том Шлик, а второй - Джейкоб Беннетт. Оба пакета в основном делают то же самое, но каждый интегрируется по разному.
Том сделал автоматическую подгрузку ресурсов в файле elixir’a /build/rev-manifest.json. Для добавления ресурсов необходимо использовать следующую конструкцию:
pushStyle($pathOfCssFile);
pushScript($pathOfJsFile);
pushImage($pathOfImageFile);

Джейкоб пошёл другим путём и еще больше автоматизировал процесс - его пакет автоматически сканирует DOM и автоматически добавляет заголовки для любого скрипта, стиля или изображения.

Какой из них вам выбрать будет зависеть от вашего проекта и ваших предпочтений. Пакет Джейкоба можно установить и забыть о нём, но он каждый раз сканирует DOM, чтобы найти все ассеты. Пакет Тома потребует больше усилий на настройку, но тем самым позволяет контролировать все аспекты своей работы.

Если вы хотите улучшить производительность вашего приложения Laravel - обязательно попробуйте этот способ.

Оригинальная статья

Отслеживание кликов в Laravel


В то время, когда Google Analytics не доступен, вы можете использовать небольшой клик-трекер прямо в Laravel.

Для кого эта статья:
  • Для разработчиков на Laravel и подрастающих злодеев, работающих с данными
tl;dr
  • Отслеживание кликов в Laravel является неимоверно легким занятием, которое может обеспечить неплохую основу для вашей собственной системы аналитики в приложении.
Последние несколько месяцев Inquiri занимается разработкой CMS для поддержки сообщества участников фармацевтических исследований. Кроме других особенностей, платформа предлагает этим участникам постоянный поток сторонних статей.