Laravel merging relationships tables - php

I have two models (and two tables in the database) in Laravel 5: Artwork and Option (table names are artworks and options). A single artwork can have many options, so my models are as follows:
<?php namespace App;
use Illuminate\Database\Eloquent\Model;
class Artwork extends Model {
public function options(){
return $this->hasMany('App\Option');
}
}
and
<?php namespace App;
use Illuminate\Database\Eloquent\Model;
class Option extends Model {
//
}
I'm trying to output an array that will contain ALL the artworks that will have their options nested inside them. Outputting only artworks works fine ($artworks = $artwork->get() as shown below), but I cannot figure out how to merge / nest options within each artwork.
Here is my Route for this
get('api/artworks','ArtworksController#index');
And here is my controller
<?php namespace App\Http\Controllers;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Artwork;
class ArtworksController extends Controller {
public function index(Artwork $artwork)
{
$artworks = $artwork->merge($artwork->options())->get();
return $artworks;
}
}
I was playing around with that merge() function and I just couldn't get it right. Is it possible to achieve this with merge() at all?

You just need to eager load the options relationship:
$artworks = $artwork->with('options')->get();

Related

How to pass type and id to laravel polymorphic relation

I have a navigation model that can have many items associated with it:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
use JetBrains\PhpStorm\ArrayShape;
use Laravel\Scout\Searchable;
class Navigation extends Model
{
use HasFactory;
use Searchable;
protected $guarded = [];
public function navigation_items(): HasMany
{
return $this->hasMany(NavigationItem::class);
}
}
The navigation item model looks like this
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\MorphTo;
class NavigationItem extends Model
{
use HasFactory;
protected $guarded = [];
public function navigation(): BelongsTo
{
return $this->belongsTo(Navigation::class);
}
public function navigatable(): MorphTo
{
return $this->morphTo();
}
}
Now an item can either be of type Page or Blog, in this case the Page model looks like this:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\MorphOne;
use JetBrains\PhpStorm\ArrayShape;
use Laravel\Scout\Searchable;
class Page extends Model
{
protected $guarded = [];
public function navigatable(): MorphOne
{
return $this->morphOne(NavigationItem::class, 'navigatable');
}
}
When I try to save a navigation model and associate it with a item, the following error appears:
SQLSTATE[HY000]: General error: 1364 Field 'navigatable_type' doesn't have a default value
I save the model like this:
foreach ($this->selected as $id) {
$this->navigation->navigation_items()->create([
'navigation_id' => $this->navigation->id,
]);
Where $this->selected is the navigation id, it should automatically get the correct navigatable_type and navigatable_id, but this doesn't seem to be working.
passing in the type and id manually works, but this kinda defeats the point of a polymorphic relationship.
any ideas?
On NavigationItem model, since you defined polymorphic relation as 'navigatable' it is expected that NavigationItem model's table contains navigatable_type and navigatable_id. First please ensure this checks out.
Creating records through relation's base function is not a valid method. It is not clear what you are trying to achieve there but when you want to set relation there is two standard way of achieving it:
1- Associate
When a relation is defined as belongsTo, you may use associate() function. Like so:
$account = Account::find(10);
$user->account()->associate($account);
2- Attach
Attach is used when relation is defined belongsToMany (pivot). It allows you to attach multiple records to a model instance/record.
$user = User::find(1);
$user->roles()->attach($roleId);
So if you want to set a 'navigatable' to a Navigation instance, you may:
$somePageInstance=Page::find(55);
$nagivation->navigatable()->associate($somePageInstance)
$nagivation->save();//remember to save, otherwise it won't be

withCount() for multiple levels?

Like you can do Project::with('events.contacts') can you also do Project::withCount('events.contacts') ? It doesn't seem to work. Is there another way to find the total count of contacts for all events for a certain project where project.id = event.project_id and event.id = contact.event_id
You can use relationship Has Many Through
Docs: https://laravel.com/docs/8.x/eloquent-relationships#has-many-through
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Project extends Model
{
public function contacts()
{
return $this->hasManyThrough(Contact::class, Event::class);
}
}
Then you can do
Project::withCount('contacts')->get();

Eloquent relationship returning can't convert to string

I'm trying to map an existing one to one relationship in my database using Eloquent following the Laravel tutorial and I'm receiving a string conversion error.
I have to use an existing database that is used by other program, so I can't change the database structure.
This are my models:
Pessoa.php
namespace App\Models;
use Illuminate\Support\Facades\Log; use
Illuminate\Database\Eloquent\Model;
class Pessoa extends Model {
protected $table = 'pessoas';
public function estadoCivil(){
//return EstadoCivil::find($this->estado_civil_id);
return $this->hasOne('App\Models\EstadoCivil', 'estado_civil_id');
}
}
EstadoCivil.php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class EstadoCivil extends Model
{
protected $table = 'estados_civis';
}
I don't know what to do, but I am getting this error:
Object of class Illuminate\Database\Eloquent\Relations\HasOne could not be converted to string
I searched for typos and other mistakes and couldn't find anything. I'm not even trying to convert anything to string to get this error, the types in the database for the id and the foreign key are the same too.
Here is the controller that is using it:
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Models\Pessoa as Pessoa;
class Eu extends Controller
{
public function __construct()
{
}
public function dadosCompletos(Request $request){
return Pessoa::find($request->user()->pessoa_id)->estadoCivil();
}
}
If I just use return Pessoa::find($request->user()->pessoa_id) it works fine and returns the data correctly from pessoas table.
you are returning the relation not the actual EstadoCivil collection.
use return Pessoa::find($request->user()->pessoa_id)->estadoCivil without parenthesis
You have to use ->estadoCivil instead of ->estadoCivil()

Laravel: How do I create the relationship and which one do I use?

I have the database structure that have a classes table, a users table and users_classes table that matches the other two, because a user can belong to multiple classes. I have a problem now. I have code like this:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\DB;
class Classes extends Model
{
protected $table = 'classes';
public function students()
{
}
}
And I want to be able to access the students of the class by typing $class = Classes::find(1) and then $class->students to access the students. How do I define the relationship without using the query builder? I want to use eloquent. Im a noobie in Laravel pls dont downvote.
You use a belongsToMany relation.
If your users_classes table has the fields user_id and class_id you can do the following:
public function students()
{
return $this->belongsToMany(Student::class, 'users_classes', 'class_id', 'user_id');
}

Can someone explain how Laravel relationships work?

When I save a post it saves id of user which posted it.
That is great but I don't understand how.
Post controller
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Post;
class PostController extends Controller
{
public function postCreatePost(Request $request)
{
$post = new Post();
$post->body = $request['body'];
$request->user()->posts()->save($post); //i cant understand this line
return redirect()->route('dashboard');
}
}
?>
User model
<?php
namespace App;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Database\Eloquent\Model;
class User extends Model implements Authenticatable
{
use \Illuminate\Auth\Authenticatable;
public function posts()
{
return $this->hasMany('App\Post'); // ?
}
}
Post model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
public function user()
{
return $this->belongsTo('App\User'); // ?
}
}
I don't understand how belongs to and has many relations work.
If someone could explain it to me I would be very grateful.
In this case, the hasMany indicates that it will find many rows with the user id on the user_id column in the posts table.
The belongsTo simply means that it will find a user with an id in the users table that matches the user_id column on the posts related row.
Finally, $request->user()->posts()->save($post);:
Get the request
Get the user from the request
Get the posts from the user
The ->save($model) is a bit tricker. This requires that the object passed to the ->save($object) function is an instance of the relationship. In our case, the relationship is posts() and therefore the $post simply has to be an instance of App\Post (or wherever your Models namespace is).
You can find an explanation in the official documentation and in the chapter "Eloquent Relationships" from the book "Code Smart" (Laravel 4).
You can find a lot more resources in Google.

Categories