Laravel по-русски

Русское сообщество разработки на PHP-фреймворке Laravel.

Ты не вошёл. Вход тут.

#1 15.03.2015 11:28:10

Использование собственных библиотек.

Третий день сижу.
Хотя особым новичком себя не чувствовал до этого.
Прошу, пришлите пару вменяемых ссылок о том как использовать собственные библиотеки в Laravel.
Интересует как это верно "По феншую" создать свой клас, который сможет общаться с класами Eloquent. Как вызвать его с контролера и тд.
Очень много путаницы в этот вопрос вносит разница в загрузке класов между  laravel 4 в 5.

То что нашел но не помогло
http://stackoverflow.com/questions/2569 … controller
Секции "autoload":  laravel 5 нету. Я так понимаю перешли на стандарт  "psr-4" и так делать не рекомендуется.

Опять же пример для 4 той версии http://fideloper.com/laravel-4-applicat … utoloading.
  Все как бы хорошо но непонятно как с  ипользуемой бибилиотеки использовать Eloquent. Да и библиотеку не хотелось бы каждый раз по новому инициилизировать  и в каждом класе писать:

 $anvil = new Acme\Product\AnvilHeavy; 

Буду очень благодарен за реальный пример.

Не в сети

#2 15.03.2015 21:12:44

Re: Использование собственных библиотек.

Мне помогли немного понять эти скринкасты:

http://www.youtube.com/watch?v=uANgBsrl … 4hRbND7MZ0

Не в сети

#3 16.03.2015 07:51:58

Re: Использование собственных библиотек.

svadim, я не совсем понял насчёт «библиотек» и «классов» — что именно нужно-то?

если добавить класс — он кладётся в app в нужную папку в соответствии с PSR4. инстанцируется либо через new либо DI-контейнером.

например.

пусть я создаю класс, который инкапсулирует весь функционал по отслеживанию посещений сайта пользователями. у меня есть модель UserVisitsLogEntry и миддлварь LogVisitIfAuthenticated. можно конечно весь код нафигачить в миддлварь, но если мне потом понадобится взаимодействовать с логгером ещё где-то в коде (например, при авторизации — закрывать предыдущее посещение и начинать новое) — придётся плодить копипасту. поэтому я выношу весь код в класс VisitLogger.

теперь я задаю себе вопрос: а VisitLogger — это что? по всему выходит, что это изолированный класс, который предоставляет определённый функционал приложению через фиксированное апи, т.е. сервис. поэтому я создаю в app\Services\ файл VisitLogger.php с классом VisitLogger и добавляю ему метод visit.

в приципе здесь я уже могу этот класс инстанцировать и вызывать этот метод средствами пхп: PHP(new \App\Services\VisitLogger)->visit(), но встаёт вопрос — откуда класс и его метод возьмёт информацию о пользователе? а если мне нужно логировать ip пользователя, то за ip надо ещё лезть в Request. я могу воспользоваться фасадами \Auth и \Request соответственно, но это не laravel5-way. фасады достались в наследство от л4 и по возможности надо стараться избегать их использования. в л5 наше приложение является DI-контейнером, который может внедрить в класс нужные зависимости, нам надо только указать контракт.

допустим я решаю внедрять зависимости через конструктор, я добавляю к VisitLogger конструктор PHPfunction __construct(Guard $authRequest $request) а умный пхпсторм сразу добавляет в шапку файла PHPuse Illuminate\Contracts\Auth\Guard; и PHPuse Illuminate\Http\Request;. теперь мне надо инстанцировать класс не через new а через контейнер: PHPapp()->make('App\Services\VisitLogger')->visit().

если бы я решил внедрить зависимости в метод visit, вызов был бы например такой PHPapp()->call('App\Services\VisitLogger@visit). но в данном случае это не очень удобно, поскольку кроме visit у меня ещё добавится login для обработки входов пользователя — а зависимости используются обоими методами сервиса. поскольку все зависимости создаются и внедряются через контейнер, обработку логинов можно добавить, например, элементарно добавив обработчик события PHP'auth.login' => [ 'App\Services\VisitLogger@login' ] в поле $listen в App\Providers\EventServiceProvider.

всё прекрасно, если мы просто делаем сайтик для заказчика, но если нам надо предоставить выбор способа логирования визитов через конфиг (например если мы готовим повторно используемый компонент для 100500 сайтов или просто хотим всё спроектировать по фэншую с расчётом на будущее) — остаётся сделать один шаг. добавить контракт App\Contracts\VisitLogger, сделать сервис реализацией этого контракта (implements), и связать их через контейнер, добавив в register в App\Providers\AppServiceProvider вызов PHP$this->app->bind('App\Contracts\VisitLogger''App\Services\VisitLogger');. теперь мы можем написать реализации DummyVisitLogger, TimeoutBasedVisitLogger, CrossSiteVisitLogger и т.п., добавить к конфигам настройку — какой логгер мы подключаем с какими настройками и в зависимости от настроек — привязывать нужный логгер к контракту в сервис-провайдере.

для независимых библиотек просто добавляется собственный корень в неймспейсах — так поступают библиотеки, которые устанавливаются композером. но ничто не мешает тебе вручную добавить в качестве корня любую другую папку в приложении. в библиотеке у тебя будет свой конфиг, свой сервис провайдер, контракты и их реализации в своём неймспейсе, но структура останется неизменной. останется только подключить свой сервис-провайдер в config/app.php.

Изменено constb (16.03.2015 07:57:53)

Не в сети

#4 16.03.2015 14:12:00

Re: Использование собственных библиотек.

constb, да вам батенька статьи на хабре нужно писать.

Одним компактным постом изложили всю концепцию Laravel 5.
У Вас блога нет случайно по Laravel, я бы там "прописался"))) Или уроков каких?

Не в сети

#5 16.03.2015 14:48:11

Re: Использование собственных библиотек.

не, это на меня с утра что-то нашло, счас вроде отпустило. )

Не в сети

#6 01.04.2016 12:20:52

Андрей

Re: Использование собственных библиотек.

Доброе время суток!
Constb, спасибо вам за ответ, но для меня осталось загадкой, в чем смысл биндинга
$this->app->bind('App\Contracts\VisitLogger', 'App\Services\VisitLogger');

В определении VisitLogger вы уже указывали implements App\Contracts\VisitLogger,

Вызов app()->make('App\Services\VisitLogger')->visit() работает  вне зависимости от этого биндинга.

Поэтому смысл биндинга не ясен.

#7 01.04.2016 13:02:29

Андрей

Re: Использование собственных библиотек.

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

У меня есть контроллер,  сейчас в нем в действии аналог вашего
app()->make('App\Services\VisitLogger')->visit();

примерно так (с логированием не связан на самом деле, но это сейчас не суть важно):

    public function index()
    {
        app()->make('App\Services\VisitLogger')->visit();
       
        //return view('index');
    }
   
   

а будет еще куча таких вызовов в разных контроллерах.

Когда наступит лихая година, и я захочу использовать DummyVisitLogger вместо VisitLogger.
хочется заменить это в одном месте, по идее, в сервис провайдере.

Но непонятно, на что  надо заменить app()->make('App\Services\VisitLogger')
чтобы потом просто поменять биндинг в сервис провайдере?

Вариантов придумать на самом деле могу несколько,
1 наследование всех контроллеров приложения некоторому контроллеру  - прослойке,
в котором будет
$this->_logger = app()->make('App\Services\VisitLogger');

(но тогда зачем мне весь этот ваш биндинг???)


2. Использование миддлвара для инициализации $this->_logger  необходимой реаллизацией (тут не уверен, но думаю возможно)
    (но тогда зачем мне весь этот ваш биндинг???)
   
3. Создать собственный сервис-контейнер, и тогда
  CustomContaiiner()->getImplementation('App\Conracts\IVisitLogger');
 
  (но хочется использовать все-таки готовое решение)
 

А больше всего интересно, как на самом деле правильно?

#8 01.04.2016 13:10:03

Андрей

Re: Использование собственных библиотек.

Ура, понял!
После биндинга просто пишу в контроллере

use App\Contracts\VisitLogger;

public function index(VisitLogger $logger)
    {
        $logger->visit();
       
        //return view('index');
    }

Вот почему-то в голову приходит в последнюю очередь -(

Подвал раздела