質問

I am having an issue getting a Facade to work properly with a dependency injected into the underlying class.

I have a class called 'Listing'. It has one dependency called 'AdvertRepository' which is an interface and a class called EloquentAdvert which implements the interface. The code for these three classes is here:

// PlaneSaleing\Providers\Listing.php

<?php namespace PlaneSaleing\Providers;

use PlaneSaleing\Repositories\Advert\AdvertRepository;

class Listing {

    protected $advert;

    public function __construct (AdvertRepository $advert_repository) {
        $this->advert = $advert_repository;
    }

    public function test() {
            $this->advert->test();
    }

    public function test2() {
        echo "this has worked";
    }
}

// PlaneSaleing\Repositories\Advert\AdvertRepository.php

<?php namespace PlaneSaleing\Repositories\Advert;

interface AdvertRepository {

    public function test();

}

// PlaneSaleing\Repositories\Advert\EloquentAdvert.php;

<?php namespace PlaneSaleing\Repositories\Advert;

class EloquentAdvert implements AdvertRepository {

    public function test() {
        echo 'this has worked';
    }
}

I have then created a service provider called ListingServiceProvider.php, which has the following code:

// PlaneSaleing/Providers/ListingServiceProvider.php

<?php  namespace PlaneSaleing\Providers;

use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\App;

class ListingServiceProvider extends ServiceProvider {

    public function register() {

        App::bind('PlaneSaleing\Repositories\Advert\AdvertRepository', 'PlaneSaleing\Repositories\Advert\EloquentAdvert');

    }
}

I also added this to the ServiceProviders array in app.php

Now, if I inject Listing as a dependency into a controller and call the test method (as shown below) Laravel correctly detects the dependency, instantiates EloquentAdvert via its binding and displays 'this has worked'.

// Controllers/TestController.php

use PlaneSaleing\Providers\Listing;

class TestController extends BaseController {

    protected $listing;

    public function __construct(Listing $listing) {
        $this->listing = $listing;
    }

    public function test1() {
        $this->listing->test();
    }
}

Now, I then created a facade for Listing. I added a new facade as follows and added an alias in app.php:

// PlaneSaleing\Providers\ListingFacade.php

<?php  namespace PlaneSaleing\Providers;

use Illuminate\Support\Facades\Facade;

class ListingFacade extends Facade {

    protected static function getFacadeAccessor() {

        return 'Listing';
    }
}

I also added the following new lines to ListingServiceProvider.php:

<?php  namespace PlaneSaleing\Providers;

use PlaneSaleing\Repositories\Advert\AdvertRepository;
use PlaneSaleing\Repositories\Advert\EloquentAdvert;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\App;

class ListingServiceProvider extends ServiceProvider {

    public function register() {

        App::bind('PlaneSaleing\Repositories\Advert\AdvertRepository', 'PlaneSaleing\Repositories\Advert\EloquentAdvert');

        // New lines...
        $this->app['Listing'] = $this->app->share(function() {
            return new Listing(new AdvertRepository);
        });
    }
}

NOW...if I call Listing::test(), I get the following error: Cannot instantiate interface PlaneSaleing\Repositories\Advert\AdvertRepository.

If I call Listing::test2() , I get 'this has worked' so it seems the Facade is working correctly.

It seems that when accessing Listing via its Facade the binding between AdvertRepository and EloquentAdvert doesnt work. I have looked at my code in the ServiceProvider thinking it was the issue, but I cant figure it out.

Both the Facade and binding work when tested individually but not when both are used at the same time.

Any ideas???

役に立ちましたか?

解決

OK, So I have figured it out...For those who run into a similar problem...

The offending statement was in ListingServiceProvider.php which read:

$this->app['Listing'] = $this->app->share(function() {
    return new Listing(new AdvertRepository);
});

The error is the new AdvertRepository statement. The reason being is that, we are telling php to directly instantiate the interface 'AdvertRepository'. Instead, we need to tell Laravel to instantiate the appropriate implementation of the 'AdvertRepository' interface. To do that, we use App::make('AdvertRepository'). That way, Laravel uses the binding previously declared to instantiate the correct implementation.

他のヒント

If your constructor is not being inject with a class, you must tell Laravel what class will be used when it needs to instantiate a particular interface:

Put this in your filters or bindings file:

App::bind('PlaneSaleing\Repositories\Advert\AdvertRepository', function()
{
    return new PlaneSaleing\Repositories\Advert\EloquentAdvert;
});
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top