Passing data from controller into Model in Laravel - laravel

I have this comment controller:
class CommentsController extends Controller
{
public function store(Article $article){
$comment = new Comment();
$comment->user_id = auth()->id();
$comment->comment = request('comment');
$comment->article_id = $article->id;
$comment->save();
return back();
}
}
And it works. I tried to make my code cleaner by putting that logic into my model. So I changed it like this:
class CommentsController extends Controller
{
public function store(Article $article){
$article->addComment(request('comment'));
return back();
}
}
Meanwhile, in my Comment Model I'm doing like this:
class Article extends Model
{
protected $fillable = ['title','content','user_id'];
public function comments(){
return $this->hasMany(Comment::class);
}
public function user(){
return $this->belongsTo(User::class);
}
public function addComment($comment){
Comment::create([
'comment' => $comment,
'article_id' => $this->id,
'user_id' => auth()->id()
]);
}
}
but when I do this, I'm getting this kind of error:
"SQLSTATE[HY000]: General error: 1364 Field 'user_id' doesn't have a default value (SQL: insert into `comments` (`comment`, `article_id`, `updated_at`, `created_at`) values (Test comment bla bla bla..., 1, 2017-10-16 09:27:27, 2017-10-16 09:27:27)) ◀"
It seems I can't get the user_id in that manner, so how can I pass the user id so i can insert it into my comment tables? Thanks.

You need to add user_id to $fillable array in Comment model, not in Article model to make it work. Your original code works just because you do not use mass assignment there.

Try this:
public function addComment($comment){
Comment::create([
'comment' => $comment,
'article_id' => $this->id,
'user_id' => \Auth::user()->id
]);
}

try
\Auth::id()
instead of
auth()->id()
and go to your database and and make user_id default as NULL
The reason for this kind of error is that laravel protects database fields for mass assignment when you add the following code it makes all fields fillable.
protected $guarded = [];
Another way of doing is to add user_id in comments model. Is this case it will only allow the fields mentioned in the array to be mass assigned.
protected $fillable = [
'user_id'
];

Related

How to create a data associatively? laravel eloquent

I have a Post model:
class Post extends Model
{
protected $fillable = [
'title',
'user_id',
'token',
'body'
];
public function favorites()
{
return $this->hasMany(Favorite::class);
}
public function addFavorite($state = 1)
{
$this->favorites()->create(compact('state'));
}
}
Favorite model:
class Favorite extends Model
{
protected $fillable = ['user_id', 'post_id', 'state'];
}
When I test in tinker:
$post = Post::first();
$post->addFavorite();
It returns me an error below:
Illuminate/Database/QueryException with message 'SQLSTATE[HYOOO]: General error: 1364 Field 'user_id' doesn't have a default value (SQL: insert into favorites...
Why it ask user_id when it is given in the post? Question is do I necessarily need to input the user_id to achieve this?
The question of whether user_id is necessary is up to you. Will it come in handy later on? Does having it on the posts table suffice?
It is asking for user_id because you do not have a default value field on that field in the favorites table. You can either set a default value, remove it from the table (if you decide you don't need it), OR provide it when creating via the relationship:
class Post extends Model
{
protected $fillable = [
'title',
'user_id',
'token',
'body'
];
public function addFavorite($state = 1)
{
$this->favorites()->create([
'state' => $state,
'user_id' => $this->user_id,
]);
}
public function removeFavorite()
{
$this->addFavorite(0);
}
}
Don't forget to include the relationship definition of favorites on the Post model.
Based on the plural name, it seems that a post has many favorites, but then your removeFavorite() method calls the addFavorite method?? This would not actually remove anything - it would create a new record.
Since Favorite model is related to Post model and you create it via relation()->create(), you can skip specifying post_id as Laravel can deduce it. But you do have to specify user_id, because there's no way for your code to know that favourite.user_id and post.user_id is the same. So in short: yes, you have to specify user_id.

Update fields from two tables in Laravel

I have 2 models: customer and customerName. In my customer Controller I try to create a method that update fields from both tables. Any idea? Thanks!
CustomerController
public function update(Request $request, Customer $customer)
{
$customer = \App\CustomerName::where('customer_id', $customer->id)->first(); // if I remove this line I can update just "name" from first table
$data = $request->validate([
'name' => 'required|string', //is in customer migration
'first_name'=> 'required', //is in customerName migration
'last_name'=> 'required', //is in customerName migration
]);
$customer->update($data);
return response($customer,200);
}
Customer Model
class Customer extends Model
{
protected $fillable = ['name'];
public function customerName()
{
return $this->hasOne('App\CustomerName');
}
}
CustomerName Model
class CustomerName extends Model
{
protected $fillable = ['first_name', 'last_name'];
public function customer()
{
return $this->belongsTo('App\Customer');
}
}
Assuming customer always has record created for CustomerName, you should then use:
$customer->update(['name' => $data['name']);
$customer->customerName->update(\Arr::only($data, ['first_name', 'last_name']));
and additionally you should wrap this in database transaction like so:
\DB::transaction(function() use ($customer, $data) {
$customer->update(['name' => $data['name']);
$customer->customerName->update(\Arr::only($data, ['first_name', 'last_name']));
});
and of course you should remove this line:
$customer = \App\CustomerName::where('customer_id', $customer->id)->first(); // if I remove this line I can update just "name" from first table
because you should already have $customer object set using Route model binding.
Take a look at your code. You're overriding some variables by naming them the same thing:
public function update(Request $request, Customer $customer)
{
$customer = \App\CustomerName::where('customer_id', $customer->id)->first();
...
Before the line $customer = \App\CustomerName..., $customer is an instance of Customer. After that line, it is an instance of CustomerName, and you no longer have access to the Customer instance. Simply change you naming:
public function update(Request $request, Customer $customer)
{
$customerName = \App\CustomerName::where('customer_id', $customer->id)->first();
// Or, $customerName = $customer->customerName;
// You shouldn't have to query if your relationship is defined properly.
...
Next, save the values accordingly:
$customer->name = $request->input("name"); // or $data["name"]
$customer->save();
$customerName->first_name = $request->input("first_name"); // or $data["first_name"]
$customerName->last_name = $request->input("last_name"); // or $data["last_name"]
$customerName->save();
Set the values of $customer and $customerName accordingly, then call save() on both instances.
You're injecting the Customer instance, so you don't need to load it inside the function. Try this:
public function update(Request $request, Customer $customer)
{
$data = $request->validate([
'name' => 'required|string', //is in customer migration
'first_name'=> 'required', //is in customerName migration
'last_name'=> 'required', //is in customerName migration
]);
$customer->name = $data['name'];
$customer->customerName->first_name = $data['first_name'];
$customer->customerName->last_name = $data['last_name'];
$customer->push(); // This saves the model AND the related models as well.
return response($customer,200);
}

Laravel alias column name in Eloquent model

How can I alias a column name in a model? I would like to show idUser instead of id in API responses. So far I've tried the following.
protected $maps = [
'id' => 'idUser',
];
protected $visible = [
'idUser'
];
protected $appends = [
'idUser'
];
This gives me an error:
'Call to undefined method App\User::getIdUserAttribute()'
Also, I would like to alias created_at and updated_at to createdAt and updatedAt.
you can define accessor method in your model like this :
public function getUserIdAttribute($)
{
return $this->id;
}
and then you have to add the attribute name in the $appends array
protected $appends = ['user_id'];
for more details checkout the docs
https://laravel.com/docs/5.8/eloquent-mutators
As #Namoshek's comment, you should be able to return a custom aliases for each column by renaming it.
First, look for which route you want to edit in folder routes/api.php. You can either use callback function or a Controller to manage the response.
// routes/api.php
Route::middleware('auth:api')->get('auth/retrieve-user', function(Request $request) {
$user = Auth::user();
return response()
->json([
'userId' => $user->id,
'createdAt' => $user->created_at,
'updatedAt' => $user->updated_at,
]);
});

Adding records to a relations repository with Laravel

I’m using laravel 5.5 and andersao/l5-repository. I want to add an answer record with the question repository.
My Question Controller
protected $repository;
public function __construct(QuestionRepository $repository)
{
$this->repository = $repository;
}
public function add_answer(AnswerAddRequest $request)
{
$this->validator->with($request->all())->passesOrFail(ValidatorInterface::RULE_CREATE);
$question = $this->repository->answer->create([
'content' => 'Answer text question',
'user_id' => Auth::user()->id
]);
return question;
}
My Question Model
public function answer()
{
return $this->belongsTo(Answer::class, 'question_id');
}
I tried '$this->repository->answer()'
always error : Undefined property
I think I have to use the with() method, but I don’t want to take all the content. I only need to add content with the relation of the model.
You should add this part of code
public function answer()
{
return $this->belongsTo(Answer::class, 'question_id');
}
into your Question mode, not into your repository.
The Laravel Eloquent class extends the Model class, which has methods like belongsTo that you're using.
--- EDIT ---
If you want to use repository, you could integrate it with Eloquent:
$this->reposotiry->find($request->input('question_id'))->answer()->create([
'content' => 'Answer text question',
'user_id' => Auth::user()->id
]);

Laravel Model create function returns column with null value

In Laravel, When I run the following query, it returns a row with null values.
//Cards.php
public function __construct(array $attributes = []) {
$this->gateway = StripeGateway;
}
protected $fillable = ['user_id', 'card_id', 'customer_id', 'exp_year', 'exp_month', 'funding', 'brand', 'last4'];
public function createNewCardFromCustomer($user_id, $customer)
{
$result = $this->create([
'user_id' => $user_id,
'customer_id' => $customer->id,
'card_id' => $customer['sources']['data'][0]->id,
'exp_year' => $customer['sources']['data'][0]->exp_year,
'exp_month' => $customer['sources']['data'][0]->exp_month,
'funding' => $customer['sources']['data'][0]->funding,
'brand' => $customer['sources']['data'][0]->brand,
'last4' => $customer['sources']['data'][0]->last4
]);
return $result;
}
Even the Model static create method receives the right parameters. And I've taken care of the mass assignment also.
I posted this on Laracasts too :)
Anyway, you have to change your constructor to this:
public function __construct(array $attributes = []) {
$this->gateway = StripeGateway;
parent::__construct($attributes);
}
You are overriding the Model's base constructor, which changes its default behavior. Laravel uses the constructor for a lot of things (create method, relationships, etc.).
The base model's constructor function does several things, but one very important part of it is that it accepts an array to fill out its attributes as can be seen here:
public function __construct(array $attributes = [])
{
$this->bootIfNotBooted();
$this->syncOriginal();
$this->fill($attributes);
}
So, after you set your gateway property, you should call the parent's constructor function and pass the attributes.

Resources