How to create Eloquent model with relationship? - laravel

How to create Eloquent model with relationship?
I have:
Person table
id
firstname
lastname
Employee table
id
person_id
position
I want to do something like this:
Employee::create([
'firstname' => 'Jack',
'lastname' => 'London',
'position' => 'writer'
])
I know, that can create two model and then associate their. But may be there is a way do this more beautiful?

First, you have to create relation in your Person model
class Person extends Model
{
protected $fillable = ['firstname', 'lastname'];
public function employee()
{
return $this->hasOne('App\Employee');
}
}
After that in your controller you can do:
$person = Person::create($personData);
$person->employee()->create($employeeData);
As #Alexey Mezenin mentioned you can use:
$person = Person::create(request()->all());
$person->employee()->create(request()->all());
Also inverse would be:
class Employee extends Model
{
protected $fillable = ['position'];
public function person()
{
return $this->belongsTo('App\Person');
}
}

You still need to create person first, so if you're looking for readable and consize solution, you can do is this:
$data = [
'firstname' => 'Jack',
'lastname' => 'London',
'position' => 'writer'
];
$person = Person::create($data);
$person->employee()->create($data);

I'd suggest you create a static method that creates the instance and related models. Many times you not only create a model, but you may have to populate it with some additional data and having a single createModel() method is a best practice.
In my case:
public static function createCompany($data) : Company {
$company = new Company($data);
$company->save();
$company->settings()->create();
// TODO Configure settings according to $data
$company->blog()->create();
// TODO: Create demo blog post
// TODO: Create default admin user.
// TODO: Etc.
}
All these details can be abstracted from the controller, in which I only call:
$company = Company::createCompany($request->all());

Related

Problem in inserting data into many to many relationships using attach() function laravel

i have two tables (orders & products) and one pivot table (order_product).
i have made many to many relationship b\w them using following code.
class Product extends Model{
protected $fillable = ['name', 'price', 'is_iframe_product'];
public function orders() {
return $this->belongsToMany(Order::class);
}
}
class Order extends Model{
public $guaded = ['id'];
protected $fillable = ['is_iframe_order','price', 'status', 'address_id','user_id'];
public function products () {
return $this->belongsToMany(Product::class);
}
}
i am using following code to insert records in CheckoutController.php
$Product = array('name' => $item['item_name'], "price" => $item['price'], "is_iframe_product" => "1");
$saved = order()->products()->attach([$Product]);
but getting this error:
exception: "Symfony\Component\Debug\Exception\FatalThrowableError"
file: "C:\wamp3\www\jewellery\jewellery\app\Http\Controllers\CheckoutController.php"
line: 63
message: "Call to undefined function App\Http\Controllers\order()"
Here's what to do:
First save the product into the database
$product = Product::create(array('name' => $item['item_name'], "price" =>$item['price'], "is_iframe_product" => "1"));
Then attach the saved product with the product's id
$saved = $order->products()->attach($product->id);
What you need to do is create the order first:
$order = new Order;
// set some attributes
$order->save();
Then you can attach the specified product:
$product = Product::find(1);
$order->products()->attach($product->getKey());
If you are creating the product on the fly:
$product = Product::create(array('name' => $item['item_name'], "price" =>$item['price'], "is_iframe_product" => "1"));
$order->products()->attach($product->getKey());
You're using a function: order()->...
And the error says the function doesn't exist: Call to undefined function ... order()
Did you mean to reference a variable, like this? $order->...
It would be helpful if you included the rest of the controller, since I don't know what variables you're using.
Also, your Order model has a typo: $guaded should be $guarded.

Laravel Polymorphic Relations: constraint violation: Duplicate entry for key 'images_imageable_id_unique

I'm building an application with 4 tables: Films, Actors, Categories and Images
There is a Polymorph relation between Images in one side and Films, Actors and Categories in the other side.
These are my models:
- Actor
class Actor extends Model
{
protected $fillable = ['name', 'image_id', 'genre', 'slug',];
public function images()
{
return $this->morphMany('App\Comment', 'imageable');
}
}
- Category
class Category extends Model
{
protected $fillable = [ 'category', 'description', 'image_id', 'slug'];
public function images()
{
return $this->morphMany('App\Comment', 'imageable');
}
}
- Film
class Film extends Model
{
protected $fillable = ['name','image_id','description','slug','trailer','year','duration','age_id','language_id','category_id'];
public function images()
{
return $this->morphMany('App\Comment', 'imageable');
}
}
- Images
class Image extends Model
{
protected $fillable = [ 'image', 'imageable_id', 'imageable_type' ];
public function imageable()
{
return $this->morphTo();.
}
}
As far as I understand the "imageable_id" in Images table is the id (INCREMENT) of the position in the other tables (film->id, category->id or actor->id)
But the "imageable_id" must be also UNIQUE.
Here is my problem:
Let's say I create the first film and associate an image to it.
Image.id = 1, imageable_id = 1 (the id of the film), imageable_type = film
Second I create an actor and associate an image to it.
Image.id = 2, imageable_id = 1 (the id of the actor).... <-- ERROR
SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '7' for key 'images_imageable_id_unique
Should I remove the AUTO_INCREMENT in all tables?
Any idea on how to solve that problem?
The Store methods in my 3 Controllers (CategoriesController, FilmsControllers and ActorControllers) are similar. (I share here just the Categoriescontrollers)
public function store(CategoriesRequest $request)
{
$file = $request->file('image');
$name = time() . '-' . $file->getClientOriginalName();
$file->move('images', $name);
$last_img = Image::orderBy('id', 'desc')->first();
$category = Category::create([
'category' => $request->category,
'description' => $request->description,
'slug' => str_slug($request->category, '-'),
'image_id' => $last_img->id + 1,
]);
$image = Image::create([
'image' => $name,
'imageable_type' => 'Category',
'imageable_id' => $category->id
]);
$category->save();
Session::flash('success', 'Category successfully created!');
return redirect()->route('categories.index');
}
But the "imageable_id" must be also UNIQUE.
It can't be unique with polymorphic relationships. If you want to use polymorphic relationships it really cannot be unique, as the polymorphic relationships are connected to multiple tables and each of those tables will have their own autoincrementing ids, which are unique on their respective table, but not unique across the database.
It's possible to have unique ids across multiple tables, but rather uncommon in MySQL.
The solution is to remove the unique index from you imageable_id column on the images table.
You probably want the combination of imagaeble_id and imageable_type to be unique, which will enforce a 1-to-1 relationship, which can be done on a MySQL level.

Laravel - defining the right relationship

User Table: has zone_id field in it.
Zones table: has world_id field in it.
Each user can be in one zone, for example, zone_id = 1
Each zone belongs to one world, for example - world_id = 5
My desired output is returning user zone and world info.
This is how I can make it without any relationship set:
$zone = Zone::find($user->zone_Id);
$world = World::find($zone->world_id);
$data = $user;
$data['zone'] = $zone;
$data['zone']['world'] = $world;
My question is.. I'm sure relationship can be used for a cleaner code, but I'm not sure how to set it up.
Should I stick with the current code or define a relationship?
If the answer for 1 is define a relationship, Any help of what's the right relationship between these 3 models?
Solution 1:
`public function getZone(Request $request)
{
$token = $request->input('token');
$user = JWTAuth::toUser($token);
// Simplest example using relationships
$userWithZone = User::with('zone.world')->find($user->id); // You'll get the `zone` relationship info here, too
return $userWithZone;
}`
Error: returns "Call to a member function getQuery() on null"
Here's an example of how you can achieve this with Eloquent Relationships.
// User.php
class User
{
public function zone()
{
return $this->belongsTo(Zone::class);
}
}
// Zone.php
class Zone
{
public function world()
{
return $this->belongsTo(World::class);
}
}
Simplest example using relationships
$user = User::with('zone.world')->find($id); // You'll get the `zone` relationship info here, too
You can get more complex with your relationships if you want
$user = User::with(['zone' => function($query) {
$query->with('world')
->select('id', 'zone_name', 'world_id');
})->select('username', 'zone_id')->find($id);
or even...
$user = User::with(['zone' => function($query) {
$query->with(['world' => function($query2) {
$query2->select('id', 'world_name');
}])->select('id', 'zone_name', 'world_id');
})->select('username', 'zone_id')->find($id);
Your resulting $user will look something like:
'user' => [ // This is a Collection
'username',
'email',
'zone_id',
'zone' => [ // This is a Collection
'id',
'zone_name',
'world_id',
'world' => [ // This is a Collection
'id',
'world_name'
]
]
];

custom `id` name using `insertGetId` fluent method of Laravel

According to Laravel's documentation:Inserts
Note: When using PostgreSQL the insertGetId method expects the auto-incrementing column to be named "id".
So, is there a workaround for a custom id name while using inserGetId. i.e.
$id = DB::table('users')->insertGetId(
['email' => 'john#example.com', 'votes' => 0]
);
You can use the Eloquent method Model::create() to return the object inserted, and obtain the object id, whatever his name is.
Try this:
$user = User::create(['email'=>'john#ecample.com','votes'=>0]);
$id = $user->custom_id;
This works if your User model is like:
class User extends Eloquent {
//This custom_id column needs to be of type serial in your table
protected $primaryKey = 'custom_id';
protected $fillable = ['email','votes'];
//...more code ...
}
I hope this works for you

Update many multiple data with tables hasmany and belongsTo?

sorry for my english
I want two tables
Invoices
id
user_id
name
created_at
update_at
Invoicesitems
id
invoice_id
title
createad_at
update_at
Models
class Invoices extends eloquent{
public function invoicesitems(){
return $this->hasMany('Invoicesitem');
}
}
class Invoicesitems extends eloquent{
public function invoices(){
return $this->belongsTo('Invoice');
}
}
Now, for update the items of my invoices?
Example my invoices have 5 item, i need update to 10 items
first delete all items of my invoices and insert new ???
$invoices = Invoices::findOrFail($id);
$dataupdate = array(
'user_id' => Input::get('user'),
'name' => Input::get('name'),
);
$invoices->fill($dataupdate);
$invoices->save();
//Ok update invoices, now how to update items?
Thanks you.
If your business logic allows - you can just replace the invoice items.
$invoice = Invoices::findOrFail($id);
$dataupdate = array(
'user_id' => Input::get('user'),
'name' => Input::get('name'),
);
$invoice->update($dataupdate);
// replace invoice items
$invoice->invoicesitems()->delete();
$invoice->invoicesitems()->create($invoiceItems);
Note! This is quite straight solution. You can improve by using insert() method instead of create() for batch insert.

Resources