Laravel 6 - One Controller with Multiple Functions - php

I have multiple users in my system, so I want a manager User with different dashboard.
My Controller look like this:
-Dashboard
->AdminDashboardController
->UserDashboardController
In my AdminDashboardController I have 2 function
public function countAllUser()
{
$cards = User::count();
return response()->json(['cards' => $cards]);
}
public function totalSales()
{
return 'Hello';
}
And In My DashboardController Like this
public function index(Request $request)
{
$adminUser = auth()->user()->roles->pluck('name')->toArray();
if($adminUser[0] === 'administrator') {
return (new AdminDashboardController())->countAllUser();
}
}
yes, its work, but if I tried something like this
return (new AdminDashboardController())->countAllUser()->totalSales();
It doesn't work and I think this doesn't make sense either..
Is there a way I can achieve this?? Thanks...

Although call controller method from another controller is not a good practice ,you should use service.
But if you really want to do this , you can do it by
\App::call('App\Http\Controllers\AdminDashboardController#countAllUser');
or
(new AdminDashboardController())->countAllUser();
or
app(\App\Http\Controllers\AdminDashboardController::class)->countAllUser();
Your code
return (new AdminDashboardController())->countAllUser()->totalSales();
didn't work because
(new AdminDashboardController())->countAllUser() returns a \Illuminate\Http\JsonResponse instance , you should call totalSales on an controller instance

You should create Action/Helper/Service Class but if you want to return controller methods you will need to do something like
return response([
'user_count' => (new AdminDashboardController())->countAllUser(),
'sales' => (new AdminDashboardController())->totalSales(),
]);

Related

how can I use multiple methods in a route?

I would like to understand how to associate more methods to my route. For example:
Route::get('/dashboard', 'DController#showX')->middleware('auth');
Besides showX() I have another function called showY() that I would like to associate with the route, but if I rewrite it twice it doesn't go, how can I solve the problem?
Controller:
public function showY(){
$name=Auth::user()->name;
return view('dashboard',['name'=>$name]);
}
public function showX(){
$y= Y::all();
}
There is no way to do it from the route like that. How would you handle two return values?
Judging by the controller methods, maybe you want to use the value of showX in showY?
The way I see to handle this would be to have one method in the route:
Route::get('/dashboard', 'DController#show')->middleware('auth');
and have it fire both of your other methods:
public function show() {
// decide what to return
$xValue = $this->showX();
return $this->showY($xValue);
}
protected function showY($y){
$name=Auth::user()->name;
return view('dashboard',['name' => $name, 'y' => $y]);
}
protected function showX(){
$y= Y::all();
}

call model relation function in controller laravel

In my Model I have the function
App\Akte.php
public function lvs() {
return $this->hasMany('App\lvs', 'lv_id');
}
In my Controller I call
public function index()
{
$aktes = \App\Akte::all();
return view('admin.akte.index', ['aktes' => $aktes]);
}
And i´d like to extend my collection $aktes with the lvs table. Can somebody explain how to do this?
So my result should be a collection in which every single element of "Akte" has its Many collections of lvs in it..
If you also want the relationship loaded, just use:
$aktes = \App\Akte::with('lvs')->get();
See that. May be usefull for your needs.
https://laravel.com/docs/5.7/eloquent-relationships
public function index()
{
$aktes = \App\Akte::->all()->where('lvl', 2);
return view('admin.akte.index', ['aktes' => $aktes]);
}
somthing like this ...

Is it possible to add data to view data from controller constructor

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!

Why view::make doesn't work when called from a different function in controller?

This is a fairly simple question, and I made this work in other controllers, but I don't seem to be able to figure out what's exactly going on in this specific case, and why it's not working.
I have this two functions in my controller:
public function create(Request $request)
{
//
$this->edit($request, null);
}
public function edit(Request $request, Group $group = null)
{
//
return View::make('groups.create')
->with('controllerUrl', $this->controllerUrl)
->with('record', $group);
}
In this example the create function sends me to a blank page.
This is my route:
Route::group(['middleware'=>['web', 'CheckWritePermission']], function ()
{
Route::resource('some_model', 'SomeModelController');
Route::resource('model', 'ModelController');
Route::resource('groups', 'GroupController');
});
For some reason doing it like this in other controllers works, and for some other it doesn't in this case.
I'm very confused as to why this is, because doing it like this works just fine.
public function create(Request $request)
{
//
// $this->edit($request, null);
return View::make('groups.create')
->with('controllerUrl', $this->controllerUrl)
->with('record', $group);
}
I just want to understand why in some cases it works and in others it doesn't.
You are missing a return statement
return $this->edit($request, null);
your edit method does return something, but your create method doesn't, therefore page stays blank

Laravel Object Oriented

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.

Categories