#php #laravel #namespaces #inversion-of-control
#php #laravel #пространства имен #инверсия управления
Вопрос:
Я пытаюсь выяснить, как добавить метод в класс в пакете Laravel, чтобы все контроллеры и модели, вызывающие этот класс, могли получить доступ к новому методу. Как мне заменить этот класс в МоК?
Это пакет, о котором идет речь, Angel CMS.Пакет — это мое творение, поэтому я могу изменить его, если нам нужно добавить псевдонимы или что-нибудь для этого.
Допустим, я хочу добавить метод в этот класс:
vendor/angel/core/src/models/PageModule.php
Хорошо, поэтому я копирую файл класса сюда:
app/models/PageModule.php
А затем я изменяю скопированный файл, добавляя пространство имен и желаемый custom_function
метод:
<?php namespace MyModels;
use Eloquent;
class PageModule extends Eloquent {
protected $table = 'pages_modules';
public static function custom_function()
{
return 'It works!';
}
}
Как вы можете видеть, я использую MyModels
здесь пространство имен.
Затем я запускаю composer dump-autoload
.
Затем я открываю app/routes.php
и регистрирую привязку и настраиваю тестовый маршрут:
App::bind('PageModule', function($app) {
return new MyModelsPageModule;
});
Route::get('test-binding', function() {
return PageModule::custom_function();
});
Но при посещении тестового маршрута я всегда получаю ту же ошибку, что метод не определен.
Что я здесь делаю не так? Заранее благодарю вас за любую помощь.
Чтобы уточнить:
Я пытаюсь заменить класс для всего приложения, чтобы все другие классы (контроллеры / модели / и т.д.), Которые вызывают PageModule, имели доступ к custom_function
методу. Спасибо.
Комментарии:
1. Я не думаю, что есть простой способ сделать это. Я проверил их
CoreServiceProvider.php
, и они не делали никаких привязок. Они также вызывают createPageModule
object непосредственно в своих контроллерах , используяnew PageModule
.2. @Unnawut, пакет мой — я могу добавить все необходимое, чтобы заставить это работать. Как вы думаете, я должен привязывать псевдонимы для создания легко заменяемых классов или как мне это сделать?
3. Это может показаться раздражающим, и я уверен, что вы бы уже сделали это, если бы это соответствовало вашему сценарию, но что мешает вам напрямую модифицировать класс PageModule?
4. @Unnaawut — это пакет composer, что означает, что он перезаписывается при каждом обновлении (в поставщике / папке). Нам нужно найти какой-то способ расширения классов по-разному на десятках разных веб-сайтов, для каждого из которых потребуются разные методы, чтобы они не перезаписывались. Это то, для чего был создан IoC, я просто не понимаю, как его использовать. 🙁
5. Хорошо, это в значительной степени тот ответ, который я ожидал, я попробую написать ответ на это.
Ответ №1:
Честно говоря, я довольно новичок во всем этом IoC, концепции инверсии / внедрения зависимостей. Но я думаю, что раньше я проходил через ту же борьбу. Что я бы сделал, насколько позволяют мои знания, так это…
Добавьте конструктор в src/controllers/admin/AdminPageController.php:
protected $pageModule;
public function __construct(PageModule $pageModule)
{
$this->pageModule = $pageModule;
}
Затем, где вы сделали $module = new PageModule
в том же файле. Вы заменяете его на:
$module = $this->pageModule;
В двух приведенных выше модификациях используется IoC Laravel, позволяющий вводить другой объект PageModule в ваш контроллер, вместо того, чтобы строго создавать PageModule в вашем коде.
Теперь на этом этапе Laravel должен знать, что когда он создает AdminPageController, он должен создать PageModule и внедрить его в контроллер для вас.
Поскольку ваш контроллер теперь ожидает класс PageModule, вы больше не можете этого делать class PageModule extends Eloquent
в своем приложении, потому что, хотя имя то же самое, PHP не думает, что это так! Вам нужно будет расширить его:
Итак, давайте переименуем ваш app/models/PageModule.php
в app/models/CustomPageModule.php
, а в файле изменим класс на:
class CustomPageModule extends PageModule {
До этого момента у вас также был CustomPageModule
класс, который является дочерним по отношению к вашему пакету PageModule
. Все, что вам нужно сделать сейчас, это сообщить Laravel, что если какие-либо контроллеры запрашивают PageModule
, он должен обслуживать контроллер вместе с вашим MyModelsCustomPageModule
.
Итак, в верхней части routes.php
файла вашего приложения:
App::bind('PageModule', 'MyModelsCustomPageModule');
AdminPageController
Теперь вы должны использовать свой CustomPageModule
и можете использовать любые общедоступные методы, которые там есть!
Я ожидаю, что буду сильно редактировать этот ответ, так как это будет довольно долгое обсуждение. Моя первая попытка ответить на вышеприведенный вопрос — не самый лучший код, который вы можете написать, но я надеюсь, что для этого потребуется наименьшее количество правок в исходном коде, и тогда мы сможем продолжить работу.
Или ускорьте процесс, прочитав такие статьи, как http://culttt.com/2013/07/08/creating-flexible-controllers-in-laravel-4-using-repositories
Комментарии:
1. Кстати, этот ответ был написан вместе со мной, модифицирующим код моего проекта, и он работает. Поэтому я надеюсь, что это сработает везде.
2. Эй, еще раз большое спасибо @Unnawut. Ты направил меня в правильном направлении… Я должен заменить все случаи прямых
PageModule::
вызовов во всей используемой структуре$pageModuleModel = App::make('PageModule'); $pageModule::
, аналогично тому, как работают инъекции зависимостей конструктора. Это огромный капитальный ремонт (я собираюсь сделать это для всех контроллеров и моделей, а не толькоPageModule
), но оно того стоит! Спасибо!3. @Leng Рад, что это помогает! Я думаю, что это заслуживает еще одного вопроса от него самого. Несмотря на то, что контент о IoC и инверсии / внедрении зависимостей повсюду. Я не нашел ничего конкретного о разработке легко расширяемых пакетов, таких как создание пакета CMS.
4. @Leng на самом деле, говоря о легко расширяемых пакетах, мне приходит в голову этот Laravel-Administrator . Поскольку предполагается, что он подходит в качестве бэкэнд-администратора для всех видов приложений Laravel, я думаю, вы могли бы получить несколько хороших идей, просмотрев их исходный код.
5. Потрясающе! Еще раз спасибо — этот
Laravel-Administrator
пакет окажет огромную помощь в понимании того, как правильно использовать привязки и пространства имен!
Ответ №2:
Вероятно, у вас есть псевдоним для PageModule
фасада, вы должны переопределить этот псевдоним, используя свой класс MyModelsPageModule
в вашем app/config/app.php
файле.
Будьте осторожны, похоже, что вы перезаписываете PageModule
класс вместо его расширения. Вероятно, вам следует расширить родительский класс вместо Eloquent
.
Комментарии:
1. Спасибо за вашу помощь. К сожалению, в пакете нет фасадов, и я действительно пытаюсь заменить класс, чтобы все другие классы, вызывающие PageModule, загружали мой новый класс пользовательской функцией.
2. Возможно, использование псевдонимов для всех моих классов, которые я хочу расширить, действительно было бы хорошим решением? Полное сообщение об ошибке
Call to undefined method IlluminateDatabaseQueryBuilder::custom_function()
3. Angel CMS — это мой пакет, поэтому я могу настроить псевдонимы, если вы считаете, что это было бы более чистым решением!
4. Похоже, вы на самом деле не расширяете Eloquent… Попробуйте удалить
use
оператор и расширить Eloquent с помощьюextends Eloquent
(дикое предположение)