I am new to this concept of DI, and IoC so i might be doing this completely wrong but i am trying to inject the Model that matches a controller into that controllers constructor (UserModel -> UsersController) so that i can mock it later on.
So my model looks like:
use Illuminate\Auth\UserInterface;
class User extends Eloquent implements UserInterface {
public function getAuthIdentifier()
{
return $this->getKey();
}
public function getAuthPassword()
{
return $this->password;
}
}
And i am then trying to inject in UsersController like so :
class UsersController extends Controller {
protected $user;
public function __construct(User $user)
{
$this->user = $user;
}
public function index()
{
//dd( $this->user);
$users = $this->user->all();
foreach ( $users as $user )
print_r($user);
return;
}
}
Then when i hit this controller in the browser i get a "Unresolvable dependency resolving" error.
I noticed that this happend only when the class that i am trying to inject is a sub class of eloquent, if i try the same code with a custom class that do not extend eloquent then it works fine.
Am i missing something?
Further to the comments, I finally got to know that this is a complicated issue. To bypass this you need to bind your model with the IoC and return a new instance of your model manually.
App::bind('User', function()
{
return new User;
});
Related
I have made a UserRepository and implemented interface with methods it should hold. After that I have registered it within my service provider which is also registered in app.php.
class UserRepository extends AbstractUserRepository implements UserRepositoryInterface
{
public function __construct(User $user = null)
{
$this->model = $user ?: $this->getAuthenticatedUser();
}
...
}
UserRepository extends AbstractUserRepository which extends EloquentRepository which is supposed to abstract some generic eloquent actions.
EloquentRepository has a protected member model and its getter getModel().
Now the issue I have is that the initialization doesn't seem to work as it should. After I log in and dump this from the test route:
Route::get('test', function () {
$repo = new \Account\Repository\UserRepository();
return $repo->getModel();
});
I am getting back the authenticated user.
However if I use DI to do the same thing, I am getting an error:
use Account\Contracts\UserRepositoryInterface as UserRepository;
private $userRepository;
public function __construct(UserRepository $userRepository)
{
$this->userRepository = $userRepository;
}
And then do a dump in the controller method
return $this->userRepository->getModel();
I am getting an error.
Specifically, it seems as if it is trying to initialize User model, but fails because user isn't actually forwarded
EDIT all bindings:
$this->app->bind('User', User::class);
$this->app->bind('UserRepository', UserRepository::class);
$this->app->bind(UserRepositoryInterface::class, UserRepository::class);
$this->app->bind('AbstractUserRepository', AbstractUserRepository::class);
$this->app->bind(AbstractUserRepositoryInterface::class, AbstractUserRepository::class);
public function provides()
{
return [
'User',
'UserRepository',
UserRepositoryInterface::class,
AbstractUserRepositoryInterface::class,
'AbstractUserRepository',
I am following this link to implement it
I did below steps to implement the Contract in my existing class.
Below is the class where I will write some logic also before sending it to controller
namespace App\Classes\BusinessLogic\Role;
use App\Classes\DatabaseLayer\Role\RoleDb;
use App\Classes\Contract\Role\IRole;
class RoleBL implements IRole {
public function All() {
return (new RoleDb())->All();
}
}
Database Function
namespace App\Classes\DatabaseLayer\Role;
class RoleDb {
public function All() {
$Roles = \App\Models\Role\RoleModel
::all();
return $Roles;
}
}
Interface
namespace App\Classes\Contract\Role;
interface IRole {
public function All();
}
Service Provider class
namespace App\Providers\Role;
class RoleServiceProvider extends \Illuminate\Support\ServiceProvider {
public function register()
{
$this->app->bind('App\Classes\Contract\Role\IRole', function($app){
return new \App\Classes\BusinessLogic\Role\RoleBL($app['HttpClient']);
});
}
}
Finally in config/app.php in provider wrote below line.
App\Providers\Role\RoleServiceProvider::class
Controller - Constructor
protected $roles;
public function __construct(\App\Classes\Contract\Role\IRole $_roles) {
parent::__construct();
$roles = $_roles;
}
Controller Action method
public function index(IRole $roles) {
$RoleTypes = $roles->All();
}
So far everything works fine if I keep Interface as parameter in method.
if I try to use the variable $roles in index method and remove the variable, it is always null.
Please guide me if I missed anything?
You incorrectly assign the $roles property in your __construct() method.
Replace
$roles = $_roles;
with
$this->roles = $_roles;
and then in your index method do:
$RoleTypes = $this->roles->All();
I'm writing a new project with laravel 5.1, and I want to use the repository pattern, but I can't figure out what is the best way of doing that.
I was thinking about:
public function save(User $user)
{
$user->save();
}
public function find($id)
{
return User::find($id);
}
And then
$user = new User();
$user->email = 'foo#bar.com';
$userRepo->save($user);
That way I work with the model as DTO, and it's super easy and comfortable, but then I will be depend on Eloquent.
So I was thinking of using an array instead of model, like that:
public function save(array $user)
{
User::save($user);
}
public function find($id)
{
return User::find($id)->toArray();
}
But then it will be much less comfortable to use.
Can you explain me what is the best way of using repository in Laravel so I will be able to change data source easily in the future, but it will still be comfortable to use this pattern?
I have it set up as follows, using your example:
<?php namespace Repositories;
use Models\User;
class UserEloquentRespository implements UserInterface {
protected $user;
public function __construct(User $user)
{
$this->user = $user;
}
public function create($input)
{
$this->user->create($input);
}
}
Then in my controller
Laravel 4
<?php namespace Controllers;
use Repositories\UserInterface as User;
class UsersController extends \BaseController {
protected $user;
public function __construct(User $user)
{
$this->user = $user;
}
public function store()
{
$input = \Input::all();
// validation here
// now create your user
$user = $this->user->create($input);
if ($user) {
// redirect or do whatever you do on successful user creations
}
// Here you can do whatever you do if a user wasn't created for whatever reason
}
}
Laravel 5
<?php namespace App\Http\Controllers;
use Repositories\UserInterface as User;
use App\Http\Requests\UserRequestForm;
use App\Http\Controllers\Controller;
class UsersController extends Controller {
protected $user;
public function __construct(User $user)
{
$this->user = $user;
}
public function store(UserRequestForm $request)
{
// Form request validates in middleware
// now create your user
$user = $this->user->create($request->input());
if ($user) {
// redirect or do whatever you do on successful user creations
}
// Here you can do whatever you do if a user wasn't created for whatever reason
}
}
Lastly, don't forget to bind your interface to your eloquent repository as a service provider.
App::bind(
'Repositories\UserRepositoryInterface',
'Repositories\Eloquent\UserEloquentRepository'
);
Now, whenever you need to change your implementation just change the binding to whatever new class implements your interface.
I am working on a Task Management App. In App there is a User Model and there is Project and Task models.
In order for user to add a Project and related Task, all I would do at Model Level is:
class Project extends Model
{
public function add($user_id,$task_details)
{
//Add Project Meta
$this->title = "Project Title";
$this->description "Desc"
$this->save()
for($t=0;$t<count($task_details);$t++) {
//Add Task Details
$task = new Task();
$task->title = $task_details["title"];
$task->description = $task_details["description"];
$task->save();
}
}
}
It looks clumsy to me. How can I improve this in Laravel 5? How can I make my modules more atomic?
Yeah it is clumsy. You should use Repository pattern so that there is no such type of multiple responsibilities.
And Eloquent already has a create method like findorCreate or just create method.
Here is simple example for UserRepository.
//UserRepository
<?php namespace App\Repository\User;
use App\User;
class UserRepository{
public $model;
public function __construct(User $userModel) // type hinting the User Model
{
$this->model=$userModel;
}
public function create($inputs)
{
return $this->model->create($inputs);
}
}
// UserController
<?php namespace App\Http\Controllers;
use \App\Repository\User\UserRepository;
class UserController extends Controller{
public $userRepo;
public function __construct(UserRepository $userRepository) //type hinting the userRepository Class
{
$this->userRepo=$userRepository;
}
public function getUser($id)
{
return $this->userRepo->model->findorfail($id);
}
public function getCreate()
{
if($this->userRepo->create(Input::all())
return view('success');
return Redirect->back()->withErrors();
}
}
I'm developing a package for Laravel and I'm getting an error which I can't figure out how to fix:
Argument 1 passed to Cartalini\Drayman\Drayman::__construct() must be an instance of Cartalini\Drayman\Repositories\UserRepositoryInterface, none given, called in /Applications/MAMP/htdocs/l4/app/controllers/HomeController.php on line 10 and defined
Here's my code...
namespace Cartalini\Drayman;
use Cartalini\Drayman\Repositories\UserRepositoryInterface;
class Drayman
{
protected $user;
public function __construct(UserRepositoryInterface $user)
{
$this->user = $user;
}
public function deliverBeer()
{
return $this->user->all();
}
}
UserRepository...
namespace Cartalini\Drayman\Repositories;
class UserRepository implements UserRepositoryInterface
{
public function all()
{
return User::all();
}
}
UserRepositoryInterface...
namespace Cartalini\Drayman\Repositories;
interface UserRepositoryInterface
{
public function all();
}
Service provider...
public function register()
{
$this->app->bind('Cartalini\Drayman\Repositories\UserRepositoryInterface', 'Cartalini\Drayman\Repositories\UserRepository');
}
And finally my controller...
use Cartalini\Drayman\Drayman as Drayman;
class HomeController extends BaseController
{
public function showWelcome()
{
$drayman = new Drayman;
return $drayman->deliverBeer();
}
}
Can anyone help me to debug this please?
In your showWelcome function:
public function showWelcome()
{
// need to pass a UserRepositoryInterface object here:
$drayman = new Drayman;
return $drayman->deliverBeer();
}
Since you did not pass a UserRepositoryInterface object that your code requires you get that error.
it might be a to late, but i had the same problem and the reason was my concrete class didn't implement it's corresponding interface class. after implementing it, all went well.
although you are correctly implementing it, so this error might have a few reason, which one of them is what i described.