I have and function like this, and I am using this through API and send request object.
public function test(Request $request){
//code
}
now I want to use the same function in another function like this
public function test2(){
$id = 2;
$this->test($id);
}
but in above I need to pass an id.
but the first function expects an argument type of request instance.
How can it be done? and I can't add second argument.
If you are not allowed to edit the method code for some reason, you can do the following:
Create a new Request instance.
Add id property to it with the value.
Call your method.
The Illuminate\Http\Request class has a capture() method which is like below:
/**
* Create a new Illuminate HTTP request from server variables.
*
* #return static
*/
public static function capture()
{
static::enableHttpMethodParameterOverride();
return static::createFromBase(SymfonyRequest::createFromGlobals());
}
In your code, you would do like below:
<?php
use Illuminate\Http\Request;
class xyz{
public function test(Request $request){
//code
}
public function test2(){
$request = Request::capture();
$request->initialize(['id' => 2]);
$this->test($request);
}
}
You should export your code in another function and then use a Trait in each of your controller. Therefore you will have access to the same function in two different classes.
By doing this, you can give whatever argument you want, even set defaults one without calling the controller function itself.
The official doc about Trait
The best practice would be to create a third private method in the controller (or in a separate class, as you prefer) that is called by both functions:
class TestController extends Controller {
public function test(Request $request){
$id = $request->get('id', 0); // Extract the id from the request
$this->doStuffWithId($id);
}
public function test2(){
$id = 2;
$this->doStuffWithId($id);
}
private function doStuffWithId($id) {
// code
}
}
You can and should organize your shared code across multiple controllers with services. Basically create class
<?php
namespace App\Services;
class TestService
{
public function testFunction($id)
{
// add your logic hear
return 'executed';
}
}
and in your controller inject this service and call function testFunction() like this:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Services\TestService;
class TestController
{
protected $testService;
public function __construct(TestService $testService)
{
$this->testService = $testService;
}
public function test(Request $request){
// handle validation, get id
$this->testService->testFunction($id);
// return response from controller (json, view)
}
Related
In my Laravel project, many Controllers and Models have the same headers.
For example, they all include
use Illuminate\Support\Facades\Auth;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use DB;
So, each time I ever create a new Controller, I have to insert the same header part. (like above)
Is there any way to autoload the above libraries in all controllers and models?
You could create a base class which accepts the dependencies in the constructor.
You could also create a Container class which reduces the amount of direct dependencies you have in a controller :
class Container
{
public function __construct(/* Your dependencies */) {
/* Set dependencies */
}
/* Dependency getters */
}
Controller:
class MyController
{
public function __construct(Container $container)
{
$this->container = $container;
}
public function index() {
/* Access dependencies on container */
}
}
But to be honest if you depend on request in a model class you have done something wrong. Typically in MVC the request info is passed from within the controller to the model, so the model does not know about the Request object, the values from Request are passed through as primitive values or value objects.
Update to explain my answer
You can reduce the amount of dependencies in your model classes (which is the best option) by simply following these rules, as explained here: https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html
So for example instead of writing:
//Note this is not a laravel specific example
class MyModel
{
private $request;
public function __construct(Request $request)
{
$this->request = $request;
}
public function getInfo()
{
return /* find info on $request->get('id'); */
}
}
You can write:
class MyController
{
public function __construct(MyModel $myModel)
{
$this->myModel = $myModel;
}
public function index()
{
$info = $this->myModel->getInfo($this->getRequest()->get('id'));
}
}
Where Request dependency is now removed from the Model:
//Note this is not a laravel specific example
class MyModel
{
public function getInfo(int $id)
{
return /* find info on $id; */
}
}
This was the simplest explanation, it will get more complex, so the best idea is to read and understand the article.
I trying to implements a interface to a controller but when i try that, the request is converted into a string.
Here is the code of the controller:
class FilesController extends Controller implements Repository
{
function __construct()
{
$this->factory = new RepositoryFactoryImp();
}
public function index($request)
{
$repository = $this->factory->createRepository($request->type_repository);
return $repository->getFilesList($request);
}
}
Here is the code of the interface:
interface Repository
{
public function index(GetFileListRequest $request);
}
Then the error that i get is:
ErrorException: Trying to get property 'type_repository' of non-object
in file
C:\xampp\htdocs\pocs\repository\app\Http\Controllers\FilesController.php
on line 31
I do a dd($request); and the result is a string, the string is the content of type_repository variable of the route:
Route::get('files/{type_repository}', 'filesController#index');
What can be the problem? Is possible to implements a interface to a controller?
Well to get started you haven't injected the request in your controller:
class FilesController extends Controller implements Repository
{
// ...
public function index($request) // <-----
{ // ^^^^^^^^^
$repository = $this->factory->createRepository($request->type_repository);
return $repository->getFilesList($request);
}
}
Try doing this instead:
use Illuminate\Http\Request;
// ...
public function index(Request $request) { ... }
// ^^^^^^^^^^^^^^^^
Side note
As an observation, you have declared the index() method in your interface but you are calling the createRepository() one in your implementation.
I want to reuse my method store that is in generar\productoController
public function store(Request $request){}
and I want to reuse it in this class adquisicion\ComprasController, I know that I have to import the class to use the method i want, but the problem is the $request variable, should I create a new object of it with $request = new Request(), adding the data I want with this and sending it as parameter?
Thx for the help I'm really new with laravel
you can try it like this $this->store(request(),$otherData)
use the helper to get the current object of request
You can pass Request data to other method
productoController(Request $request){
// anything here
return redirect('your route name')->with('data', $request->all());
}
Here are two ways that can make methods reusable in laravel application:
Make a helper method
Create a Helpers folder in app folder, and create all static methods inside a helper.php
Helper.php
namespace App\Helpers;
class Helper {
public static function store() {
$request = request();
// ....
}
}
YourController.php
namespace App\Repositories;
use App\Helpers\Helper;
use Illuminate\Http\Request;
class YourController extends Controller
{
public function store(Request $request) {
// call the store method as
Helper::store();
}
}
The downside here is you will mix up all the non-related helper methods here and may difficult to organize.
Repository
You can use a Repository Pattern to architect your application, for example, if you store a foo object to your datastore, then you can first create Repositories folder in app folder, and create FooRepository.php in Repositories folder:
FooRepository.php
namespace App\Repositories;
class FooRepository {
public function store() {
$request = request();
// ...
}
}
YourController.php
namespace App\Http\Controllers;
use App\Repositories\FooRepository;
use Illuminate\Http\Request;
class YourController extends Controller
{
private $fooRepository = null;
public function __construct(FooRepository $fooRepository) {
parent::__construct();
$this->fooRepository = $fooRepository;
}
public function store(Request $request) {
// call the method as
$this->fooRepository->store();
}
}
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 developping an API and because I have (mostly) the same functionality I've created an abstract class to be extended on my controllers.
My abstract class looks like: http://laravel.io/bin/23Bzj
Where in the controller I would construct with a model and response (will probably move the response to ApiController constructor later).
class EventController extends ApiController
{
public function __construct(Event $model, ResponseRepository $response)
{
$this->model = $model;
$this->response = $response;
}
}
But the question is: how will I be able to use the specific Request class in my ApiController to be used the in the methods for validation/what is the best practice.
I can use a normal Request class but then I won't have any validation before the methods.
When I'm in my EventController I will be able to use UpdateEventRequest and CreateEventRequest and so on.
As far as I know if you use in your controller in any method
public function edit(UpdateEventRequest $req) {
// any code
}
before launching // any code part validation will be done.
What you could try to do:
Change your update method in abstract class to protected
Change signature of this method from public function update(Request $request, $id) to public function update($request, $id) - I don't know it this step will be necessary
Create new method for example realUpdate with the following code:
public function realUpdate(UpdateEventRequest $req, $id) {
parent::update($req, $id);
}
I'm not sure about step 2 because I don't know if Laravel will try to run any validation if you use Request in your abstract class. It's also possible that it will run this validation again for UpdateEventRequest - you should give a try, I haven't tested it.
Basically you will have code similar to this:
<?php
class X
{
}
class Y extends X
{
}
abstract class ApiController
{
protected function update(X $x, $id)
{
echo "I have " . get_class($x) . ' and id ' . $id;
}
}
class Controller extends ApiController
{
public function realUpdate(Y $y, $id)
{
parent::update($y, $id);
}
}
$c = new Controller();
$c->realUpdate(new Y, 2);
and Laravel should run at least once validator based on rules from UpdateEventRequest.
You cannot have the same name for this method in child class because you will get a warning:
Strict Standards: Declaration of Controller::update() should be
compatible with ApiController::update(X $x, $id) in ... line 31
It will however still work but I assume you don't want to have any warnings.