Laravel calling model from controller? Is this the right approach? - laravel

I am trying to split some code and let model handle all database stuff, such as create, retrieve etc.
At the moment all of that code was in the controller and I quickly realized that code is very messy so instead I wanted to do something like this:
public function incompletedEntity(EntityRequestPartial $request)
{
$partial_entity = EntityTrash::saveEntity();
}
And my model:
public static function saveEntity(Request $request)
{
$entity = new EntityTrash();
$entity->lat = $request->input('lat');
$entity->lng = $request->input('lng');
$entity->slug = $request->input('name');
$user_id = Auth::id();
$entity->name = $request->input('name');
$entity->type = $request->input('type');
$entity->email = $request->input('email');
$entity->tags = $request->input('tags');
$entity->slug = $user_id;
$entity->building_name = $request->input('building_name');
$entity->address = $request->input('address');
$entity->town = $request->input('town');
$entity->postcode = $request->input('postcode');
$entity->telephone = $request->input('telephone');
$entity->save();
}
However, I cannot call that function because I am not passing an argument from the controller, what is the right approach for this? Should I do $request->input in controller and assign it to an array maybe? and deal with it in the controller?

If you wish to split out the code so that controllers don't touch models, I would recommend that you look into the repository pattern.
The idea behind this would be that in your controller you have
$this->entityRepository->create($data);
You could either pass in an array, or each individual property
$this->entityRepository->create($lat, $lng, $name, $type..etc);
This way, your controller can retrieve all of the data and validate it.
$data = $request->only(['lat', 'lng', 'name', 'type', 'email', 'tags', ..etc]);
$validator = Validator::make($data, ['name' => ['required']]);
Obviously you can use request validation or whatever you're comfortable with.
This way, your controller is responsible for receiving data and validating it. It can then pass it on blindly to the repository knowing that it is valid, and trusting that the repository will do its job.
As a side note, I highly recommend that you do not have your models interact with the Request object directly. The Illuminate\Http\Request class belongs to the HTTP layer, and the model belongs to the persistence layer. These two layers should never know of the existence of the other.

Generally speaking, your model should never depend on the Request object. Models can be used for any access of a database, or other storage area. Many of those access points may not be HTTP at all.
Your HTTP controllers should always be used to pass information from an HTTP request to a deeper layer of your application (e.g. a Model). So if you are using the Request object anywhere, it should be in your HTTP controllers.
I think it's important for you to review why the controller layer is there and why we don't just have Models and Views.

I would recommend you to take a look at the official Laravel Documentation first: https://laravel.com/docs and the Controller / Eloquent Model chapters. Moreover, Adam Wathans talk Github from the current Laracon is a good read for further refactoring.
First, make use of the CRUD pattern from the Laravel Controller in addition with the Eloquent Model. Then pass the validated data to your model via the create/save method.
<?php
namespace App\Http\Controllers;
use App\EntityTrash;
use App\Http\Controllers\Controller;
class EntityTrashController extends Controller
{
public function create(EntityRequestPartial $request)
{
return EntityTrash::create($request->only(['lat', 'lng', 'name', 'type', 'email', ...]));
}
}
Finally, maybe the repository pattern can improve your code as well.

Related

Where to save different models at once in Laravel?

I have a litte question for you.
I'm using Laravel and I'm not sure which is the best way (and place) to save different models at same time.
For example:
When a user creates a "RecordSheet", I need to automatically create other models related to the RecordSheet model. Obviously I will create the RecordSheet model in his own controller:
class RecordSheetController extends Controller
{
public function store(){
RecordSheet::create([
.......
'user_id' => Auth::user()->id
]);
}
}
Where should I put the creation of the other models? In the same RecordSheetController?
class RecordSheetController extends Controller
{
public function store(){
DB:beginTranaction()
try{
$record = RecordSheet::create([
.......
'user_id' => Auth::user()->id
]);
ModelB::create([
.......
'recordSheet' => $record->id,
'user_id' => Auth::user()->id
]);
}catch(Exception $e)
{
DB:rollback();
}
DB:committ();
}
}
I'm not sure about thate since I suppose that RecordSheetController should be responsible only of "RecordSheet" models and not other models.
Any suggestion would be appreciated! Thanks everyone!
you can use Laravel Observers for this scenario, create a RecordSheetObserver and place your ModelB code in the created method
Laravel provides some built-in conventions for placement of your action or CRUD (Create - Read - Update - Delete) code.
Typically, you can put the related model action in the same method. To start, you can utilise the artisan command:
php artisan make:controller RecordSheetController --resource
This will add the standard methods to your controller. These methods tie into any resource methods you have in your routing, which follow standards for GET/POST/PUT/etc.
Once you have your controller set up, it is usually easiest and most readable to do your related action within the same method, so you don't have to go back and forth with the user from page to controller and back again. So:
public function store(Request $request){
// Add transactions as you wish
$record = RecordSheet::create([
.......
' user_id' => Auth::user()->id
]);
ModelB::create([
.......
'recordSheet' => $record->id,
'user_id' => Auth::user()->id
]);
}
You can certainly make sub functions within this, but the key is to perform this at one time for efficiency. If there are many repeatable sub functions with less related actions, it may be helpful to move this to other parts of your app. But for simple, directly related creation, it tends to be more readable to keep them in the same class.

How to handle json request in laravel controller?

I'm using JSON request to get nation detail in my view, here is how I am doing it;
Controller:
public function ajaxrequest(Request $request)
{
$nations = Nation::all()->pluck('nation', 'id');
return response()->json($nations);
}
now I want to access data from Area table, I will have to create another controller? or I can add that in the above controller? I have 10 different tables like nation from where I want to get data through JSON. but I am not sure whether I can do everything in a single controller.
It all depends how do you want to access data and yes you can fetch data from one controller only if it's needed.
Also you can check it based on the request
EXAMPLE :
public function ajaxrequest(Request $request)
{
$check = $request->get('something_to_check");
if($check){
$data = Table1::all()->pluck('id');
}else{
$data = Table2::all()->pluck('id');
}
return response()->json([
'data' => $data,
//...
]);
}
Like #ViperTecPro mentioned, you can access multiple tables from the same method in a controller but if possible you should have separate endpoints for each case to you get rid of multiple if checks.
Just a thought.

What is $model in Yii2?

I'm new to MVC and Yii Framework. The $model variable seems very confusing to me.
Where is it declared in the fist place? Where does it come from?
When I work with GridView I see that some functions take $model as a parameter. Neither model nor model search of this GridView declares $model variable anywhere. Yet it is widely used in all sorts of data management. It just doesn't make sense to me.
So I need a simple, straight forward, "for dummies" explanation of $model variable in Yii Framework v2. Help in clarifying these questions is much appreciated:
1. What is the origin of $model variable?
2. How to identify what model of the app is the $model variable representing when it's used in view files?
3. There are sometimes multiple $model variables in a single view file. Do all of them represent one model class? How to distinguish them when used for multiple classes?
Thanks.
If you are unsure where $model, $searchModel and other variables come from, you are most likely searching for them on the view file where they are used.
They are created on the controller that renders said view, just like any other object/variable.
From the controller, you can render a view and pass objects/variables the following way:
// MyController.php
...
public function actionMyAction($id) {
// Create and manipulate $model and $searchModel
...
/*
* First param is the name of the view to be rendered
* Second param is an Associative Array with params
* that will be made available to the view.
*/
return $this->render('my-view-name', [
'model' => $model,
'searchModel' => $searchModel,
]);
}
The $model is a var as the others ...normally in the yii2 samples contain an instance of a model class (as tiplically an active record=)
assuming you have a class
class Category extends \yii\db\ActiveRecord
{
........
a tipical code could be
$model = Category::findOne($id);
where Category::findOne($id) find an instance form database using $id as primary key and assign the result to $model ..
then you can access to the instance attribute (eg:attribute1) using
$model->attribute1
you can take a look at this guide
http://www.yiiframework.com/doc-2.0/guide-index.html
http://www.yiiframework.com/doc-2.0/guide-structure-models.html
http://www.yiiframework.com/doc-2.0/guide-db-active-record.html

Model returns relation´s dynamic attributes but null relation

I have set 2 models (Post and Category) with it´s proper relationships configured
class Post extends Model
{
protected $fillable = [
'title',
'excerpt',
'body',
'featured',
'published',
'category_id',
];
public function category()
{
return $this->belongsTo('App\Category');
}
}
class Category extends Model
{
protected $fillable = [
'name',
];
public function posts()
{
return $this->hasMany('App\Post');
}
}
And my Post´s storing method is
public function store(Request $request)
{
$post = Post::create($request->all());
return redirect('admin/posts');
}
The thing is, it´s actually working ok, it sets the category_id on the table and I can fetch all the dynamic data by using $post->category->name, but when I var_dump($post->relation) I get a null return.
I if create a new Post model, set all the attributes, save it and then associate the Category model (as documented on the official channel), it will return everything as expected.
For now, all I need is to fetch it´s dynamic attributes, and it´s working fine now, but I know I must be doing something wrong to get the null response. My concern is that it may be working fine now, but when the project gets larger I´ll probably face a bigger problem and I´ll have a lot of work to fix this issue.
The relation isn't there because you haven't loaded it. All it knows is the foreign key. It would be wildly inefficient if it grabbed all that information for you because it wouldn't always need all that. Think of instances where a single model could have many relationships, that would be many database calls for no reason.
If you need the relation, you can use $post->category. Since the relation is not yet loaded, it will get it for you when you do this.
Or you can eager load it by using the following $post->load('category') although this doesn't really benefit you because you are working with a single Post at this point. If you had a collection of Post objects, then you'd start seeing the benefits of using $posts->load('category') otherwise you end up with the n + 1 problem.
Consequently, if you use $post->load('category') and then var_dump($post), you should see that the relation is no longer null.

Code Igniter Models & libraries

in CI i created a model called "User" which has a method called "entries" and another one called "books"
I would like to pass a $user_id parameter to the model so it creates an instance of the class in my controller.
the way I currently call the model in the controller is :
$data1 = $this->user->entries($user_id);
$data2 = $this->user->books($user_id);
I would like to pass that user_id parameter directly to the constructor so that i dont have to use the $user_id parameter each time
perhaps something like this ( i know the syntax is wrong in this case):
$this->load->model('user',$user_id);
$data['row1'] = $this->user->entries();
$data['row2'] = $this->user->books();
Please forgive my lack of understand of OOP ..i just made the switch.
thanks for your help
You cannot pass variables to the constructor, but you could make a method to set the userID, and then use it.
Example:
class user extends CI_Model{
var $user_id;
function __construct(){
parent::__construct();
}
function set_user_id($user_id){
$this->$user_id = $user_id;
}
}
And then inside your entries and books books method, you can use $this->$user_id, without needing to pass it again.
Like so:
function entries(){
$user_id = $this->user_id;
}

Resources