5

I am having an issue trying to debug my code, as far as I can see looking at the various bits of code, it all links up correctly, but there must be something obvious I am missing here.

I am sorry about the amount of code I've pasted in to the question here, but unfortunately there are a lot of files in play for a single entity of the application, and I thought it better to provide more rather than less.

First of all the error message:

Argument 1 passed to Raid\Composers\PreferenceDataComposer::__construct() must be an instance of Raid\Repo\User\PreferenceInterface, instance of Raid\Repo\Preference\CacheDecorator given, called in C:\wamp\www\raid\app\Raid\Composers\ComposerServiceProvider.php on line 34 and defined

So first of all, my view composer which is where this error is being generated:

<?php namespace Raid\Composers;

use Raid\Repo\User\PreferenceInterface;

class PreferenceDataComposer {

    protected $preference;

    public function __construct(PreferenceInterface $preference)
    {
        $this->preference = $preference;
    }

    public function compose($view)
    {       
        $view->with('preferences', $this->preference->getActive());
    }

}

and then the service provider for the composer:

<?php namespace Raid\Composers;

use Illuminate\Support\ServiceProvider;

class ComposerServiceProvider extends ServiceProvider {

    public function register()
    {
        $this->app->bind('Raid\Composers\PreferenceDataComposer', function($app)
        {
            return new PreferenceDataComposer(
                $this->app->make('Raid\Repo\Preference\PreferenceInterface')
            );
        });
    }

    public function boot()
    {
        $this->app->view->composer('account.preferences', 'Raid\Composers\PreferenceDataComposer');
    }

}

Next up is the interface:

<?php namespace Raid\Repo\Preference;

interface PreferenceInterface {

    public function getActive();

}

And the CacheDecorator:

<?php namespace Raid\Repo\Preference;

use Raid\Service\Cache\CacheInterface;

class CacheDecorator extends AbstractPreferenceDecorator implements PreferenceInterface {

    protected $cache;

    public function __construct(PreferenceInterface $preference, CacheInterface $cache)
    {
        parent::__construct($preference);
        $this->cache = $cache;
    }

    public function getActive()
    {
        $key = md5('active');

        if ($this->cache->has($key)) {
            return $this->cache->get($key);
        }

        $preferences = $this->preference->getActive();

        $this->cache->put($key, $preferences);

        return $preferences;
    }
}

and the abstract decorator:

<?php namespace Raid\Repo\Preference;

abstract class AbstractPreferenceDecorator implements PreferenceInterface {

    protected $preference;

    public function __construct(PreferenceInterface $preference)
    {
        $this->preference = $preference;
    }

}

then we have the repository:

<?php namespace Raid\Repo\Preference;

use Raid\Repo\AbstractRepo;
use Illuminate\Database\Eloquent\Model;
use Raid\Service\Log\LogInterface;
use Raid\Service\Email\EmailInterface;

class EloquentPreference extends AbstractRepo implements PreferenceInterface {

    protected $preference;
    protected $preferenceType;
    protected $log;
    protected $email;

    public function __construct(Model $preference, Model $preferenceType, LogInterface $log, EmailInterface $email)
    {
        $this->preference = $preference;
        $this->preferenceType = $preferenceType;
        $this->log = $log;
        $this->email = $email;
    }

    public function getActive()
    {
        return $this->preference->whereActive()->get();
    }

}

and then the eloquent Model itself:

<?php

class Preference extends Eloquent {

    protected $table = 'preferences';
    protected $guarded = array('id');
    protected $softDelete = true;

    public function scopeWhereActive($query)
    {
        return $query->where('active', '=', '1');
    }

}

and then the service provider that binds the interface and the repo:

<?php namespace Raid\Repo;

use Preference;
use PreferenceType;
use Raid\Service\Cache\FileCache;
use Raid\Repo\Preference\CacheDecorator as PreferenceCacheDecorator;
use Raid\Repo\Preference\EloquentPreference;
use Illuminate\Support\ServiceProvider;

class RepoServiceProvider extends ServiceProvider {

    public function register()
    {
        $app = $this->app;

        $app->bind('Raid\Repo\Preference\PreferenceInterface', function($app)
        {
            $preference = new EloquentPreference(
                new Preference, 
                new PreferenceType,
                $app->make('Raid\Service\Log\LogInterface'),
                $app->make('Raid\Service\Email\EmailInterface')
            );

            return new PreferenceCacheDecorator(
                $preference, 
                new FileCache($app['cache'], 'preferences', 1440)
            );
        });
    }

}

In the code above, you can see in the Composer, that I ask for an instance of the Interface, and in the composer's service provider, I resolve an instance of it out of the IoC.

In the repo service provider I bind the interface by making a instance of the repo (passing in its dependencies), and then return the repo wrapped with a cache decorator. All of the repo, the decorator, the abstract decorator implement the interface, so I'm not sure how it is being resolved as not being an instance of the interface?

Any help you are able to give with debugging would be me wonderful.

If you need further code, please shout.

Mortelugo
  • 73
  • 1
  • 4
  • which is `Raid\Composers\ComposerServiceProvider.php on line 34` ? – egig Apr 30 '14 at 10:03
  • it is the second block of code in the question, line 34 is the line which returns the new PreferenceDataComposer: `return new PreferenceDataComposer($this->app->make('Raid\Repo\Preference\PreferenceInterface'));` – Mortelugo Apr 30 '14 at 10:21
  • @egig (forgot to tag you before sorry). Any other data/code I can provide which might help shed some light on this? Really has me stumped – Mortelugo Apr 30 '14 at 13:01
  • 1
    It seems your namespaces are wrong somewhere - you require `Raid\Repo\User\PreferenceInterface` in the constructor, while you bind `Raid\Repo\Preference\PreferenceInterface`. – Jarek Tkaczyk Apr 30 '14 at 13:23

2 Answers2

2

Found the issue at long last - thanks to @rizqi on #laravel, on my view composer, I'm using the wrong namespace:

use Raid\Repo\User\PreferenceInterface;

should be

use Raid\Repo\Preference\PreferenceInterface;
Mortelugo
  • 73
  • 1
  • 4
2

Your problem might be in Raid\Repo\User\PreferenceInterface, which should be Raid\Repo\Preference\PreferenceInterface.

Other than that I can't really see a problem in your code, to test I created some namespaces, interfaces and classes but PreferenceDataComposer instantiated with no problems for me.

In my routes.php I created one route to instantiate it, create eloquent based classes, some needed bindings, manually register Service Providers and load the namespaced file:

<?php

class Preference extends Eloquent {

    protected $table = 'preferences';
    protected $guarded = array('id');
    protected $softDelete = true;

    public function scopeWhereActive($query)
    {
        return $query->where('active', '=', '1');
    }

}

class PreferenceType extends Eloquent {

    protected $table = 'preferences';
    protected $guarded = array('id');
    protected $softDelete = true;

    public function scopeWhereActive($query)
    {
        return $query->where('active', '=', '1');
    }

}

App::bind('Raid\Service\Log\LogInterface', 'Raid\Service\Log\Log');
App::bind('Raid\Service\Email\EmailInterface', 'Raid\Service\Email\Email');
App::bind('Raid\Service\Cache\CacheInterface', 'Raid\Service\Cache\FileCache');

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

Route::any('test', function() {

    $repo = new Raid\Repo\RepoServiceProvider(App::make('app'));
    $repo->register();

    $composer = new Raid\Composers\ComposerServiceProvider(App::make('app'));
    $composer->register();

    $preference = App::make('Raid\Composers\PreferenceDataComposer');

    // This is it instantiated

    dd($preference);

});

I created a Mortelugo.php file with all your namespaces, but I had to create some missing ones and change one of them that was named incorrectly:

<?php

namespace Raid\Composers {

    use Raid\Repo\Preference\PreferenceInterface;

    class PreferenceDataComposer {

        protected $preference;

        public function __construct(PreferenceInterface $preference)
        {
            $this->preference = $preference;
        }

        public function compose($view)
        {       
            $view->with('preferences', $this->preference->getActive());
        }

    }

}

namespace Raid\Composers {

    use Illuminate\Support\ServiceProvider;

    class ComposerServiceProvider extends ServiceProvider {

        public function register()
        {
            $this->app->bind('Raid\Composers\PreferenceDataComposer', function($app)
            {
                return new PreferenceDataComposer(
                    $this->app->make('Raid\Repo\Preference\PreferenceInterface')
                );
            });
        }

        public function boot()
        {
            $this->app->view->composer('account.preferences', 'Raid\Composers\PreferenceDataComposer');
        }

    }

}

namespace Raid\Repo {

    use Preference;
    use PreferenceType;
    use Raid\Service\Cache\FileCache;
    use Raid\Repo\Preference\CacheDecorator as PreferenceCacheDecorator;
    use Raid\Repo\Preference\EloquentPreference;
    use Illuminate\Support\ServiceProvider;

    abstract class AbstractRepo {

    }

    class RepoServiceProvider extends ServiceProvider {

        public function register()
        {
            $app = $this->app;

            $app->bind('Raid\Repo\Preference\PreferenceInterface', function($app)
            {
                $preference = new EloquentPreference(
                    new Preference, 
                    new PreferenceType,
                    $app->make('Raid\Service\Log\LogInterface'),
                    $app->make('Raid\Service\Email\EmailInterface')
                );

                return new PreferenceCacheDecorator(
                    $preference, 
                    new FileCache($app['cache'], 'preferences', 1440)
                );
            });
        }

    }

}

namespace Raid\Repo\Preference {

    interface PreferenceInterface {

        public function getActive();

    }

    use Raid\Service\Cache\CacheInterface;

    abstract class AbstractPreferenceDecorator implements PreferenceInterface {

        protected $preference;

        public function __construct(PreferenceInterface $preference)
        {
            $this->preference = $preference;
        }

    }


    class CacheDecorator extends AbstractPreferenceDecorator implements PreferenceInterface {

        protected $cache;

        public function __construct(PreferenceInterface $preference, CacheInterface $cache)
        {
            parent::__construct($preference);
            $this->cache = $cache;
        }

        public function getActive()
        {
            $key = md5('active');

            if ($this->cache->has($key)) {
                return $this->cache->get($key);
            }

            $preferences = $this->preference->getActive();

            $this->cache->put($key, $preferences);

            return $preferences;
        }
    }

    use Raid\Repo\AbstractRepo;
    use Illuminate\Database\Eloquent\Model;
    use Raid\Service\Log\LogInterface;
    use Raid\Service\Email\EmailInterface;

    class EloquentPreference extends AbstractRepo implements PreferenceInterface {

        protected $preference;
        protected $preferenceType;
        protected $log;
        protected $email;

        public function __construct(Model $preference, Model $preferenceType, LogInterface $log, EmailInterface $email)
        {
            $this->preference = $preference;
            $this->preferenceType = $preferenceType;
            $this->log = $log;
            $this->email = $email;
        }

        public function getActive()
        {
            return $this->preference->whereActive()->get();
        }

    }

}

namespace Raid\Service\Log {

    interface LogInterface {

    }

    class Log implements LogInterface {

    }

}

namespace Raid\Service\Email {

    interface EmailInterface {

    }

    class Email implements EmailInterface {

    }

}

namespace Raid\Service\Cache {

    interface CacheInterface {

    }

    class FileCache implements CacheInterface {

    }

}
Antonio Carlos Ribeiro
  • 86,191
  • 22
  • 213
  • 204
  • 1
    Indeed, that is the issue, the incorrect namespace. I should really switch to an IDE so that stuff like that gets pointed out for me automatically! – Mortelugo May 01 '14 at 17:23
  • I'm currently enjoying PHPStorm 8 (beta), really helps with this sort of mistakes and does a lot more, writes most of your boilerplate code for you and helps you refactor. – Antonio Carlos Ribeiro May 01 '14 at 17:26