Laravel: When call function from another controller, the relationship query not work - laravel

I have two controllers (FirstController, SecondController) that use the same functions, to avoid rewriting them I thought of creating another controller (ThirdController) and subsequently calling the functions through it.
the problem is that if in ThirdController there are relationship query they give me the error that "they don't exist".
example:
User Model
class User extends Authenticatable implements AuthenticatableUserContract
{
use HasFactory, Notifiable;
public function comments(){
return $this->hasMany('App\Models\Comment');
}
ThirdController
class ThirdController extends Controller
{
public static function example($id){
$comments = Comment::find($id)->comments();
return $comments;
}
}
FirstController/SecondController
public function example2(Request $request){
return ThirdController::example($request->id);
When call the route it give me error:
BadMethodCallException: Method Illuminate\Database\Eloquent\Collection::comments does not exist.
my questions are:
Is there any better method instead of creating a third controller?
Is there a solution to this?
p.s. I know I could very well build the queries without exploiting the relationship, but where's the beauty of that? :D

You do not need to create 3rd controller. You can create a class and here you write the query in a function and use this class in controller1 and controller2 by dependency injection.

First thing that's not a best practice to define a static method in one controller and call it in another controller (not recommended way).
Second you're calling Comment::find($id) with comments() relation. you should call a User class, like below snippet:
class ThirdController extends Controller
{
public static function example($id){
$comments = User::find($id)->comments();
return $comments;
}
}
RECOMEND APPROACH:
Creat a one seperate service/repository class in which you'll define a common method i.e. getUserComments() and use it in both or all of three controllers (upto your requirement/needs). By this way you implementations will be on a centric place.
If you want learn about Repository pattern you can get basic idea from: Article#1

Related

Where should I be saving a model in Laravel MVC?

I'm trying to get a more concrete understanding of MVC and keeping the controller layer as thin as possible.
One thing I keep asking myself is "Where should I call modelname->save()?"
Looking at the Laravel documentation, they set data to the model and call save in the controller which doesn't seem right...
<?php
namespace App\Http\Controllers;
use App\Flight;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
class FlightController extends Controller
{
public function store(Request $request)
{
// Validate the request...
$flight = new Flight;
$flight->name = $request->name;
$flight->save();
}
}
This is quite a simple example and might be why they do it all in the controller.
From my understanding and everything I've been reading, all business logic should sit inside the model, the controller is responsible for "traffic control" between the view and the model.
So would I be calling save inside the model itself? or should I be using a service layer?
Here is my current problem with example data.
I am updating the status of a model. The row already exists in the DB. I use PATCH /route/ to get to the controller method. From there I get the model.
class TimecardController extends Controller {
...
public function markAsPass(Request $request, $id) {
$test = Test::findOrFail($id);
//I don't think this is the corect way
//$test->status = "passed";
//$test->markedBy = "Teacher123";
//$test->save();
$test->passed();
...
return redirect($redirect_url);
}
}
class Test extends Model {
...
public function passed() {
$this->status = "passed";
//would I call save here?
//$this->save();
}
}
Do I take an approach like above? Or do I create a service layer where I would use the model instance to call the model functions and then call save on the model?
//in service class
public function makeTestAsPassed($test){
$test->passed();
$test->save();
}
Please let me know if any claification is needed.
You’re right in that business logic belongs in models. If you take a “resourceful” approach to your applications (in that you create controllers around entities) then you’ll find that your controller actions seldom call more than one model method.
Instead of calling save(), you can call create() and update() methods on your model. In your store() controller action, you can create a new entity with one line like this:
public function store(CreateRequest $request)
{
$model = Model::create($request->all());
}
And update an existing model in an update() action like this:
public function update(UpdateRequest $request, Model $model)
{
$model->update($request->all());
}
When it comes to business logic, you can call other methods on your models, too. To use resourceful controllers, you don’t have to have a model that relates to a database table.
Take shipping an order. Most people would be tempted to put a ship() method in an OrderController, but what happens when you ship an order? What entity could shipping an order result in? Well, you’d be creating a shipment, so that could instead be a store() method on an OrderShipmentController. This store() method could then just call a ship() method on your Order model:
class OrderShipmentController extends Controller
{
public function store(ShipOrderRequest $request, Order $order)
{
$order->ship();
}
}
So as you can see, with resourceful controllers and route–model binding, you can have “skinny controllers” with your application’s business logic living in your models.
MVC is designed for ease of maintenance.
The approach you don't recognize as "good" is the proper approach. All data handling related to business logic goes in the controller. Otherwise, a different coder will be confused as he/she would not find the data manipulation logic in the controller code.
Your thin controller goal defeats MVC.
Also note the model code is purposed to be thin as it is a place to define the database schema as mirror image to the database tables.
MVC is not object oriented abstration. MVC is a structure for code maintenance uniformity.

Pass object in all methods of all controllers in Laravel

I have this code in the HomeController#index:
$towns = Town::all();
return Redirect::to('home')
->with('towns', $towns);
Is there any way I can tell Laravel to execute that lines of code before the end of methods and controllers I define without me copying and pasting those lines of code in every method?
You don't need to do that, you can just share this data with all views by using the view()->share() method in a service provider:
view()->share('towns', Town::all());
You can also use a view composer for that:
public function compose(View $view)
{
$view->with('towns', Town::all());
}
You can extend all controllers from your basic controller. Use Controller.php on app/Http/Controllers/controller.php or create new one.
Add myThreeLines to base controller.
controller.php:
function myThreeLines(){
$towns = Town::all();
return Redirect::to('home')
->with('towns', $towns);
}
class TestController extend Controller{
function index(){
return $this->myThreeLines();
}
}

Laravel - Running method of another controller in one controller

I have UserController and PetController.
In my UserController, I have rewardUser() method.
in my PetController, I'm using the $user variable which indicates the current logged in user.
How I can run my rewardUser() method from my PetController?
I've been trying to user $user->rewardUser(); but for some reasons its not recognizing my method this way.
"Call to undefined method Illuminate\Database\Query\Builder::rewardUser()"
The best way is to use a trait.
Create a trait file, in App\Common.php, for e.g. Then copy the rewardUser() method to the trait.
Your trait file:
namespace App\Forum;
trait Common {
public function rewardUser() {
// Your code here...
}
}
Then in yourUserController.php and PetController.php, use the trait.
// UserController and PetController.php
namespace App\Http\Controllers
use App\Common; // <- Your trait
class UserController extends Controller {
use Common // <- Your trait
public function doSomething() {
// Call the method from both your controllers now.
$this-rewardUser();
}
}
You can use the straight in as many controllers as you want and you can call the method in the straight using $this->methodName().
Very simply and effective.
It seems like you are missing some structure concepts, but if you really need it, you may use the container to do so:
$userController = app()->make(UserController::class);
return app()->call([$userController, 'rewardUser']);
may be you should define the method rewardUser() in the User Model and import it with use App\User

Loading classes only if function is called

I have one FrontendController that get all requests from frontend. As all URLs are like:
Route::get('/{slug}', 'FrontendController#index');
I need to use the same controller to get all Entities. My FrontendController looks like this:
use Auth;
use App;
use Cache;
use URL;
use Redirect;
use Session;
use Response;
use App\Country;
use App\I18n;
use App\User;
use App\CMS;
use App\CMSPageContent;
use App\Slugs;
use App\News;
...
...
use App\Http\Controllers\Controller;
I have several questions regarding this:
Are ALL these services injected in each execution of FrontendController. Because maybe I'm loading the entire code and It will make my page load slow.
If answer to previous question is yes, can I load a library only if one function is called?
Is it a good way to solve the slug problem? Because all URLs have one piece only for SEO reasons and I don't know other way to treat the routes.
It varies depending on how you are using the code. For example if you required the Auth login method, but nothing else, it would be a waste of resources to initialise a model or inject the model into that function.
For example say this is a function in my model
public function doSomething()
{
//Do stuff
}
I would like to call this function in my Controller. I have a few options, I could reference the model at the top of my controller
use App\MyModel;
I believe this doesn't actually initiate the model, it acts like a reference, so that when it is called, the system knows where to find it.
I could inject it into my function
public function myControllerFunction(\App\MyModel $model)
{
return $model->doSomething();
}
This uses the most resources due to the model being assigned to the $model variable, which is fine if you need the models eloquent for database actions and its functions. If you require just one function from that model then a static call would use less resources.
In your model make the function static
public static function doSomething()
{
}
Then in your controller you can call it like this
public function myControllerFunction()
{
return \App\MyModel::doSomething();
}
This would use the less resources and would clean up the code a bit as you wouldn't need to keep referencing your uses at the top of the controller

Access an object of one class in other codeigniter

I have two controller classes in my codeigniter application, say class A and B.I just want to create an object of class A and access the functions declared in class A from class B.Something like:-
class A extends someclass
{
public function function1(){
$this->load->view('welcome_message');
}
}
}
class B extends someclass2
{
protected $object;
public function __construct()
{
parent::__construct();
$this->objectA = new A();
}
}
}
I want to access the function function1 from class B using the object objectA. How can i do this?
Please help.
Thanks
well actually this is not the proper way in codeigniter. Actually when you have common functions in and you want to use them in 2 or more controllers. The best way is to create base controller in core folder with name of MY_Contoller and extend it from CI_Contoller. Write your common function in MY_Contoller. Now you have to extend all your controllers from MY_Contoller instead of CI_Contoller. You can do the same with Model.
Cross-controller access goes against CI best practice.
Either inherit both controllers from a controller that holds this common functionality (don't forget to prefix the function with '_' so it's inaccessible via url routing) or create a library that contains your re-usable functionality. A helper can also work.

Resources