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(...);
}
}
Related
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)
}
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.
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);
}
I want to make a modular Controller by separating Actions in different class.
The problem is some of the actions are calling a private function of the controler.
Controller :
class ApiController extends Controller
{
public function actions()
{
return array(
'index'=>'application.controllers.api.IndexAction',
);
}
..........
private function _sendResponse($status = 200, $body = '', $content_type = 'text/html')
{
// some code
}
}
In IndexAction.php I tried like this, but doesn't work :
class IndexAction extends CAction
{
public function run()
{
$this->getController()->_sendResponse(204); //this error
}
}
the exception is
ApiController and its behaviors do not have a method or closure named "_sendResponse".
Is this possible what i'm trying to do?
am I missing something here?
I looks like you try to access a private Method out of the Scope of your Class. Not even Classes that inherit can access a private Method.
Try public function _sendResponse()
I have this route: Route::controller('/', 'PearsController'); Is it possible in Laravel to get the PearsController to load a method from another controller so the URL doesn't change?
For example:
// route:
Route::controller('/', 'PearsController');
// controllers
class PearsController extends BaseController {
public function getAbc() {
// How do I load ApplesController#getSomething so I can split up
// my methods without changing the url? (retains domain.com/abc)
}
}
class ApplesController extends BaseController {
public function getSomething() {
echo 'It works!'
}
}
You can use (L3 only)
Controller::call('ApplesController#getSomething');
In L4 you can use
$request = Request::create('/apples', 'GET', array());
return Route::dispatch($request)->getContent();
In this case, you have to define a route for ApplesController, something like this
Route::get('/apples', 'ApplesController#getSomething'); // in routes.php
In the array() you can pass arguments if required.
( by neto in Call a controller in Laravel 4 )
Use IoC...
App::make($controller)->{$action}();
Eg:
App::make('HomeController')->getIndex();
and you may also give params
App::make('HomeController')->getIndex($params);
You should not. In MVC, controllers should not 'talk' to each other, if they have to share 'data' they should do it using a model, wich is the type of class responsible for data sharing in your app. Look:
// route:
Route::controller('/', 'PearsController');
// controllers
class PearsController extends BaseController {
public function getAbc()
{
$something = new MySomethingModel;
$this->commonFunction();
echo $something->getSomething();
}
}
class ApplesController extends BaseController {
public function showSomething()
{
$something = new MySomethingModel;
$this->commonFunction();
echo $something->getSomething();
}
}
class MySomethingModel {
public function getSomething()
{
return 'It works!';
}
}
EDIT
What you can do instead is to use BaseController to create common functions to be shared by all your controllers. Take a look at commonFunction in BaseController and how it's used in the two controllers.
abstract class BaseController extends Controller {
public function commonFunction()
{
// will do common things
}
}
class PearsController extends BaseController {
public function getAbc()
{
return $this->commonFunction();
}
}
class ApplesController extends BaseController {
public function showSomething()
{
return $this->commonFunction();
}
}
if you were in AbcdController and trying to access method public function test() which exists in OtherController you could just do:
$getTests = (new OtherController)->test();
This should work in L5.1