Is it a bug or a feature?
I have two controllers IndexController and TestController.
The first one looks like this:
class IndexController extends \Phalcon\Mvc\Controller
{
public function indexAction()
{
$products = $this->basket->get('products', []);
$products[] = uniqid('index.index');
$this->basket->set('products', $products);
}
public function testAction()
{
var_dump($this->basket->products);
}
}
I just save an array in a session with indexAction and show that data in testAction.
For the first request output for index/test is an empty array. But the second and all following requests add one new element. If I comment line $this->basket->set('products', $products); then the next request to index/test will add another value to array but after that extra pushing to array does not happen.
Then I add
class TestController extends \Phalcon\Mvc\Controller
{
public function indexAction()
{
$products = $this->basket->get('products', []);
$products[] = uniqid('test.index');
$this->basket->set('products', $products);
die();
}
public function testAction()
{
var_dump($this->basket->products);
die();
}
}
But for request test/test I again get changing in session variable.
Looks like that route index/index always executes before any other routes. Is it a feature, bug or some sort of misconfiguration? I use standard configuration for multimodule application from official documentation.
This is more than likely because your browser is hitting /favicon.ico in the background. I've been stung by this a number of times across different frameworks.
Try putting a favicon.ico file (or a rule to block that path) and see if the problem persists.
Related
I know this might seem anti pattern, and a lot will throw stones at me, but please hear me out.
I want to create a generic Controller to support many reference tables (mostly id, label). So I did something like this:
class GenericController extends Controller
{
public function index($modelName)
{
$x = '\\App\\Models\\'.$modelName;
$data = $model->all();
return view('generic.list', ['model'=>$model, 'data'=>$data]);
}
}
And this way my routes in web.php will be reduced to the minimum like this:
//List
Route::get('/{model}', function ($model) {
return App::call('\App\Http\Controllers\GenericController#index', ['modelName' => $model]);
});
It's working very well with simple CRUD actions like store, update, etc.. However I know I am over simplifying the design because sometimes I need to return a field from a joined table in the index list for example. That's where I am heading into a dead end, sort of.
My first thought was to create a controller for each model that inherits from the GenericController like this:
class CategoryController extends GenericController
{
}
And whenever I need to override the GenericController method, I would simply add it to the child class. However how can I do this from inside the GenericController (call a method in a sub class from parent class)? Because otherwise I will have to create routes for every single model which is against my wish.
So basically I am looking for something like this:
class GenericController extends Controller
{
public function index($modelName)
{
$x = '\\App\\Models\\'.$modelName;
//this thing I'm looking for is something like this:
//Check if we have CategoryController and it has a definition for index
//if yes do something like $data = CategoryController->index();
//otherwise just call $data = $model->all();
return view('generic.list', ['model'=>$model, 'data'=>$data]);
}
}
So I know this seems weird and anti-pattern, but other wise how can I create my generic routes and controller actions?
You are right, this is not really what is called "best practice". However, from a POO standpoint, it is an interesting question.
This what you can do:
class GenericController extends Controller
{
protected function getData(string $model)
{
return $model::all();
}
public function index($modelName)
{
$model = '\\App\\Models\\'.$modelName;
$data = $this->getData($model);
return view('generic.list', ['model'=>$model, 'data'=>$data]);
}
}
By default, the data will be retrieved "the simple way", using $data = $this->getData($model);.
However, if you make a CategoryController:
class CategoryController extends GenericController
{
protected function getData(string $model)
{
return Category::query()->with('something')->where('hello','world')->get();
}
}
You will just have to override the getData method inside your CategoryController.
This is the way to go if you want something clean. Of course, your categories routes will have to use this CategoryController instead of the GenericController.
In my laravel 5.5 api I have a lot of response message like
"You successfully completed some action..".
At the moment I have stored them as constants in the controller they
are used. I want to move all of them to a single location, so if I need to change them later I don't have to hunt for them in each controller.
What is the best approach for this usecase?
What about Laravel localization? Then using it as trans('success-message-key-here')
In your use case, I would make static functions to call the responses the same way.
class ResponseMessage
{
public static function succesfulResponse()
{
return response('successfull', 200);
}
public static function failedResponse()
{
return response('fail', 400);
}
}
Use case:
...
return ResponseMessage::succesfulResponse();
Another way is to take the parent controller, which is often just named Controller in your controller folder, which you extend from.
class controller
{
public function succesfulResponse()
{
return response('successfull', 200);
}
}
Now you are not in a static context, but you can use the functions if you extend from it.
class yourController extends Controller
{
public function get($id) {
...
return $this->succesfulResponse();
}
}
You could make use of the translations files even if you are just supporting one language.
In your controller you would have something like:
$message = \Lang::get('directory/file.str1');
And your translation file:
return [
'str1' => 'You successfully completed some action.',
];
In resource/lang/en directory (in other words Localization you can put your message like this
ApiMessage.php
return [
'success' => 'success message',
];
Then in your controller you can call like this
public function somefunction(Request $request)
{
// your logic
return response()->json(__('apiMessages.success'));
}
here en folder denotes your local language (default is english symbolized as en)
I have a model, called Tours and controller ToursController which uses restful methods (index, show, store, edit, update etc).
Now I have this code:
$names = request()->get('names');
$lastnames = request()->get('lastnames');
$hotels = request()->get('hotel');
both in Store and Update. So i duplicate the same code twice. And this is only one exmaple of duplicated code.
I want to create a function "getEverythingFromRequest()"
which I can use in both Store and Update methods. Something like:
public function store (Request $request) {
getEverythingFromRequest();
dd($names[3];
}
public function store (Request $request) {
getEverythingFromRequest();
dd($hotels[2];
}
How can I do it? Globally, how can I avoid re-writing the same code in Controller?
There are a bunch of ways to solve this. One way would be to create a repo that extracts the arrays from your request. (I updated my code to use injection).
Controller
public function store (GuestsRepository $repo, Request $request) {
dd($repo->names);
}
Repository
<?php
namespace App;
class GuestsRepository
{
public $names;
public $lastnames;
public $hotels;
public function __construct(){
$this->names = request()->get('names');
$this->lastnames = request()->get('lastnames');
$this->hotels = request()->get('hotel');
}
}
I am trying to pass the request variable from a form request to another controller (the second controller is going to have a lot of code in it so I want to use it to keep the main controller clean), but when I try and pass the variable over, nothing happens, the variable data isn't sent over.
Here is my current code:
class mainController extends Controller{
public function store(Request $request)
{
//validation
$otherClass = (new secondController)->createDBEntry($request);
}
}
class secondController extends Controller{
public function createDBEntry($request)
{
return $request;
}
}
However, nothing is passed from the $request into the secondController. If I echo something in the secondController it works no problem, so I know it's being called, but the data isn't being sent over. What am I missing here? Keep in mind I am fairly new to laravel and I am using 5.4.
Your code works just fine. You are just expecting a behavior that is never going to happen though because:
new secondController instantiates secondController
createDBEntry($request) calls the method createDBEntry passed
with $request
The returned value is stored in the variable $otherClass
And that's it! nothing more is (and will be) happening. If you want to see the value of $otherClass (and see your code working) you have to return it:
class mainController extends Controller
{
public function store(Request $request)
{
$otherClass = new secondController
$otherClass->createDBEntry($request);
return $otherClass;
}
}
class secondController extends Controller
{
public function createDBEntry($arg)
{
return $arg;
}
}
How to recall the construct as it contains all the required data for the page?
class Abc extends CI_Controller
{
public function __construct()
{
parent::__construct();
$this->load->model('xyz_m');
$this->data['info'] = $this->xyz_m->get(); //get data
}
public function 123()
{
/*view page code*/
}
public function 456()
{
/*insert code here*/
$this->123(); // redirect, need to load 123() with updated data from construct.
}
}
So, how do you make the __construct initiate again so you get a new updated results from database?
You should name your methods with letter first i.e. there is convention for method names uses descriptive words getProducts() or get_books or you will get PHP error for using numbers as method names. So in your case method names should be like a123() or b_456().
Second thing, regarding your need in question, since you assign data from DB using model to array $this->data, you would use it like:
class Abc extends CI_Controller
{
public function __construct()
{
parent::__construct();
$this->load->model('xyz_m');
$this->data['info'] = $this->xyz_m->get(); //get data
}
public function a123()
{
$this->load->view('a123_view', $this->data);//loading file APPPATH . 'a123_view.php' and passing created array to it
}
public function b_456()
{
/*insert code here*/
$this->a123(); // redirect, need to load 123() with updated data from construct.
}
}
In your APPPATH . 'a123_view.php':
<?php var_dump($info);//here you would call key of array you passed from controller as variable ?>
Check basics in CodeIgniter documentations. All this is described in General Topics section.