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.
Related
I know there are so many answer, but I cannot really solve this.
I did follow this answer (How to make a REST API first web application in Laravel) to create a Repository/Gateway Pattern on Laravel 5.7
I have also the "project" on github, if someone really kindly want test/clone/see : https://github.com/sineverba/domotic-panel/tree/development (development branch)
App\Interfaces\LanInterface
<?php
/**
* Interface for LAN models operation.
*/
namespace App\Interfaces;
interface LanInterface
{
public function getAll();
}
App\Providers\ServiceProvider
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Schema;
class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
/**
* Solve the "Key too long" issue
*
* #see https://laravel-news.com/laravel-5-4-key-too-long-error
*/
Schema::defaultStringLength(191);
}
/**
* Register any application services.
*
* #return void
*/
public function register()
{
$this->app->register(RepositoryServiceProvider::class);
}
}
App\Providers\RepositoryServiceProvider
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class RepositoryServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->bind(
'app\Interfaces\LanInterface', // Interface
'app\Repositories\LanRepository' // Eloquent
);
}
}
App\Gateways\LanGateway
<?php
/**
* The gateway talks with Repository
*/
namespace App\Gateways;
use App\Interfaces\LanInterface;
class LanGateway
{
protected $lan_interface;
public function __construct(LanInterface $lan_interface) {
$this->lan_interface = $lan_interface;
}
public function getAll()
{
return $this->lan_interface->getAll();
}
}
App\Repositories\LanRepository
<?php
/**
* Repository for LAN object.
* PRG paradigma, instead of "User"-like class Model
*/
namespace App\Repositories;
use App\Interfaces\LanInterface;
use Illuminate\Database\Eloquent\Model;
class LanRepository extends Model implements LanInterface
{
protected $table = "lans";
public function getAll()
{
return 'bla';
}
}
I did add also App\Providers\RepositoryServiceProvider::class, in providers section of config\app.php
This is finally the controller (I know that it is not complete):
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Gateways\LanGateway;
class LanController extends Controller
{
private $lan_gateway;
/**
* Use the middleware
*
* #return void
*/
public function __construct(LanGateway $lan_gateway)
{
$this->middleware('auth');
$this->lan_gateway = $lan_gateway;
}
/**
* Display a listing of the resource.
*
* #return \Illuminate\Contracts\Support\Renderable
*/
public function index()
{
$this->lan_gateway->getAll();
return view('v110.pages.lan');
}
}
And the error that I get is
Target [App\Interfaces\LanInterface] is not instantiable while building [App\Http\Controllers\LanController, App\Gateways\LanGateway].
I did try:
php artisan config:clear
php artisan clear-compiled
I think #nakov might be right about it being case-sensitive. I don't believe PHP itself cares about upper/lowercase namespaces, but the composer autoloader and the Laravel container use key->value array keys, which do have case-sensitive keys, to bind and retrieve classes from the container.
To ensure the names always match, try using the special ::class constant instead, like this:
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use App\Repositories\LanRepository;
use App\Interfaces\LanInterface;
class RepositoryServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->bind(
LanInterface::class,
LanRepository::class
);
}
}
In my case i forgot to enlist the provider to confit/app.php that's why the error.
Clear the old boostrap/cache/compiled.php:
php artisan clear-compiled
Recreate boostrap/cache/compiled.php:
php artisan optimize
In my views i am extending a default blade template which acts as my Master Template. I have a ViewComposer setup which serves this template with a number of variables.
I have come to a situation where i need to access one of these variables within my index.blade.php which is the page initiating the #extends function.
Do the variable passed via the ViewComposer reach the scope of the initial view? Or will i need to create another ViewComposer to pass the same variable.
ViewComposer
<?php
namespace App\Http\ViewComposers;
use Illuminate\View\View;
use Illuminate\Http\Request;
use App\Repositories\UserRepository;
use Sentinel;
use App\ProjectUsers;
class MasterComposer
{
/**
* The user repository implementation.
*
* #var UserRepository
*/
protected $users;
private $request;
/**
* Create a new profile composer.
*
* #param UserRepository $users
* #return void
*/
public function __construct(Request $request)
{
$this->request = $request;
// Dependencies automatically resolved by service container...
$uid = Sentinel::getUser()->id;
$this->users = ProjectUsers::where("user_id", '=', $uid)->get();
}
/**
* Bind data to the view.
*
* #param View $view
* #return void
*/
public function compose(View $view)
{
$view->with('projects', $this->users);
$view->with('activeProject', $this->request->session()->get("activeProject"));
}
}
ComposerServiceProvider
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class ComposerServiceProvider extends ServiceProvider {
/**
* Register bindings in the container.
*
* #return void
*/
public function boot() {
// Using class based composers...
view ()->composer ( 'admin/layouts/default', 'App\Http\ViewComposers\MasterComposer' );
}
/**
* Register the service provider.
*
* #return void
*/
public function register() {
//
}
}
index.blade.php
#extends('admin/layouts/default')
{{ $activeProject }}
This ultimately give me an undefined variable error.
Undefined variable: activeProject (View: /home/laravel/public_html/base/resources/views/admin/index.blade.php)
Yes, all variables which are available in the master layout will be passed to any of its children.
Since you're using #extends in your content layout you can use this
#extends('admin/layouts/default', ['activeProject' => $activeProject])
If this doesn't work you might need to pass it through your controller
I am quite new to Laravel and I really need some help. I need to create a simple app for my job, and I think I will not have problem with this as the tutorials here are really excellent.
The issue I have is that for that project I need to authenticate the users against an external DB using a SOAP webservice and if the user does not exist in the local DB I create it and log the user in. I am able to manage this part as I have already written a Joomla plugin that does that.
I have tried to figure out the documentation on how to create a custom driver. http://laravel.com/docs/5.1/authentication I thought that at first I would replicate the EloquentUserProvider befor modifying it, thus I created:
ErsAuthServiceProvider and ErsUserProvider respectively placed in App\Providers and App\Extensions
But it mysteriously does not work... I get the following error:
ErrorException in ErsUserProvider.php line 33: Argument 1 passed to App\Extensions\ErsUserProvider::__construct() must be an instance of Illuminate\Contracts\Hashing\Hasher, none given, called in /home/vagrant/Code/ERSTools/app/Providers/ErsAuthServiceProvider.php on line 31 and defined
Actually I do not understand much in the documentation what they are doing with the boot() method in the example. I understand that they extend The Auth class in order to add the new driver (ers in my case) but I do not get why they pass the $app['riak.connection']
<?php
namespace App\Providers;
use Auth;
use App\Extensions\ErsUserProvider;
use Illuminate\Contracts\Auth\Access\Gate as GateContract;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
class ErsAuthServiceProvider extends ServiceProvider
{
protected $policies = [
'App\Model' => 'App\Policies\ModelPolicy',
];
/**
* Register any application authentication / authorization services.
*
* #param \Illuminate\Contracts\Auth\Access\Gate $gate
* #return void
*/
public function boot(GateContract $gate)
{
parent::registerPolicies($gate);
Auth::extend('ers', function($app) {
// Return an instance of Illuminate\Contracts\Auth\UserProvider...
return new ErsUserProvider;
});
//
}
/**
* Register the application services.
*
* #return void
*/
public function register()
{
//
}
}
and
<?php
namespace App\Extensions;
use Illuminate\Support\Str;
use Illuminate\Contracts\Auth\UserProvider;
use Illuminate\Contracts\Hashing\Hasher as HasherContract;
use Illuminate\Contracts\Auth\Authenticatable as UserContract;
class ErsUserProvider implements UserProvider
{
/**
* The hasher implementation.
*
* #var \Illuminate\Contracts\Hashing\Hasher
*/
protected $hasher;
/**
* The Eloquent user model.
*
* #var string
*/
protected $model;
/**
* Create a new database user provider.
*
* #param \Illuminate\Contracts\Hashing\Hasher $hasher
* #param string $model
* #return void
*/
public function __construct(HasherContract $hasher, $model)
{
$this->model = $model;
$this->hasher = $hasher;
}
... the rest is similar to the original file (EloquentUserProvider)
Finally, my plan is to keep the ErsUserprovider quite similar to the EloquentUserProvider and to implement my check with the webservice in the validateCredentials() method as in this method I shoul know if a user exists with the requested username in the local DB, I will know if the user passes validation with the SOAP webservice I can then
Login the user
Login the user and create a new user based on the date returned by the webservice
refuse the login.
Is this a good plan?
I sweated but I made the first part work. The issue was within the boot method.My custom provider is a working replica of the original laravel 5.1 I can now customize it.
Here is the Service provider that works:
<?php
namespace App\Providers;
use App\Extensions\ErsUserProvider;
use Illuminate\Support\ServiceProvider;
use Illuminate\Contracts\Auth\UserProvider;
class ErsAuthServiceProvider extends ServiceProvider
{
/**
* Bootstrap the application services.
*
* #return void
*/
public function boot()
{
$this->app['auth']->extend('ers',function($app)
{
$model = $app['config']['auth.model'];
return new ErsUserProvider($app['hash'], $model);
});
}
/**
* Register the application services.
*
* #return void
*/
public function register()
{
//
}
}
I'm building a Laravel project and in one of the controllers I'm injecting two dependencies in a method:
public function pusherAuth(Request $request, ChannelAuth $channelAuth) { ... }
My question is really simple: How do I pass parameters to the $channelAuth dependency?
At the moment I'm using some setters to pass the needed dependencies:
public function pusherAuth(Request $request, ChannelAuth $channelAuth)
{
$channelAuth
->setChannel($request->input('channel'))
->setUser(Auth::user());
What are the alternatives to this approach?
P.S. The code needs to be testable.
Thanks to the help I received on this Laracast discussion I was able to answer this question. Using a service provider it's possible to initialize the dependency by passing the right parameters to the constructor. This is the service provider I created:
<?php namespace App\Providers;
use Security\ChannelAuth;
use Illuminate\Contracts\Auth\Guard;
use Illuminate\Http\Request;
use Illuminate\Support\ServiceProvider;
class ChannelAuthServiceProvider extends ServiceProvider {
/**
* Bootstrap the application services.
*
* #return void
*/
public function boot()
{
//
}
/**
* Register the application services.
*
* #return void
*/
public function register()
{
$this->app->bind('Bloom\Security\ChannelAuthInterface', function()
{
$request = $this->app->make(Request::class);
$guard = $this->app->make(Guard::class);
return new ChannelAuth($request->input('channel_name'), $guard->user());
});
}
}
You can pass parameters (as a string indexed array) when resolving a dependence like this:
<?php namespace App\Providers;
use Security\ChannelAuth;
use Illuminate\Contracts\Auth\Guard;
use Illuminate\Support\ServiceProvider;
class ChannelAuthServiceProvider extends ServiceProvider {
/**
* Bootstrap the application services.
*
* #return void
*/
public function boot()
{
//
}
/**
* Register the application services.
*
* #return void
*/
public function register()
{
$this->app->bind('Bloom\Security\ChannelAuthInterface', function($params)
{
$channelName = $params['channelName'];
$guard = $this->app->make(Guard::class);
return new ChannelAuth($channelName, $guard->user());
});
}
}
Then when resolving eg in a controller:
public function pusherAuth()
{
$channelAuth = app()->makeWith('Bloom\Security\ChannelAuthInterface', [
'channelName' => $request->input('channel_name')
]);
// ... use $channelAuth ...
}
You can create and register your own service provider and create object with constructor's requests parameters.
I don't know how to do this in Laravel, but in Symfony2 you can inject in your own service something like RequestStack. It's the best way, because you have small service providers that are fully testable.
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