Laravel 5.5 MassAssignmentException - php

I'm following the Laravel From Scratch tutorial series, I'm currently at the part that you are creating a comment system for your articles system. But I'm having a problem, I don't really know what the error is saying at this point.
The error:
Illuminate\Database\Eloquent\MassAssignmentException
body
The comment model:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Comment extends Model
{
public function post()
{
return $this->belongsTo(Post::class);
}
}
The post model:
<?php
namespace App;
class Post extends Model
{
public function comments()
{
return $this->hasMany(Comment::class);
}
public function addComment($body)
{
$this->comments()->create(compact('body'));
}
}
The route I made:
Route::post('/posts/{post}/comments', 'CommentsController#store');
The comments controller:
<?php
namespace App\Http\Controllers;
use App\Post;
class CommentsController extends Controller
{
public function store(Post $post)
{
$post->addComment(request('body'));
return back();
}
}
Thanks in advance!

Explanation of this error
This is a security feature of Laravel. It is designed to protect you against form manipulation when using mass assignments.
For example on a sign-up form: When you have an is_admin column in your database, a user simply could manipulate your form to set is_admin to true on your server, and therefore in your database. This security feature prevents that by using a whitelist to define safe fields.
How to fix that
You need to set a $fillable property on your model. It's value must be an array containing all fields that are safe to mass assignable (like username, email address, ...).
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Comment extends Model
{
# This property!
protected $fillable = ['body'];
// ...
}
See "Mass assignment" in the docs:
https://laravel.com/docs/5.5/eloquent#mass-assignment

Mass assignment is when you send an array to the model creation, basically setting a bunch of fields on the model in a single go, rather than one by one, something like what you did here:
public function addComment($body)
{
$this->comments()->create(compact('body'));
}
You need to add the field you are populating to the fillable array in Comments.php model:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Comment extends Model
{
protected $fillable = ['body'];
public function post()
{
return $this->belongsTo(Post::class);
}
}
As the documentation states:
You may also use the create method to save a new model in a single
line. The inserted model instance will be returned to you from the
method. However, before doing so, you will need to specify either a
fillable or guarded attribute on the model, as all Eloquent models
protect against mass-assignment by default.
Hope this helps you.

Related

Laravel Eloquent Relationship with different foreign key

Laravel version is 7.0:
I have setup model relationships like this.
<?php
namespace App;
class Template extends Model
{
protected $fillable = ['header_id', 'content', 'name'];
public function header()
{
return $this->belongsTo('App\Header', 'header_id');
}
}
In controller I can get template object with header.
<?php
namespace App\Http\Controllers;
use App\Template;
class TemplateController extends Controller
{
public function show($id)
{
$template = Template::find($id);
}
}
Now I can use $template->header in view.
How can I pass different header_id and get header relationship object?
I would like to do as following:
<?php
namespace App\Http\Controllers;
use App\Template;
class TemplateController extends Controller
{
public function show($id, $temp_header_id)
{
$template = Template::find($id);
$template->header_id = $temp_header_id;
}
}
I want to get new header relationship in view:
Is there any way to return new header relationship when I do $template->header in view.
Thank you
Yes you can do what you are looking to do, but kinda defeats the relationship in the database. You can assign any id to $template->header_id and then load the relationship using that new value:
$template->header_id = 897;
// load the relationship, will use the new value
// just in case the relationship was already loaded we make sure
// to load it again, since we have a different value for the key
$template->load('header');
$template->header; // should be header with id = 897

How to attach a relationship directly on an object?

I don't know if I formulated the question correctly, but whatever.
So when I use the "store" method on my controller, I send two fields, "name" and "fr", both in the same request.
In my controller, I want to be able to create my Model (Room) and attach its relationship to it (RoomTranslation). When I try the following code, it tells me I didn't provide the room_id. Is there an automatic way to achieve this ?
public function store(RoomRequest $request)
{
$request = $request->validated();
$room = new Room;
$room->create($request);
$room->translations()->create($request);
return success('');
}
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class RoomTranslation extends Model
{
protected $fillable = ['fr', 'room_id'];
public function room() {
return $this->belongsTo('App\Room');
}
}
<?php
namespace App;
use Illuminate\Http\Request;
use Illuminate\Database\Eloquent\Model;
use App\RoomTranslation;
class Room extends Model
{
protected $fillable = ['name'];
public function categories() {
return $this->hasMany('App\Category');
}
public function translations() {
return $this->hasOne('App\RoomTranslation');
}
}
Thank you for your help !
P.S. : If there is a cleaner way to write this part of my code, I will be happy to hear how I can improve it.
Thank you !
You can do this:
Room::create($request->only(['name']))->translations()->create($request->only(['fr']));
just look for typo or input names to be correct.
Also in Room model class translations relation if you have multiple languages for every Room should be hasMany, And if you don't have many translations per Room you could just add a column for translation language.

How can I use laravel Auditor in controller

I used laravel Auditor in a model and it works very well as following:
use Illuminate\Database\Eloquent\Model;
use OwenIt\Auditing\Contracts\Auditable;
class Contracts extends Model implements Auditable
{
use \OwenIt\Auditing\Auditable;
protected $fillable=['condatereceived'];
public function user()
{
return $this->belongsTo(User::class);
}
}
But I want to used it in the controller as :
public function updatecomplated(Request $request, $id,Contracts $contract ,Auditor $auditor)
{
Contracts::where('id', $id)
->update(['complated' => 50, 'conuploadby' => Auth::id(),'constatus' =>'Need To Active' ]);
if ($audit = $auditor->execute($contract)) {
$auditor->prune($contract);
}
return redirect()->back();
}
The code in controller give me error:
Call to undefined method OwenIt\Auditing\Facades\Auditor::execute()
any ideas to use auditor in the controller, please.
try this package its easy with good documentation
simply add this to your table
$table->auditable();
and this to your model
namespace App;
use Yajra\Auditable\AuditableTrait;
class User extends Model
{
use AuditableTrait;
}
thats it now simply get your auditor by calling
$user->creator // for who create
and
$user->updater //for who update data
for more information click here for check trait
Hope this helps

How to get all data from two related tables in Laravel [one to many]

I am pretty new in Laravel and need write a simple backend API.
I am doing smething wrong and I dont know what, because I get some of data from Suppliers table and empty array payments:[ ].
I am trying to get all data from two related tables - PAYMENTS and SUPPLIERS.
It`s a one to many relation SUPPLIERS_ID in PAYMENTS table is connected with ID in SUPPLIERS. Here I give You a graphic representation:
Here`s my code:
Suppliers.php model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Suppliers extends Model
{
public function payments()
{
return $this->hasMany('App\Payments');
}
}
Payments.php model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Payments extends Model
{
public function suppliers()
{
return $this->hasOne('App\Suppliers');
}
}
PaymentsController.php
use App\Payments;
use App\Suppliers;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
class PaymentsController extends Controller
{
public function index()
{
$payments = Suppliers::with('payments')->get();
return response($payments, Response::HTTP_OK);
}
}
And i get the following answear:
[{"id":1,"name":"Ekonaft","adress":"33-100 Tarnow ","email":"ekonaft#gmail.com","payments":[]},
{"id":2,"name":"Orlen","adress":"Ares testowy","email":"email#email.pl","payments":[]}]
What I`m doing wrong that I get te empty array payments:[ ] on the end of each object?
Try the inverse relationship on payments
belongsTo = has a foreign key to another table
Quoting an example
Should i use belongsTo or hasOne in Laravel?
This is how you can access suppliers from Payments
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Payments extends Model
{
public function suppliers()
{
return $this->belongsTo('App\Suppliers');
}
}
This is payments from suppliers
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Suppliers extends Model
{
public function payments()
{
return $this->hasMany('App\Payments','suppliers_ID','id');
}
}
Also, make sure the id's are visible on the output (if id's are hidden, laravel can't work with the relationship). You can also specify the keys on the relationship if you want to use hasOne
Edit: add the keys names within the relation, your fk naming is in capslock
Change you relations like bel
Suppliers.php model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Suppliers extends Model
{
public function payments()
{
return $this->hasMany(App\Payments::class, 'suppliers_ID', 'id');
}
}
Payments.php model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Payments extends Model
{
public function suppliers()
{
return $this->belongsTo(App\Suppliers::class, 'suppliers_ID', 'id');
}
}
then try again..... :)
You are getting empty array of payments:[] due to miss-matching table relationship key name.
Please, make few changes in both relational function.
public function payments()
{
//return $this->hasMany('App\Model', 'foreign_key', 'local_key');
return $this->hasMany('App\Payments', 'suppliers_id');
}
public function suppliers()
{
//return $this->belongsTo('App\Model', 'foreign_key', 'other_key');
return $this->belongsTo('App\Suppliers', 'suppliers_id');
}
You can learn more about eloquent relationship directly from Laravel documentation for better understanding. https://laravel.com/docs/5.7/eloquent-relationships#one-to-many
Let me know if you still getting same error.

Load extra table/data into user object

In Laravel 5.6 I'm trying to load data into the user object, so I can view user credentials/settings etc.
Whats annoying is I had it working, but for some reason now It seems to have stopped, and I'm not sure what I've changed to break it.
Anyway I want to load two tables, access and settings. Both of them have user_id field in there with the corresponding user_id in.
In my User.php class I have two functions:
public function access() {
return $this->hasMany(Access::class);
}
public function settings() {
return $this->hasOne(Settings::class);
}
I am not Use-ing them at the top of the class (i.e. use \App\Access) if that makes any difference.
And then the Access class looks like:
namespace App;
use Illuminate\Database\Eloquent\Model;
class Access extends Model
{
protected $table = "access";
}
And the Settings class is very much the same:
namespace App;
use Illuminate\Database\Eloquent\Model;
class Settings extends Model
{
protected $table = "settings";
}
However whenever I try and access Auth::user()->settings or Auth::user()->access I get undefined index: error. It's frustrating because like I said I had it working the other day and I'm not sure what's changed.
Few things you could try here. First, Lazy Eager Load the relationships by loadMissing:
// settings
Auth::user()->loadMissing('settings');
// access
Auth::user()->loadMissing('access');
To load a relationship only when it has not already been loaded, use the loadMissing method
Second, you can use with when querying for a user, although it's not as relevant with using the auth facade:
User::with(['settings', 'access'])->where('atribute', $value)->get();
Last, if you always want the settings and access relationships to always be returned with each user model, set the with attribute on the user model:
public class User {
protected $with = ['settings', 'access'];
...
}
I usually define the inverse relationships on models as well, so Access and Settings would have a BelongsTo relationship defined:
class Access extends Model
{
protected $table = "access";
public function user() {
return $this->belongsTo(User::class);
}
}
class Settings extends Model
{
protected $table = "settings";
public function user() {
return $this->belongsTo(User::class);
}
}

Categories