How do I solve "Target [Interface] is not instantiable" in Laravel 4? - php

My error message:
Illuminate \ Container \ BindingResolutionException
Target [Project\Backend\Service\Validation\ValidableInterface] is not instantiable.
I understand that interfaces and abstract classes are not instantiable so I know that Laravel should not be trying to instantiate my interface. Yet somehow it's trying to and I suspect this may be a binding issue...even though I believe I have bound it correctly and have registered it as a service provider.
I should mention that I have taken this example out of Chris Fidao's "Implementing Laravel" and it's almost identical!
This is the first couple of lines of my form class:
namespace Project\Backend\Service\Form\Job;
use Project\Backend\Service\Validation\ValidableInterface;
use Project\Backend\Repo\Job\JobInterface;
class JobForm {
/**
* Form Data
*
* #var array
*/
protected $data;
/**
* Validator
*
* #var \Project\Backend\Form\Service\ValidableInterface
*/
protected $validator;
/**
* Job repository
*
* #var \Project\Backend\Repo\Job\JobInterface
*/
protected $job;
public function __construct(ValidableInterface $validator, JobInterface $job)
{
$this->validator = $validator;
$this->job = $job;
}
This is the first few lines of my validator class:
namespace Project\Backend\Service\Form\Job;
use Project\Backend\Service\Validation\AbstractLaravelValidator;
class JobFormValidator extends AbstractLaravelValidator {
// Includes some validation rules
This is the abstract validator:
namespace Project\Backend\Service\Validation;
use Illuminate\Validation\Factory;
abstract class AbstractLaravelValidator implements ValidableInterface {
/**
* Validator
*
* #var \Illuminate\Validation\Factory
*/
protected $validator;
/**
* Validation data key => value array
*
* #var Array
*/
protected $data = array();
/**
* Validation errors
*
* #var Array
*/
protected $errors = array();
/**
* Validation rules
*
* #var Array
*/
protected $rules = array();
/**
* Custom validation messages
*
* #var Array
*/
protected $messages = array();
public function __construct(Factory $validator)
{
$this->validator = $validator;
}
This is the code where I bind it all to the app:
namespace Project\Backend\Service\Validation;
use Illuminate\Support\ServiceProvider;
use Project\Backend\Service\Form\Job\JobFormValidator;
class ValidationServiceProvider extends ServiceProvider {
public function register()
{
$app = $this->app;
$app->bind('Project\Backend\Service\Form\Job\JobFormValidator', function($app)
{
return new JobFormValidator($app['validator']);
});
}
}
This is then registered in app/config/app.php:
.....
'Project\Backend\Service\Validation\ValidationServiceProvider',
....
Finally these are the first few lines of my controller:
use Project\Backend\Repo\Job\JobInterface;
use Project\Backend\Service\Form\Job\JobForm;
class JobController extends \BaseController {
protected $jobform;
function __construct(JobInterface $job, JobForm $jobform)
{
$this->job = $job;
$this->jobform = $jobform;
}

You need to tell Laravel which instance it should use for a certain interface when injecting it into the constructor via type hinting.
You do this using the bind() method (in your service provider for example)
$app->bind('JobInterface', 'Job'); // Job being the class you want to be used
I highly recommend you watch the video here where Taylor Otwell, the creator of Laravel, explains this and some other things.

First you need to bind using
/app/Providers/AppServiceProvider.php
<?php namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider {
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
//
}
/**
* Register any application services.
*
* #return void
*/
public function register()
{
//
$this->app->bind('JobInterface', 'Job');
}
}
Once you complete this change
Run composer update

Related

Laravel How to Test Static Query Builder Methods?

I have the following single responsibility repository class
<?php
namespace App\Launches\Repositories\Customer;
use App\Launches\Models\Customer\Subscription;
use Illuminate\Support\Collection;
final class GetSubscriptionRepository
{
/**
* #param int $productId
* #return Collection
*/
public function byProductId(int $productId): Collection
{
return Subscription::where('product_id', $productId)->get();
}
}
I want to be able to test that method, to make sure the object retrieve is the one I've asked. So I've done the following:
<?php
namespace Tests\Unit\Launches\Repository\Customer;
use App\Launches\Models\Customer\Subscription;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Collection;
use Tests\TestCase;
use App\Launches\Repositories\Customer\GetSubscriptionRepository;
class GetSubscriptionRepositoryTest extends TestCase
{
use RefreshDatabase;
/**
* #var GetSubscriptionRepository
*/
protected $getSubscriptionRepository;
/**
* #var Collection
*/
protected $subscriptionCollection;
public function setUp(): void
{
parent::setUp();
$this->getSubscriptionRepository = new GetSubscriptionRepository();
$this->subscriptionCollection = factory(Subscription::class, 20)->make();
}
/**
* #covers GetSubscriptionRepository::byProductId
*/
public function testSubscriptionIsPickedById()
{
$randomSubscription = $this->subscriptionCollection->random(1)->first()->toArray();
$pickedSubscription = $this->getSubscriptionRepository->byProductId($randomSubscription['id']);
$this->assertEquals($randomSubscription['id'], $pickedSubscription->get('id'));
}
}
It's always returning null on $this->getSubscriptionRepository->byProductId($randomSubscription['id']);
It is obviously expecting stuff to be in the database, is there a way to test it without adding stuff to the database?

Automatic login after clicking on the link with the token (jrean/laravel-user-verification)

I use the "jrean/laravel-user-verification" package. When I click on the link with the token I want to redirect in my homepage and be already logged. How can I implement this? Thank you)
Laravel: 5.4
Package Version: 4.1
Solve this problem. Add to my register function (RegisterController) event:
public function register(VerificationRequest $request)
{
...
event(new Registered($user));
...
}
Сreate listener:
<?php
namespace App\Listeners;
use Illuminate\Auth\AuthManager;
use Jrean\UserVerification\Events\UserVerified;
/**
* Class UserVerifiedListener
* #package App\Listeners
*/
class UserVerifiedListener
{
/**
* #var AuthManager
*/
private $auth;
/**
* Create the event listener.
*
* #param AuthManager $auth
*/
public function __construct(AuthManager $auth)
{
$this->auth = $auth;
}
/**
* Handle the event.
*
* #param UserVerified $event
* #return void
*/
public function handle(UserVerified $event)
{
$this->auth->guard()->login($event->user);
}
}
And register it in :
app/Providers/EventServiceProvider.php
<?php
namespace App\Providers;
use App\Listeners\UserVerifiedListener;
use Illuminate\Support\Facades\Event;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
use Jrean\UserVerification\Events\UserVerified;
class EventServiceProvider extends ServiceProvider
{
/**
* The event listener mappings for the application.
*
* #var array
*/
protected $listen = [
UserVerified::class => [
UserVerifiedListener::class
],
];
/**
* Register any events for your application.
*
* #return void
*/
public function boot()
{
parent::boot();
//
}
public function register()
{
$this->app->bind(UserVerifiedListener::class, function () {
return new UserVerifiedListener(
$this->app->make('auth')
);
});
}
}

ViewComposer Doesn't Work

I have made a header.blade.php which is extended to many View pages. in header menu items come from database.So I used ViewComposer.
Here is my ComposerServiceProvider.php
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\View;
class ComposerServiceProvider extends ServiceProvider
{
/**
* Bootstrap the application services.
*
* #return void
*/
public function boot()
{
View::composer(['cart.layouts.header'], 'App\Http\ViewComposers\CategoryComposer#compose');
}
/**
* Register the application services.
*
* #return void
*/
public function register()
{
//
}
}
here is the CategoryComposer Class:
<?php
namespace App\Http\ViewComposers;
use Illuminate\View\View;
class CategoryComposer
{
public $categoryList = [];
/**
* Create a movie composer.
*
* #return void
*/
public function __construct()
{
$this->categoryList = \DB::table('categories')
->select('categories.*')
->get();
}
/**
* Bind data to the view.
*
* #param View $view
* #return void
*/
public function compose(View $view)
{
$view->with('categories', end($this->categoryList));
}
}
I have also registered the Service Provider in config/app
But the problem is I got error in other pages like Undefined variable: categories
Can you suggest me what could be the Error here?

How to access Sylius Services from Custom Controller

I have this Controller in a fresh sylius standard App and I am trying to access some service from the container but the container is always null.
According to the Symfony Docs, all you need to make your controller container aware is extend the Controller class, as I am doing.
namespace AppBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Templating\EngineInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
class HomepageController extends Controller
{
/**
* #var EngineInterface
*/
private $templatingEngine;
/**
* #param EngineInterface $templatingEngine
*/
public function __construct(EngineInterface $templatingEngine)
{
$this->templatingEngine = $templatingEngine;
}
/**
* #param Request $request
*
* #return Response
*/
public function indexAction(Request $request)
{
dump($this->get('sylius.factory.product'));
return $this->templatingEngine->renderResponse('#App/index.html.twig');
}
}
is there any additional configuration I need to do? Any help is welcome.

Dependency inversion issue in php. (Repository Pattern)

I am implementing a repository pattern in Laravel, and it seems to be very tedious. For example, let's say I have products then I have to create a ProductRepository interface then a ProductRepository class that implements that interface, now I have some very generic methods on the ProductRepository like:
retrieveAll
store
update
delete
And now I have to do the same thing for ingredients. It would be nice if I could simply create a ModelRepository interface with all those generic methods and implement it by passing a generic data type (namely the model), something similar to Java Generics:
<?php
interface ModelRepositoryInterface<T> {
function retrieveAll(): Collection<T>;
function store(T $item);
function update(int $id, T $data);
function delete(int $id);
}
But since php doesn't support generics how can I achieve this simplicity?
You can create a RepositoryServiceProvider to bind your repository interfaces to actual classes.
You can create a abstract Repository class with retrieveAll, store, update, delete and extend your Repositories and implement the interface. I have included below example with magic functions to be able to eloquent methods if I don't have any customization.
The below is not tested but its just to get the idea.
<?php
namespace App\Repositories;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
abstract class AbstractRepository implements RepositoryInterface
{
/**
* #var Builder|Model
*/
protected $model;
/**
* #return mixed
*/
public function getModel()
{
return $this->model;
}
/**
* #param array $columns
* #return \Illuminate\Database\Eloquent\Collection|Model[]
*/
public function all($columns = ['*'])
{
return $this->model->all($columns);
}
/**
* #param $name
* #param $arguments
* #return mixed
*/
public function __call($name, $arguments)
{
return $this->model->{$name}($arguments);
}
}
OrderRepository
<?php
namespace App\Repositories;
use App\Models\Order;
use Illuminate\Support\Facades\Date;
use Illuminate\Support\Facades\DB;
class OrderRepository extends AbstractRepository implements OrderRepositoryInterface
{
/**
* OrderRepository constructor.
* #param Order $model
*/
public function __construct(Order $model)
{
$this->model = $model;
}
public function countPaid(): int
{
return $this->model->paid()->count();
}
/**
* #return int
*/
public function countReady(): int
{
return $this->model->ready()->count();
}
/**
* #return int
*/
public function countCancelled(): int
{
return $this->model->cancelled()->count();
}
}
OrderRepositoryInterface
<?php
namespace App\Repositories;
interface OrderRepositoryInterface
{
}
RepositoryServiceProvider
<?php
namespace App\Providers;
use App\Repositories\OrderRepository;
use App\Repositories\OrderRepositoryInterface;
use Illuminate\Support\ServiceProvider;
class RepositoryServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* #return void
*/
public function register()
{
$this->app->bind(OrderRepositoryInterface::class, OrderRepository::class);
}
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
//
}
}
RepositoryInterface
<?php
namespace App\Repositories;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Collection;
interface RepositoryInterface
{
function retrieveAll(): Collection;
function store(Model $item);
function update(int $id, Model $data);
function delete(int $id);
}

Categories