Update fields from two tables in Laravel - 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);
}

Related

Laravel how to save belongstomany in store controller?

I can save my ticket inside a ticket table. But i also have a ticket_user table with inside a ticket_id and a user_id. So when the user press save it need to automaticlay pick also the ticket_id and the user_id inside the ticket_user table. I have a many to many table between Users and Ticket.
this is the error i get Call to a member function attach() on null
User Models
public function ticket(){
return $this->belongsToMany(Ticket::class, 'ticket_user');
}
Ticket models
public function users() {
$this->belongsToMany(User::class, 'ticket_user');
}
Controller
public function store(Request $request)
{
$this->validate($request, array(
'title' => 'required',
'ticket' => 'required'
));
$ticket = new Ticket;
$ticket->title = $request->title;
$ticket->ticket = $request->ticket;
$ticket->save();
$ticket->users()->attach($request->input('user_id'));
return redirect()->route('users.tickets.index');
}
You are not returning anything in users function in Ticket class.
public function users() {
return $this->belongsToMany(User::class, 'ticket_user');
}

How to store the actual user logged into my database and display it as a created by field for my CRUD?

I have this code in my controller:
public function store(StoreRequest $request)
{
$user = Auth::user();
$request->get('nombre');
$request->get('correo');
$request->get('creado_por');
$creado_por = Auth::user()->id;
$request->validate([
'creado_por' => 'string'
]);
return ComprasNotificacionCancelacion::create([
'nombre' => request('nombre'),
'correo' => request('correo')
]);
}
This is the model:
protected $table = 'compras_notificacion_cancelacions';
protected $primaryKey = 'id';
protected $guarded = ['id'];
protected $fillable = [
'nombre',
'correo',
'creado_por'
];
protected $dates = [
'fecha_creacion',
'fecha_modificacion'
];
Could you help me, please?
Your question is not clear, but what you are trying to do is add logged in user as the creado_por here is how you can achieve that.
public function store(StoreRequest $request)
{
$request->validate([
'creado_por' => 'string'
]);
//here you can use either Auth()->user()->id or $request->user()->id
return ComprasNotificacionCancelacion::create([
'nombre' => $request->nombre,
'correo' => $request->correo,
'creado_por' => $request->user()->id
]);
}
additionally here are somethings you could improve. You can access same Auth()->user() from $request like $request->user().
You don't need the below codes.
$user = Auth::user();
$request->get('nombre');
$request->get('correo');
$request->get('creado_por');
$creado_por = Auth::user()->id;
and if using id as id no need to mention it
protected $primaryKey = 'id';
The way I store the author of an entry is that I have a created_by column in the database and I make sure that contains the right ID inside the model. Here's a trait I use, that I call CreatedByTrait.php and use it on the models that need it:
<?php namespace App\Models\Traits;
use Illuminate\Database\Eloquent\Model;
trait CreatedByTrait {
/**
* Stores the user id at each create & update.
*/
public function save(array $options = [])
{
if (\Auth::check())
{
if (!isset($this->created_by) || $this->created_by=='') {
$this->created_by = \Auth::user()->id;
}
}
parent::save();
}
/*
|--------------------------------------------------------------------------
| RELATIONS
|--------------------------------------------------------------------------
*/
public function creator()
{
return $this->belongsTo('App\User', 'created_by');
}
}

How to store data in Laravel

I try to store data to DB.
Following your recommendations, I created a schema
Schema::create('user_info', function (Blueprint $table) {
$table->string('name')->index();
$table->string('ip');
$table->timestamp('created_at')->nullable();
});
I created a model for a UserInfo where I plan to store IP and name
class UserInfo extends Model
{
protected $fillable = ['ip'];
}
In HomeController
public function store(Request $request) {
$user_info = new UserInfo;
$user_info->ip = $request->ip;
$user_info->name = $request->name;
$user_info->save();
}
UserInfo::create(['user_info' => Request::user_info()]);
As a result, I've got the below-given error
Method Illuminate\Http\Request::user_info does not exist.
Look there are several issues. Firstly in Schema consider using an incremental id as the primary key.
Add name in the fillable property.
protected $fillable = ['name','ip'];
And finally in the controller either use one procedure to save to the database.
public function store(Request $request) {
$user_info = new UserInfo;
$user_info->ip = $request->ip;
$user_info->name = $request->name;
$user_info->save();
}
Or
public function store(Request $request) {
UserInfo::create([
'name' => $request->name,
'ip' => $request->ip
]);
}
Request is a class. Instead, use the $request variable provided as an argument in your function:
UserInfo::create(['user_info' => $request->input('user_info')]);

Passing data from controller into Model in 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'
];

Property [comment] does not exist on this collection instance

I'm trying to get data from a column from table comment through the story table via the slug column. I've managed to do it with authors but I think I must be missing something or forgetting something because it is no longer working. I get this error
Exception in Collection.php line 1498: Property [comment] does not exist on this collection instance.
My controller function
public function slug($slug){
$menus_child = Menu::where('menu_id', 0)->with('menusP')->get();
$stories = Story::where('slug', $slug)->get();
$slug = $slug;
// I used this to get the author's email going through the slug from
// story table
$story = Story::with('author')->where('slug', $slug)->first();
$name = $story->author->first()->email;
// I would like to get the name in the comment table by going through
// the slug from the story table
$comment = Story::with('comment')->where('slug', $slug)->get();
$test = $comment->comment->first()->name;
return view('open::public.single-story', compact('menus_child', 'stories', 'slug'));
}
my Comment.php
namespace App\Modules\Authors\Models;
use Illuminate\Database\Eloquent\Model;
class Comment extends Model
{
protected $fillable = array('name', 'comment');
protected $guarded = array('id');
protected $table = 'comments';
//Validation rules
public static $rules = array(
'name' => '',
'comment' => ''
);
public function story(){
return $this->belongsToMany('App\Modules\Authors\Models\Story', 'comment_story', 'comment_id', 'story_id');
}
}
my Story.php
class Story extends Model
{
protected $fillable = array('title', 'content', 'type', 'slug');
protected $guarded = array('id');
protected $table = 'story';
//Validation rules
public static $rules = array(
'title' => '',
'content' => '',
'type' => ''
);
public function slug($title){
$this->attributes['title'] = $title;
$this->attributes['slug'] = Str::slug($title);
}
public function author(){
return $this->belongsToMany('App\Modules\Authors\Models\Author', 'author_story', 'story_id', 'author_id');
}
public function comment(){
return $this->belongsToMany('App\Modules\Authors\Models\Comment', 'comment_story', 'story_id', 'comment_id');
}
}
With some help from dparoli I managed to do it. I can't believe it to me so long to figure it out.
I changed
$comment = Story::with('comment')->where('slug', $slug)->get();
$test = $comment->comment->first()->name;
to
$comment = Story::with('comment')->where('slug', $slug)->first();
$test = $comment->comment->toArray();
and I added test to
return view('open::public.single-story', compact('menus_child', 'stories', 'slug', 'test'));
and then added
#foreach($test as $t)
<h1>{!! $t['name'] !!}</h1>
<p>{!! $t['comment'] !!}
#endforeach
to my view
Try to change this:
//here you get a collection of stories
$comment = Story::with('comment')->where('slug', $slug)->get();
To this:
//here you get a single story
$comment = Story::with('comment')->where('slug', $slug)->first();
I give you a different approach to try
$comments = Comment::with(['story' => function ($query) {
$query->where('slug', '=', $slug);
}])->get();
Give this a go if it works for what you are trying to accomplish.

Resources