Пространства имен опущены для краткости …
Я написал следующий поставщик услуг и зарегистрирован в config / app.php:
class OfferServiceProvider extends ServiceProvider { public function register() { $this->registerLossControlManager(); } protected function registerLossControlManager() { $this->app->bind('LossControlInterface', 'LossControl'); } }
Вот мой LossControlInterface
interface LossControlInterface { /** * @param int $demandId * @param float $offerTotal * @param float $productTotal * @param null|int $partnerId * @return mixed */ public function make($demandId, $offerTotal, $productTotal, $partnerId = null); /** * @return float */ public function getAcceptableLoss(); /** * @return bool */ public function isAcceptable(); /** * @return bool */ public function isUnacceptable(); /** * @return null */ public function reject(); }
Теперь в контроллере я могу ввести LossController следующим образом:
use LossControlInterface as LossControl; class HomeController extends BaseController { public function __construct(LossControl $lossControl) { $this->lossControl = $lossControl; } public function getLossThresholds() { $lossControl = $this->lossControl->make(985, 1000, null); var_dump('Acceptable Loss: ' . $lossControl->getAcceptableLoss()); var_dump('Actual Loss: ' . $lossControl->calculateLoss()); var_dump('Acceptable? ' . $lossControl->isAcceptable()); } }
Однако, если я пытаюсь зависеть, вставьте LossControlInterface из пользовательского класса, вызванного командой:
[2014-09-02 13:09:52] development.ERROR: exception 'ErrorException' with message 'Argument 11 passed to Offer::__construct() must be an instance of LossControlInterface, none given, called in /home/vagrant/Code/.../ProcessOffer.php on line 44 and defined' in /home/vagrant/Code/.../Offer.php:79
Кажется, что я не могу зависеть от ввода интерфейса в пользовательский класс, но я могу, когда зависимость вводится в контроллер.
Любые мысли о том, что я делаю неправильно или не принимали автоматическое разрешение?
IoC является автоматическим в контроллерах, и вы не видите инъекцию, потому что Laravel обрабатывает для вас конструкцию контроллеров. При создании любого другого пользовательского класса с помощью new
ключевого слова вам все равно придется отправлять все параметры, необходимые для его конструктора:
$myClass = new ClassWithDependency( app()->make('Dependency') );
Вы можете скрыть это, в определенной степени, путем создания вашего пользовательского класса через поставщика услуг:
// Your service provider public function register() { $this->app->bind('ClassWithDependency', function($app) { return new ClassWithDependency( $app->make('Dependency') ); }); }
Тогда просто сделайте IoC, когда вам это нужно:
$myClass = app()->make('ClassWithDepenency');
В вашем случае вы можете изменить свой код так, чтобы он выглядел следующим образом:
private function setOffer(Offer $offer = null) { $this->processOffer = $offer ?: new Offer( app()->make('LossControlInterface') ); }
Возможно, более чистым подходом может быть создание поставщика услуг и OfferFactory
который вводится в ваш контроллер. Затем контроллер может запросить фабрику, чтобы создать предложение, когда ему это нужно:
// Controller public function __construct(OfferFactory $offerFactory) { $this->offerFactory = $offerFactory; } public function setOffer(Offer $offer = null) { $this->processOffer = $offer ?: $this->offerFactory->createOffer(); } // OfferFactory class OfferFactory { public function createOffer() { return app()->make('Offer'); } }
Это позволяет полностью развязать контроллер с логикой создания предложения, но при этом вы можете иметь место, чтобы добавить любую сложность, необходимую для процесса создания предложений.
В Laravel 5.2 самым простым решением для вашей конкретной проблемы было бы заменить
new Offer();
с
App::make('Offer');
или даже короче
app('Offer');
который будет использовать Laravel Container, чтобы заботиться о зависимостях.
Если вы хотите передать дополнительные параметры в конструктор Offer
, необходимо связать его с поставщиком услуг
App::bind('Offer', function($app, $args) { return new Offer($app->make('LossControl'), $args); });
И вуаля, теперь вы можете написать
app('Offer', [123, 456]);
В laravel 5.4 ( https://github.com/laravel/framework/pull/18271 ) вам нужно использовать новый метод makeWith контейнера IoC.
App::makeWith( 'App\MyNameSpace\MyClass', [ $id ] );
если вы все еще используете 5.3 или ниже, приведенные выше ответы будут работать.