Question might be unclear. here's the explanation. Let's say I've:
Route file:
Route::get('testing', 'someController#functionOne');
Route::get('testingtwo', 'someController#functiontwo');
Controller file:
public function functionOne() {
$this->data = generateReallyBigArray();
return redirect('testingtwo');
}
public function funtionTwo() {
// Here $this->data is lost. obviously 'coz this controller file got reinstantiated for #functionTwo
return view('someview', ['data' => $this->data]);
}
$this->data is lost the moment testingtwo is hit. How do I pass this data across different route requests? Or if there're other ways of doing it.
I was thinking of doing this:
public function functionOne() {
$this->data = 'somedata';
return $this->functionTwo();
}
public function funtionTwo() {
// Here $this->data is lost. obviously 'coz this controller file got reinstantiated for #functionTwo
// even this doesn't work. Exception: Method get does not exist
return Route::get('testingtwo', function() {
return view('someview', ['data' => $this->data]);
});
}
use with() to send data through session -
public function functionOne() {
$this->data = 'somedata';
return redirect('testingtwo')->with('data', $this->data);
}
Or you could flash() the data for using on next request.
$request->session()->flash('data', $this->data);
the best way for that is
traits
trait Data{
public function getData() {
// .....
}
}
and in your controllers write
use Data;
you can use traits over controllers
or
You can access your controller method like this:
app('App\Http\Controllers\controllerName')->getDataFunction();
This will work, but it's bad in terms of code organisation (remember to use the right namespace for your ControllerName)
Related
I have a couple of functions which i use in all controllers like this:
//ajax
public function region()
{
return Region::all();
}
//ajax
public function provinces(Request $request)
{
if(!empty($request->input('region_select')))
{
$id_region = $request->input('region_select');
return Region::find($id_region)->Provinces;
}
else{
return Province::all();
}
}
Is it correct to extend the base controller with these functions to have them available globally?
Or is there a safer and more elegant approach?
Thanks in advance.
I have a data that I want to return in all of my controller methods and I thought that'd be cleaner to return from the controller's constructor; because currently it's just repetitive return code.
protected $data;
public function __construct() {
$this->data = "Test";
}
public function index() {
// Stuff
return view('test')->with([
'testData' => $this->data
// other view data
]);
}
public function store() {
// Stuff
return redirect()->back()->with([
'testData' => $this->data
// other view data
]);
}
This is just a pseudo example.
Yes, that's possible. It's done exactly in the same manner you showed.
However, I don't think that's the best way to do it. You might want to take a look into ViewComposers, which help provide a data set to a view (or multiple views) right after the controller but before the view is finally provided to the user.
You could just write a controller method to append the data property for you:
protected function view($name, $data = [])
{
return view($name, $data + $this->data);
}
public function index() {
...
return $this->view('view', ['other' => 'data']);
}
You can use ViewComposer which allow you to attach data to the view every time certain views is rendered
namespace App\ViewComposers;
class DataComposer
{
protected $data = ['1', '2', '3']; // This data is just for sample purpose
public function compose(View $view)
{
$view->with('data', $this->data);
}
}
And to register this composer with the list of all views on which the data must by attached add this code in the boot method off the AppServiceProvider
View::composer(
['view1', 'view2', 'view3', '....'],
'App\ViewComposers\DataComposer'
);
create a after middleware However, this middleware would perform its task after the request is handled by the application
Yes, it is very much possible with the code you have
[EDIT]
If you wish to remove ['testData' => $this->data] from all controller methods, then you can use view composers.
View composers are linked to one view. So for that view, if you have the same set of data to be passed all the time, use view composers!
I am somewhat new to OOP, although I know about interfaces and abstract classes a bit. I have a lot of resource controllers that are somewhat similar in the bigger scheme of things, they all look like the example below, the only main difference is the index and what I pass to the index view.
What I simply need to know is, can I OO things up a bit with my resource controllers? For example, create one "main" resource controller in which I simply pass the correct instances using an interface for example? I tried playing around with this but I got an error that the interface wasn't instantiable, so I had to bind it. But that means I could only bind an interface to a specific controller.
Any advice, tips and pointers will help me out :)
class NotesController extends Controller
{
public function index()
{
$notes = Note::all();
return view('notes.index', compact('notes'));
}
public function create()
{
return view('notes.create');
}
public function show(Note $note)
{
return view('notes.show', compact('note'));
}
public function edit(Note $note)
{
return view('notes.edit', compact('note'));
}
public function store(Request $request, User $user)
{
$user->getNotes()->create($request->all());
flash()->success('The note has been stored in the database.', 'Note created.');
return Redirect::route('notes.index');
}
public function update(Note $note, Request $request)
{
$note->update($request->all());
flash()->success('The note has been successfully edited.', 'Note edited.');
return Redirect::route('notes.index');
}
public function delete($slug)
{
Note::where('slug', '=', $slug)->delete();
return Redirect::to('notes');
}
}
Note: Totally my opinion!
I would keep them how you have them. It makes them easier to read and understand later. Also will save you time when you need to update one to do something different from the rest. We tried this in a project I worked on and while granted it wasn't the best implementation, it is still a pain point to this day.
Up to you though. I'm sure people have done that in a way that they love and works great. Just hasn't been the case in my experience. I doubt anyone would look at your code though and criticize you for not doing it.
In Case you need to bind different Model instanses then you may use Contextual Binding, for example, put the following code in AppServiceProvider's register() method:
$this->app->when('App\Http\Controllers\MainController')
->needs('Illuminate\Database\Eloquent\Model')
->give(function () {
$path = $this->app->request->path();
$resource = trim($path, '/');
if($pos = strpos($path, '/')) {
$resource = substr($path, 0, $pos);
}
$modelName = studly_case(str_singular($resource));
return app('App\\'.$modelName); // return the appropriate model
});
In your controller, use a __construct method to inject the model like this:
// Put the following at top of the class: use Illuminate\Database\Eloquent\Model;
public function __construct(Model $model)
{
$this->model = $model;
}
Then you may use something like this:
public function index()
{
// Extract this code in a separate method
$array = explode('\\', get_class($this->model));
$view = strtolower(end($array));
// Load the result
$result = $this->model->all();
return view($view.'.index', compact('result'));
}
Hope you got the idea so implement the rest of the methods.
So I have a Laravel Controller (MainController.php) with the following lines:
...
public function _settings_a(){
return view('_settings_a');
}
public function _settings_b(){
return view('_settings_b');
}
public function _settings_c(){
return view('_settings_c');
}
public function _settings_d(){
return view('_settings_d');
}
public function _staff_a(){
return view('_staff_a');
}
public function _staff_b(){
return view('_staff_b');
}
public function _staff_c(){
return view('_staff_c');
}
...
And my routes.php is as follows:
Route::any('_staff_a''MainController#_staff_a');
Route::any('_staff_b''MainController#_staff_b');
...
etc.
It seems there are a LOT of lines and a LOT of things to change if I change my mind...
I was wondering if I can have some regex in routes.php and an equivalent regex in MainController.php for handling routes that begin with an underscore (_)?
Can any Laravel experts share some tips/suggestions? I'm quite new to the framework.
Sure - just add it as a parameter. E.g. like this:
Route::any('_staff_{version}', 'MainController#_staff');
public function _staff($version) {
return view('_staff_'.$version);
}
I don't think you need to mess with regex. You can use implicit controllers Route::controller() which isn't the BEST solution, but will do what I think you are wanting.
So instead of
Route::any(..)
you can do
Route::controller('url', 'MainController');
So your route to whatever 'url' is will send you to this controller. Follow that with a '/' and then add whichever method in the controller you want to call.
Here is an example:
My url: 'http://www.example.com/users'
// routes.php
Route::controller('users', UserController');
// UserController.php
public function getIndex()
{
// index stuff
}
Now I send a request like: http://www.example.com/users/edit-user/125
// UserController.php
public function getEditUser($user_id)
{
// getEditUser, postEditUser, anyEditUser can be called on /users/edit-user
// and 125 is the parameter pasted to it
}
Doing it this way should allow you to be able to just send a request (post or get) to a url and the controller should be able to call the correct method depending on the url.
Here are some more rules about it: http://laravel.com/docs/5.1/controllers#implicit-controllers
I'm using CakePhp 2.2 and I have this simple controller, named ProvidersController:
<?php
class ProvidersController extends AppController {
public $components = array('Session', 'Social');
public $layout = false;
public function facebook(){
$this->Social->auth('facebook', 'success', 'error');
$this->render(false);
}
public function google(){
$this->Social->auth('google', 'success', 'error');
$this->render(false);
}
private function success(){
}
private function error(){
}
}
?>
and this Component, named SocialComponent:
<?php
class SocialComponent extends Component {
public function auth($provider, $success, $error){
}
}
?>
as you can see I have created success() and error() methods inside the controller. Now I pass these names and I would like to call them back from the component.
I only pass the name of the callback, how to call them from the component?
Thank you!
Have a look at the source code of the SecurityComponent in CakePHP, it has an identical situation with its blackHoleCallback.
They use a helper function SecurityComponent::_callback() which uses PHP's call_user_func_array()
protected function _callback(Controller $controller, $method, $params = array()) {
if (is_callable(array($controller, $method))) {
return call_user_func_array(array(&$controller, $method), empty($params) ? null : $params);
} else {
return null;
}
}
You can use the same pattern to pass callbacks into your component.
The point of a component is re-usability across many controllers - if you're trying to make it access a specific controller function, you should probably just be using controller methods, not a component.
BUT - you can always just do your logic in the component and pass back data (upon success or error), then check the results in the controller, and access whichever method you'd like based on those results.
Since your 'success' or 'error' logic is in the controller, I assume you don't want it in the component... ie it's different per use of the component. In that case, all you really want the component to do is do the logic and let you know how it went (return data).
//Controller
//..
public function facebook(){
$results = $this->Social->auth('facebook', 'success', 'error');
if($results['error']) $this->Social->error();
$this->render(false);
}
private function success(){ }
private function error(){ }
//...
//Component
//...
public function auth($provider, $success, $error){
$results = array();
//do something
$results['error'] = true;
return $results;
}
//...