How in laravel do the automatic assignment of id in linked tables? - laravel-5

I have 3 tables linked with hasOne(). Modeel User.php linked with Profile.php
Profile.php linked with Country.php and Profile.php linked with City.php.
In the Profiles table have user_id foreign key. In the Countrys table have profile_id foreign key. And in the Citys table have profile_id foreign key.
How i can do correctly auto fill this foreign keys with user id.
Now i do so in RegistersUsers.php
public function register(Request $request)
{
$this->validator($request->all())->validate();
event(new Registered($user = $this->create($request->all())));
$this->guard()->login($user);
$user_id = Auth::user()->id;
$profile = new Profile;
$profile->user_id = $user_id;
$profile->save();
$country = new Country;
$country->profile_id = $user_id;
$country->save();
$city = new City;
$city->profile_id = $user_id;
$city->save();
return $this->registered($request, $user)
?: redirect($this->redirectPath());
}
But I think that there is a way more correctly.

You can use relations create method to auto fill this foreign keys as:
$user = Auth::user();
$profile = $user->profile()->create(['name' => 'user_name'])
// assumes relation name is profile
$country = $profile->country()->create(['name' => 'country_name']);
// assumes relation name is country
$city = $profile->city()->create(['name' => 'city_name']);
// assumes relation name is city
You can also use save method as:
$user = Auth::user();
$profile = new Profile;
$user->profile()->save($profile);
$country = new Country;
$profile->country()->save($country);
$city = new City;
$profile->city()->save($city);
Docs

You can use the create() method of the hasOne relation to create records associated with this model:
public function register(Request $request)
{
$this->validator($request->all())->validate();
event(new Registered($user = $this->create($request->all())));
$this->guard()->login($user);
$user->profile()->create([
'field' => 'value', // fields that are in the profiles table
]);
$user->country()->create([
'field' => 'value', // fields that are in the countries table
]);
$user->city()->create([
'field' => 'value', // fields that are in the cities table
]);
return $this->registered($request, $user)
?: redirect($this->redirectPath());
}
Please note that the names of your relations inside the User model are assumed as city(), country(), profile().

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');
}

Does Laravel Sync Delete and Re-Create?

I'm looking for some more information on how Laravel Sync Actually works. I have a Relationship Table that contains the following
group_id, user_id, permission, created_at, updated_at
I'm generating an array to pass to the sync command like so.
$groups_array[$group_id] = ['permission' => 0];
When I do this and then call sync it is setting the created_at and updated_at dates on existing relationships to NULL. The desired affect would be to have it just update the permission value to 0 on the existing relationship and not set the created_at and updated_at values to NULL.
It seems as if Sync is deleting everything and just re-creating the relationships based on the array sent. Is there not a way to tell this to update existing relationships vs. deleting and re-creating them?
By default Many to Many relationships in Laravel does not include timestamps, you need to define it on the relationship.
public function users()
{
return $this->belongsToMany(User::class)->withTimestamps();
}
// Post Model
public function categories()
{
return $this->belongsToMany('App\Category')->withTimestamps();
}
public function tags()
{
return $this->belongsToMany('App\Tag')->withTimestamps();
}
// Tag Model
public function posts()
{
return $this->belongsToMany('App\Post')->withTimestamps();
}
// Category Model
public function posts()
{
return $this->belongsToMany('App\Post')->withTimestamps();
}
// Post Controller Update
public function update(Request $request, Post $post)
{
$this->validate($request,[
'title' =>'required',
'categories' => 'required',
'tags' => 'required'
]);
$post->user_id = Auth::id();
$post->title = $request->title;
$post->slug = str_slug($request->title);
$post->save();
$post->categories()->sync($request->categories);
$post->tags()->sync($request->tags);
Toastr::success('Post Successfully Updated:)','Success');
return redirect()->route('admin.post.index');
}
// Delete
public function destroy(Post $post)
{
$post->categories()->detach();
$post->tags()->detach();
$post->delete();
Toastr::success('Post Successfully Deleted :)','Success');
return redirect()->back();
}

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);
}

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')]);

Laravel many to many relationship with uuid returns always empty

I use Laravel 5.8 and changed my model's autoincrement id to uuid. Since then I have some trouble with my many-to-many relationship that was defined between 2 of my models Event and User (with pivot table events_users).
The problem :
Now when I request all element that join both table (I have 2 records in my pivot table) I always get an empty array back.
When debugging the sql, I see that the where clause param is not set :
// Generated sql
select `users`.*, `events_users`.`event_id` as `pivot_event_id`, `events_users`.`user_id` as `pivot_user_id`, `events_users`.`created_at` as `pivot_created_at`, `events_users`.`updated_at` as `pivot_updated_at`
from `users`
inner join `events_users` on `users`.`id` = `events_users`.`user_id`
where `events_users`.`event_id` = ?
// Bindings :
Array
(
[0] =>
)
Has someone any clue what I'm missing here ?
Here are the definition of my models :
class Event extends Model
{
protected $primaryKey = 'id';
protected $keyType = 'string';
public $incrementing = false;
// here some other model methods, fillable property, etc.
public function users()
{
return $this
->belongsToMany(User::class, 'events_users', 'event_id', 'user_id')
->withTimestamps();
}
}
Same declaration for User model, but with relation
public function events()
{
return $this
->belongsToMany(Event::class, 'events_users', 'user_id', 'event_id')
->withPivot(['created_at', 'updated_at']);
}
Then I retrieve the relations from the service with :
public function getSubscriptions($eventId)
{
$eventId = 'a1b7c5d6-8f86-44f4-f31a-46e32917d5c0'; // for debug purpose only
$event = Event::find($eventId);
foreach ($event->users as $user) {
print_r($user); die; // It never loops here as its length is 0 but should be 2...
}
\DB::listen(function ($query) {
print_r($query->sql);
print_r($query->bindings);
// $query->time
});
$subscriptions = $event
->users()
->get();
die;
return $subscriptions;
}
My DB contains the records
The problem was about another declaration in my models where I list the property.
I've initialized an id property there, which is probably in conflict with the uuid type or I don't know exactly what cause this drama...
Anyway, removing this line let the app work correctly.
/**
* #var array
* Rules used for fields validation
*/
public $rules = array(
'title' => 'required|string|max:255',
'start_date' => 'required|date|date_format:Y-m-d',
'end_date' => 'required|date|date_format:Y-m-d|after_or_equal:start_date',
'location' => 'string|max:254',
'latitude' => 'numeric',
'longitude' => 'numeric'
);
public $id = ""; // This is the line that create the bug... Remove it and it works !
public $title = "";
public $start_date = "";
public $end_date = "";
public $location = "";
public $latitude = "";
public $longitude = "";

Resources