laravel / framework

The Laravel Framework.
https://laravel.com
MIT License
32.21k stars 10.9k forks source link

Problem with Artisan::resolve() - 4.1 #2881

Closed antonioribeiro closed 10 years ago

antonioribeiro commented 10 years ago

This is what I have:

Adding the command to Artisan via resolve():

Artisan::resolve('App\Commands\Whitelist');

The Command:

<?php namespace App\Commands;

use Illuminate\Console\Command;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
use App\Repositories\DataRepositoryInterface;

class Whitelist extends Command {

    protected $name = 'app:whitelist';

    protected $dataRepository;

    protected $description = 'Whitelist an IP address to the app.';

    public function __construct(DataRepositoryInterface $dataRepository)
    {
        parent::__construct();

        $this->dataRepository = $dataRepository;
    }

    public function fire()
    {
        echo $this->argument('ip');
    }

    protected function getArguments()
    {
        return array(
            array('ip', InputArgument::REQUIRED, 'The IP address to be whitelisted.'),
        );
    }

}

Trying to use the command gives me this error:

[2013-12-07 22:34:54] development.ERROR: exception 'ReflectionException' with message 'Class App\Repositories\DataRepositoryInterface does not exist' in /application.dev/app/vendor/laravel/framework/src/Illuminate/Container/Container.php:522
Stack trace:
#0 application.dev/app/vendor/laravel/framework/src/Illuminate/Container/Container.php(522): ReflectionParameter->getClass()
#1 application.dev/app/vendor/laravel/framework/src/Illuminate/Container/Container.php(505): Illuminate\Container\Container->getDependencies(Array)
#2 application.dev/app/vendor/laravel/framework/src/Illuminate/Container/Container.php(416): Illuminate\Container\Container->build('App...', Array)
#3 application.dev/app/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(423): Illuminate\Container\Container->make('App...', Array)
#4 application.dev/app/vendor/laravel/framework/src/Illuminate/Container/Container.php(752): Illuminate\Foundation\Application->make('App...')
#5 application.dev/app/vendor/laravel/framework/src/Illuminate/Console/Application.php(133): Illuminate\Container\Container->offsetGet('App...')
#6 application.dev/app/vendor/laravel/framework/src/Illuminate/Support/Facades/Facade.php(208): Illuminate\Console\Application->resolve('App...')
#7 application.dev/app/app/start/artisan.php(14): Illuminate\Support\Facades\Facade::__callStatic('resolve', Array)
#8 application.dev/app/app/start/artisan.php(14): Illuminate\Support\Facades\Artisan::resolve('App...')
#9 application.dev/app/vendor/laravel/framework/src/Illuminate/Console/Application.php(62): require('/application.dev...')
#10 application.dev/app/vendor/laravel/framework/src/Illuminate/Console/Application.php(32): Illuminate\Console\Application->boot()
#11 application.dev/app/artisan(46): Illuminate\Console\Application::start(Object(Illuminate\Foundation\Application))
#12 {main} [] []

But I also have this controller where the same resolution works fine:

<? namespace App\Controllers;

use Controller;
use Redirect;
use App\Repositories\DataRepositoryInterface;

class FirewallController extends BaseController {

    private $dataRepository;

    public function __construct(DataRepositoryInterface $dataRepository)
    {
        $this->dataRepository = $dataRepository;
    }

    public function whitelist($ip)
    {   
        return Redirect::to('/')->withMessages(
                                                $this->
                                                dataRepository->
                                                firewall->
                                                addToWhitelist($ip)->
                                                getMessages()
                                            );

    }

}

Without the dependency command works fine.

Am I doing something wrong or it's a bug?

Anahkiasen commented 10 years ago

What are you binding to your interface and where are you binding it ?

antonioribeiro commented 10 years ago

Using a bindings.php separate file loaded in app/start/globals.php

require app_path().'/bindings.php';

To bind the interface to the concrete class:

App::bind(
            'App\Repositories\DataRepositoryInterface', 
            'App\Repositories\DataRepository'
        );

Also tried to put this in routes file.

Also tried to use the concrete class instead of the interface.

taylorotwell commented 10 years ago

Where do you add the command? start/artisan.php?

antonioribeiro commented 10 years ago

Yes!

taylorotwell commented 10 years ago

Have you tried a composer dump? Odd that it works in your controller.

taylorotwell commented 10 years ago

Also maybe try a fresh composer update to make sure you're totally up to date.

antonioribeiro commented 10 years ago

Did that too, while trying to figure out. Did it again now, got a new commit, but still the same. App is a fresh 4.1 install, so this is also not an upgrade-from-4.0-problem.

There's something I think might help understand it better: trying to instantiate the concrete class in artisan.php

<?php

$dataRepository = new App\Repositories\DataRepository;

//Artisan::resolve('App\Commands\Whitelist');

Gives the same error:

PHP Fatal error: Class 'App\DataRepository' not found in /application.dve/app/start/artisan.php on line 14

I was trying to instantiate it and pass to App::add().

taylorotwell commented 10 years ago

Your fatal error says class "App\DataRepository" instead of "App\Repositories\DataRepository"...?

antonioribeiro commented 10 years ago

Was a typo. I'm actually editing the error, to not expose application name:

This is it unedited:

removed

taylorotwell commented 10 years ago

Are you able to paste the real, unedited bindings as well, and an unedited command file?

antonioribeiro commented 10 years ago

full bindings:

removed

taylorotwell commented 10 years ago

Where do these files live? What is the file structure like? What is your composer.json file?

antonioribeiro commented 10 years ago

And full artisan.php

removed

antonioribeiro commented 10 years ago

This is the controller that works fine:

<? namespace ConsultorioDigital\Controllers;

use Controller;
use Redirect;
use ConsultorioDigital\Repositories\DataRepositoryInterface;

class FirewallController extends BaseController {

    private $dataRepository;

    public function __construct(DataRepositoryInterface $dataRepository)
    {
        $this->dataRepository = $dataRepository;
    }

    public function whitelist($ip)
    {   
        return Redirect::to('/')->withMessages(
                                                $this->
                                                dataRepository->
                                                firewall->
                                                addToWhitelist($ip)->
                                                getMessages()
                                            );
    }

}
taylorotwell commented 10 years ago

Hmm, I totally confused as to why this wouldn't be working then. Can you set a debug statement to make sure your binding is registered?

antonioribeiro commented 10 years ago

Another strange thing that happens in the process, looks like it finds the dependency, but just prints it out in the terminal:

http://puu.sh/5FzUf.png

taylorotwell commented 10 years ago

The top of that file has no php... just <?

taylorotwell commented 10 years ago

Can you paste that whole interface file?

antonioribeiro commented 10 years ago

Gosh, that was dumb. It was just a missing php after <?.

That one and anoter 10 other files where I just copied and pasted the namespace...

But why was that working in the first place?

Sorry.

taylorotwell commented 10 years ago

No prob.