In my Laravel app I have the following controller that takes the instance of Elastic search as a first parameter and then another variable:
use Elasticsearch\Client;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
class AngularController extends Controller {
public function selectRandom(Client $es, $numRows) {
# ...search params here
$results = $es->search($searchParams);
return $results;
}
}
I need to call the method of the controller above from another controller, I do it like this:
class HomeCtrl extends Controller {
public function index() {
$featured = new AngularController();
return $featured->selectRandom(12);
}
}
I get the following error
Argument 1 passed to
App\Http\Controllers\AngularController::selectRandom() must be an
instance of Elasticsearch\Client, integer given
I'm not well versed in OOP. Do I call it incorrectly? Because I though the method I call would take instance that is injected in controller, not from where I call it.
When you are calling a method from your Controller to another
Controller that means you are doing wrong. For this purpose you should
use service.
Create a class in app\Services Utility.php
use Elasticsearch\Client;
class Utility {
public function selectRandom(Client $es, $numRows) {
# ...search params here
$results = $es->search($searchParams);
return $results;
}
}
and just inject this class to your controller
In your AngularController class selectRandom method first parameter is a class instance second one is number,that's why you get this error.If you want to access this method using object form another controller you need to set first parameter of this object and second one is your id.Another solution is here
some modify in selectRandom method
public function selectRandom($numRows) {
# ...search params here
$es = new Client();
$results = $es->search($searchParams);
return $results;
}
Then you use this function
public function index() {
$featured = new AngularController();
return $featured->selectRandom(12);
}
Related
Is possible to call invoke function from a service in symfony?
this is the controller
class FooController extends AbstractController
{
private $fooService;
public function __construct(FooService $fooService)
{
$this->fooService = $fooService;
}
#[Route('/foo', name: 'app_foo')]
public function index(): Response
{
return new Response($this->fooService->__invoke());
//is not possible to do
//return new Response($this->fooService());
}
}
and the service
namespace App\Service;
class FooService
{
public function __invoke()
{
return 'hello';
}
}
I have to call __invoke function explicitly instead to make $this->fooService() is not possible to do it?
In PHP the method call has higher priority than property access so you need to use parentheses.
($this->fooService)()
To access the property and call it.
In my laravel (7.x) application, I have a method called _index in different controllers & models with exactly same functionality (fetch the data to display in the grid) and parameters (except 1, that requires an additional parameter called available).
So, I created a super method in the base controller, something line this:
Controller.php
namespace App\Http\Controllers;
use Illuminate\Routing\Controller as BaseController;
class Controller extends BaseController
{
protected function _index($ModelClass, $status, $available = null)
{
# models
$Model = new $ModelClass();
# accessing and returning method data
return $Model->_index(status: $status, available: $available);
}
}
SomeController.php
class SomeController extends Controller
{
public function _index()
{
# accessing super methods
$SomeModel = $this->_index(SomeModel::class, true);
...
# rendering
return view('some-view', compact($SomeModel));
}
}
class SomeModel extends Model
{
public function _index($status = null, $available = null) : array
{
if($available == true)
{
...
}
}
}
AnotherController.php
class AnotherController extends Controller
{
public function _index()
{
# accessing super methods
$AnotherModel = $this->_index(AnotherModel::class);
...
# rendering
return view('another-view', compact($AnotherModel));
}
}
class AnotherModel extends Model
{
public function _index($status = null) : array
{
...
}
}
Only SomeController / index is working fine but other controllers which does not required the $available parameter are showing Unknown named parameter $available.
Is there a way to ignore the missing parameters, as there is no point in including the parameter in the rest of the methods, throughout the application..?
I am not sure if this is the right way to handle this or not.
Controller.php
namespace App\Http\Controllers;
use Illuminate\Routing\Controller as BaseController;
class Controller extends BaseController
{
protected function _index($ModelClass, $status, $available = null)
{
# models
$Model = new $ModelClass();
try
{
# accessing and returning method data
return $Model->_index(status: $status, available: $available);
}
catch (\Throwable $th)
{
# handling missing parameter error/exception
if($th->getMessage() == 'Unknown named parameter $available')
{
return $Model->_index(status: $status);
}
}
}
}
However, in case anybody finds a better way to handle this issue. Then do post your answer.
Thanks...
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)
}
Per https://documentation.concrete5.org/developers/routing/routing-basics one captures parameters from the route as follows:
$router->get('/api/customer/{customerId}', function($customerId) {
return 'The customer ID is: ' . $customerId;
});
However, per https://documentation.concrete5.org/developers/routing/controllers one shouldn't use closure and instead use a separate controller as follows:
$router->get('/api/current_user', 'Application\Api\Controller\UserController::getCurrentUser');
class UserController
{
public function getCurrentUser()
{
//...
}
}
How do I pass a parameter when using a controller? I would have expected the following, but $customerId is not passed to the controller method.
$router->get('/api/customer/{customerId}', 'Application\Api\Controller\UserController::getSomeUser');
class UserController
{
public function getSomeUser($customerId)
{
//...
}
}
I want to access to my TestControler in DefaultController. So I've create a new instance, but the container is null. If I want to call a method, symfony throws a FatalErrorException:
Error: Call to a member function get() on a non-object in
DefaultController:
/**
* DefaultController.
*
*/
class DefaultControllerextends Controller
{
public function indexAction()
{
$contrTest = new TestController();
var_dump($contrTest);
}
var_dump result:
object(test\testBundle\Controller\TestController)#283 (1) {
["container":protected]=> NULL }
How can i do that?
Using other controllers inside a controller is a sign of bad architecture. Usually, it means you have to split the controller into a service, which you can use everywhere, and a controller.
For instance, when you have a controller which has a parseAction which parses a file and you need to use that in another controller too, you must create a acme_demo.parser.the_file_type service (give it which name you want) and use that in both controllers:
// ...
class FirstController extends Controller
{
public function xxxAction()
{
$parser = $this->get('acme_demo.parser.the_file_type');
$data = $parser->parse(...);
}
}
// ...
class SecondController extends Controller
{
public function yyyAction()
{
$parser = $this->get('acme_demo.parser.the_file_type');
$data = $parser->parse(...);
}
}