so i am new in Laravel.
I want to use repository pattern, and here my problem:
here is my interface:
namespace Repositories\User;
interface IUserRepository
{
public function getAllUsers();
}
here my class:
namespace Repositories\User;
use models\User;
class UserRepository implements IUserRepository
{
public function getAllUsers()
{
return User::all();
}
}
here my controller:
class UserController extends \BaseController {
protected $user;
public function __contruct(IUserRepository $user)
{
$this->user = $user;
}
/**
* Display a listing of the resource.
*
* #return Response
*/
public function index()
{
$users = $this->user->getAllUsers();
return View::make('index');
}
}
i register it in boostrap\start.php
App::bind('Repositories\User\IUserRepository', 'Repositories\User\UserRepository');
i think it can run smooth but it is a result i get :( :
Call to a member function getAllUsers() on a non-object
$users = $this->user->getAllUsers();
So why? :(( Thanks for helping!
If you infect that repo, then use namespace:
public function __contruct(Repositories\User\IUserRepository $user)
{
$this->user = $user;
}
Related
I'm new to UnitTest and trying to integrate it into my Laravel application, but I'm getting the below error:
Call to a member function findOne() on null
at app/Services/User/UserService.php:32
28▕ $this->userWebsiteRepository = $userWebsiteRepository;
29▕ }
30▕
31▕ public function findOne($data = []){
➜ 32▕ return $this->userRepository->findOne($data);
33▕ }
34▕
This is my code.
AuthController.php
class AuthController extends Controller {
private $userService;
public function __construct(UserService $userService)
{
$this->userService = $userService;
}
public function show($id){
return $this->userService->findOne(['id' => $id]);
}
}
UserService.php
class UserService
{
public $userRepository;
public function __construct(UserRepositoryInterface $userRepository)
{
$this->userRepository = $userRepository;
}
}
UserRepositoryInterface.php
interface UserRepositoryInterface
{
public function findOne($data);
}
UserRepository.php
use App\Models\User;
class UserRepository implements UserRepositoryInterface
{
private $model;
public function __construct(User $user)
{
$this->model = $user;
}
public function findOne($data)
{
if (empty($data)) return false;
$query = $this->model->with(['userWebsites', 'userWebsites.website', 'role']);
if(!empty($data['id'])) $query = $query->where('id', $data['id']);
return $query->first();
}
}
RepositoryServiceProvider.php
class RepositoryServiceProvider extends ServiceProvider
{
/**
* Register services.
*
* #return void
*/
public function register()
{
$this->app->bind(UserRepositoryInterface::class, UserRepository::class);
}
}
AuthControllerTest.php
class AuthControllerTest extends TestCase
{
public $authController;
public $userRepositoryInterfaceMockery;
public $userServiceMokery;
public function setUp(): void{
$this->afterApplicationCreated(function (){
$this->userRepositoryInterfaceMockery = Mockery::mock(UserRepositoryInterface::class)->makePartial();
$this->userServiceMokery = Mockery::mock((new UserService(
$this->app->instance(UserRepositoryInterface::class, $this->userRepositoryInterfaceMockery)
))::class)->makePartial();
$this->authController = new AuthController(
$this->app->instance(UserService::class, $this->userServiceMokery)
);
}
}
public function test_abc_function(){
$res = $this->authController->abc(1);
}
}
I was still able to instantiate the AuthController and it ran to the UserService. but it can't get the UserRepositoryInterface argument. I think the problem is that I passed the Interface in the constructor of the UserService. .What happened, please help me, thanks
I don't know where $userService comes from to your controller's constructor, but it seems like it comes from nowhere. You need to pass it as argument, so Laravel can resolve its instance in service container.
class AuthController extends Controller {
private $userService;
public function __construct(
private AuthService $authService,
UserRepositoryInterface $userRepository
) {
$this->userService = new UserService($userRepository);
}
public function show($id)
{
return $this->userService->findOne(['id' => $id]);
}
}
Also there is literally no findOne method in UserService. You need one there.
class UserService
{
public function __construct(private UserRepositoryInterface $userRepository)
{
}
public function findOne(array $data)
{
return $this->userRepository->findOne($data);
}
}
Update
In that case you need this in service provider:
$this->app->bind(UserRepositoryInterface::class, UserRepository::class);
$this->app->bind(UserService::class, function ($app) {
return new UserService($app->make(UserRepositoryInterface::class));
});
I'm mocking a Repository inside the controller, but when I call CompanyController#index (which in turn calls CompanyRepository#all), tests returns this error:
Test\Unit\Shared\Repositories\CompanyRepositoryTest::test_all
Mockery\Exception\InvalidCountException: Method all() from Mockery_0__App_Shared_Repostiries_CompanyRepository should be called
exactly 1 time but called 0 times.
<?php
namespace Test\Unit\Shared\Repositories;
use Mockery;
use Tests\TestCase;
class CompanyRepositoryTest extends TestCase
{
protected $companyRepo;
protected $company;
public function setUp(): void
{
parent::setUp();
}
public function tearDown(): void
{
parent::tearDown();
}
/**
* #group mockingrepo3
*/
public function test_all()
{
$this->companyRepo = Mockery::mock('\App\Shared\Repositories\CompanyRepository');
$this->companyRepo->shouldReceive('all')
->andReturn(new \Illuminate\Support\Collection)
->once();
$this->company = \App\Models\Company::find(3);
$this->be($this->company);
$this->app->instance('\App\Shared\Repositories\CompanyRepository', $this->companyRepo);
$response = $this->call('GET', route('app.admin.company.index'));
// $this->assertEquals(new \Illuminate\Support\Collection, $companies);
}
}
CompanyController
<?php
class CompanyController extends Controller
{
private $companyRepo;
public function __construct(CompanyRepository $companyRepo)
{
$this->companyRepo = $companyRepo;
}
public function index(Request $request)
{
$companies = $this->companyRepo->all();
return view("admin.company.index")->with(['companies' => $companies]);
}
}
In php mvc structure I have this base controller class and add the constructor like this :
namespace App\Core;
/**
* Controller class
*/
class Controller
{
/** #var View View The view object */
public $View;
public $templates;
public $app;
/**
* Construct the (base) controller. This happens when a real controller is constructed, like in
* the constructor of IndexController when it says: parent::__construct();
*/
public function __construct()
{
$this->app = \App\Core\System\App::instance();
$this->Language = new Language('en-gb');
$this->templates = new \League\Plates\Engine(Config::get('PATH_VIEW'));
$this->Url = new \App\Core\Url(Config::get('URL'),Config::get('URL'));
}
public function loadModel($name) {
$path = '\App\Catalog\Model\\'.$name;
$this->model = new $path;
return $this->model;
}
public function loadController($name) {
$path = '\App\Catalog\Controller\\'.$name;
$this->controller = new $path;
return $this->controller;
}
}
Now in action (ie edit account) controller i have :
namespace App\Catalog\Controller\Account;
use App\Core\Config;
use App\Core\Csrf;
use App\Core\Response;
use App\Core\Session;
class EditAccount extends \App\Core\Controller
{
public function __construct()
{
parent::__construct();
//Auth::checkAuthentication();
}
public function index()
{
}
public function action()
{
}
}
Now, I work in PhpStorm and see this override error:
How do can in Fix this error?
Note: If I remove extends \App\Core\Controller from EditAccount class, error fixed But I need to extends \App\Core\Controller.
When I receive an API request it routes trough the Application.php to the UserController.
The UserController does his thing with the information and I need to call the EmailController, because that is the controller that manages all the emails.
In the EmailController I have a function (its simplified):
class EmailController {
public function getEmail() {
return 1337 ;
}
}
In the UserController I have a function:
class UserController {
public function getUserMail(Request $request, Application $app) {
$number = ???;
return $number;
}
}
What do I have to call within the UserController to get the getEmail function of the EmailController?
If this is not a correct way of doing it, I would love to hear what term I am acutally searching for :)
Edit1:
As #lawrence-cherone pointed out, it should have been in a model.
It was stuck in my head that I had to use the controller for this task.
You could use the dependency injection to share the class that return number.
So your controllers will look like:
class EmailController
{
/**
* #var NumberCalculatorInterface
*/
private $numberCalculator;
/**
* #param NumberCalculatorInterface $numberCalculator
*/
public function __construct(NumberCalculatorInterface $numberCalculator)
{
$this->numberCalculator = $numberCalculator;
}
public function getEmail()
{
return $this->numberCalculator->getNumber();
}
}
and
class UserController
{
/**
* #var NumberCalculatorInterface
*/
private $numberCalculator;
/**
* #param NumberCalculatorInterface $numberCalculator
*/
public function __construct(NumberCalculatorInterface $numberCalculator)
{
$this->numberCalculator = $numberCalculator;
}
public function getUserMail(Request $request, Application $app)
{
$number = $this->numberCalculator->getNumber();
return $number;
}
}
Your class that calculate number or other more complex logic will be
interface NumberCalculatorInterface
{
public function getNumber();
}
class DefaultNumberCalculator implements NumberCalculatorInterface
{
public function getNumber()
{
return 1337;
}
}
Since the number calculation is not a logic proper to your EmailController cause you use the logic in several classes, it make sense to be an external class. You will be able to unit test it properly and to inject in all the classes that need this calculation to be done.
You will be able to declare it as service:
class NumberCalculatorProvider implements ServiceProviderInterface {
public function register(Container $pimple)
{
$pimple['number_calculator'] = function () {
return new DefaultNumberCalculator();
};
}
}
And inject it inside your controller easily (in the following example is use the ServiceControllerServiceProvider to declare controller as services):
class ControllerProvider implements ServiceProviderInterface {
public function register(Container $pimple)
{
$pimple['controller.user'] = function ($pimple) {
return new UserController($pimple['number_calculator']);
};
$pimple['controller.email'] = function ($pimple) {
return new EmailController($pimple['number_calculator']);
};
}
}
note: In my example i use silex 2., since its not specified in your question, you may need to adapt it if you use an older version but the logic remain the same.*
I think you need to make UserController inherit the function getEmail() from EmailController
class UserController extends EmailController {
public function getUserMail(Request $request, Application $app) {
$number = ???;
return $number;
}
}
I have a service-providers here as well as http://dfg.gd/blog/decoupling-your-code-in-laravel-using-repositiories-and-services
My ServiceProvider:
class UsersRepositoryServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->bind('App\Repositories\Users\UsersInterface', function($app)
{
return new UsersRepository(new User);
});
}
And i get error: Call to a member function find() on a non-object
My Repository:
use \Illuminate\Database\Eloquent\Model;
//..
protected $usersModel;
public function __consturct(Model $users)
{
$this->usersModel = $users;
}
/**
* Get user by id
*
* #param mixed $userId
* #return Model
*/
public function getUserById($userId)
{
return $this->convertFormat($this->usersModel->find($userId));
}
__consturct is misspelled.
correct is __construct