Laravel 4 Добавить метод в класс (IoC / Namespaces)

#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 , и они не делали никаких привязок. Они также вызывают create PageModule 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 (дикое предположение)