I have a method that accepts a request
public function createUser(Request $request)
{
...
}
I want to call it from another method
public function someMethod(){
$array = [...];
return $this->createUser($array); <----
}
and how can I pass a new request to it with the array I need?
How about instead of trying to call a controller method, you move the logic to create a user to a service class and then use the service class in your createUser and someMethod methods?
UserService.php
class UserService
{
public function __construct() { }
public function createUser(array $userData)
{
// TODO use $userData to create a user here
return $newUser;
}
}
SomeController.php
public function createUser(Request $request)
{
$this->userService->createUser($request->all());
}
public function someMethod(){
$array = [...];
return $this->userService->createUser($array);
}
Related
I have a class like this:
class BaseApiController extends Controller
{
protected $user;
function __construct()
{
$this->configHeaderRequest();
$this->validateToken();
}
protected function validateToken()
{
$this->middleware(function ($request, $next) {
if (Auth::guard('web')->user()) {
$this->user = Auth::guard('web')->user();
}
var_dump($this->user); //=> This is "user object" as well
return $next($request);
});
}
}
And another class that is extended from the class above:
class NewsController extends BaseApiController
{
public function __construct(Request $request)
{
parent::__construct($request);
$this->middleware(function ($request, $next) {
if (empty($this->user)) {
return $this->sendFailedResponse('Unauthorized Request', 401);
}
return $next($request);
});
}
public function search(Request $request): JsonResponse
{
var_dump($this->user); //=> but there is "null"
}
}
As you can see, $this->user will be null when I needed the user's object inside the search(Request $request) method while surprisingly the user's object exists inside the validateToken() method. Why? And how can I access the user's object there?
I have a method with a lot of code
public function createNewObject(Request $request)
{
// Code...
}
There is another method that I plan to call, but how to pass it to the createNewObject method as a Request argument?
public function deleteAndCreateObject()
{
$this->createNewObject(???);
}
Just type-hint it in your deleteAndCreateObject() method.
class YourController
{
public function createNewObject(Request $request)
{
// Code...
}
public function deleteAndCreateObject(Request $request)
{
$this->createNewObject($request);
}
}
If that—for some reason—doesn't work for you, you can always use request():
class YourController
{
public function createNewObject()
{
$request = request();
// Code...
}
public function deleteAndCreateObject()
{
$this->createNewObject();
}
}
Initially I have to attach with each action :-
Here we first fetch menu detail then pass in to view section.
Class ManageadministratorController extends Controller {
public $data_menu;
public function __construct() {
$this->middleware('auth');
$obj = new General;
$this->data_menu=$obj->displaymenu();
}
public function index()
{
$obj = new General;
$permission = $obj->checkViewPermission("manageadministrator");
$query= Adminlogin::get();
return View::Make('admin.manageadministrator.manage',array('record'=>$query,'menu_list'=>$this->data_menu));
}
function add()
{
return View::Make('admin.manageadministrator.add',array('menu_list'=>$this->data_menu));
}
}
You can register a custom service provider or use AppServiceProvider:
public function boot()
{
$obj = new General;
$data_menu = $obj->displaymenu();
view()->composer('admin.manageadministrator', function($view) {
$view->with('menu_list', $data_menu);
});
}
Or use a dedicated class:
// app/Providers/AppServiceProvider.php
public function boot()
{
view()->composer('admin.manageadministrator', 'App\Http\Composers\MasterComposer');
}
// app/Http/Composers/MasterComposer.php
use Illuminate\Contracts\View\View;
class MasterComposer {
public function compose(View $view)
{
$obj = new General;
$data_menu = $obj->displaymenu();
$view->with('menu_list', $data_menu);
}
}
In my controller, I have something like the following:
public function index()
{
$questions = Question::all();
return view('questions.index', compact('questions'));
}
However, I would like this route to also be used by my ajax requests. In which case, I'd like to return JSON. I'm considering the following:
public function index()
{
$questions = Question::all();
return $this->render('questions.index', compact('questions'));
}
public function render($params)
{
if ($this->isAjax()) {
return Response::json($params);
} else {
return view('questions.index')->with($params);
}
}
..by the way, I haven't tested any of this yet, but hopefully you get the idea.
However, I was wondering if I can alter the built in view(...) functionality itself to keep things even lighter. So I just keep the following:
public function index()
{
$questions = Question::all();
// this function will detect the request and deal with it
// e.g. if header X-Requested-With=XMLHttpRequest/ isAjax()
return view('questions.index', compact('questions'));
}
Is this possible?
You probably want to make custom response:
add ResponseServiceProvider.php
namespace App\Providers;
use Request;
use Response;
use View;
use Illuminate\Support\ServiceProvider;
class ResponseServiceProvider extends ServiceProvider
{
/**
* Perform post-registration booting of services.
*
* #return void
*/
public function boot()
{
Response::macro('smart', function($view, $data) {
if (Request::ajax()) {
return Response::json($data);
} else {
return View::make($view, $data);
}
});
}
/**
* Register any application services.
*
* #return void
*/
public function register()
{
//
}
}
Add 'App\Providers\ResponseServiceProvider' to providers list in config/app.php:
'providers' => [
'App\Providers\ResponseMacroServiceProvider',
];
Use new helper in controller:
return Response::smart('questions.index', $data);
Simply check if the Request is an Ajax request in your index method itself.
public method index() {
$questions = Question::all();
if(\Request::ajax())
return \Response::json($questions);
else
return view('questions.index', compact('questions'));
}
Use Request::ajax(), or inject the request object:
use Illuminate\Http\Request;
class Controller {
public function index(Request $request)
{
$data = ['questions' => Question::all()];
if ($request->ajax()) {
return response()->json($data);
} else {
return view('questions.index')->with($data);
}
}
}
Your view should never know anything about the HTTP request/response.
I guess the simple method is just to put a method inside the parent Controller class:
use Illuminate\Routing\Controller as BaseController;
abstract class Controller extends BaseController {
...
protected function render($view, $data)
{
if (Request::ajax()) {
return Response::json($data);
} else {
return view($view, $data);
}
}
}
and then instead of doing view('questions.index, $data);, do $this->render('questions.index', $data);
I'm using laravel (4.2) framework to develop a web application (PHP 5.4.25). I've create a repository-interface that was implemented with eloquent-repository, I use that repository inside a UserController:
# app/controllers/UsersController.php
use Gas\Storage\User\UserRepositoryInterface as User;
class UsersController extends \BaseController {
protected $user;
public function __construct(User $user) {
$this->user = $user;
}
public function store() {
$input = Input::all();
$validator = Validator::make(Input::all(), $this->user->getRoles());
if ( $validator->passes() ) {
$this->user->getUser()->username = Input::get('username');
$this->user->getUser()->password = Hash::make(Input::get('password'));
$this->user->getUser()->first_name = Input::get('first_name');
$this->user->getUser()->last_name = Input::get('last_name');
$this->user->getUser()->email = Input::get('email');
$this->user->save();
return false;
} else {
return true;
}
}
}
My Repository implementation:
namespace Gas\Storage\User;
# app/lib/Gas/Storage/User/EloquentUserRepository.php
use User;
class EloquentUserRepository implements UserRepositoryInterface {
public $_eloquentUser;
public function __construct(User $user) {
$this->_eloquentUser = $user;
}
public function all()
{
return User::all();
}
public function find($id)
{
return User::find($id);
}
public function create($input)
{
return User::create($input);
}
public function save()
{
$this->_eloquentUser->save();
}
public function getRoles()
{
return User::$rules;
}
public function getUser()
{
return $this->_eloquentUser;
}
}
I've also create a UsersControllerTest to testing the controller and all works fine, the user was added to the DB. After I mocked my UserRepositoryInterface because I don't need to test the DB insert, but I just want to test the controller
class UsersControllerTest extends TestCase {
private $mock;
public function setUp() {
parent::setUp();
}
public function tearDown() {
Mockery::close();
}
public function mock($class) {
$mock = Mockery::mock($class);
$this->app->instance($class, $mock);
return $mock;
}
public function testStore() {
$this->mock = $this->mock('Gas\Storage\User\UserRepositoryInterface[save]');
$this->mock
->shouldReceive('save')
->once();
$data['username'] = 'xxxxxx';
$data['first_name'] = 'xxxx';
$data['last_name'] = 'xxxx';
$data['email'] = 'prova#gmail.com';
$data['password'] = 'password';
$data['password_confirmation'] = 'password';
$response = $this->call('POST', 'users', $data);
var_dump($response->getContent());
}
}
My ruote file:
Route::resource('users', 'UsersController');
When I run the test I get the following error:
Mockery\Exception\InvalidCountException : Method save() from Mockery_0_Gas_Storage_User_UserRepositoryInterface should be called
exactly 1 times but called 0 times.
Why the mocked method save has not be called?
What is wrong?
EDIT: without partial mock all works fine, now the question is: why with partial mock it doesn't work?
Thanks
Looking back at your code, it seems like you should be able to use partial mocks just by changing your mock function to something like this:
public function mock($class) {
$mock = Mockery::mock($class);
$ioc_binding = preg_replace('/\[.*\]/', '', $class);
$this->app->instance($ioc_binding, $mock);
return $mock;
}
You are telling the mock to expect the save() method, but the save() is on the Eloquent model inside the Repository, not the Repository you are mocking.
Your code is currently leaking details of the implementation of the Repository.
Instead of calling:
$this->user->getUser()->username = Input::get('username');
You need to pass an instance of the User into the Repository:
$this->user->add(User::create(Input::all());
Or you pass the array of Input into the Repository and allow the Repository to create a new User instance internally:
$this->user->add(Input::all());
You would then mock the add() method in your test:
$this->mock->shouldReceive('add')->once();
The comments about Laravel not being suited for mocking or unit testing are wrong.