Laravel 5 - calling create() on hasMany relationship with conditions - php

I have a couple of models - let's call them Item and Ean. In Item model there are a couple of hasMany relations to the Ean model.
public function eans() {
return $this->hasMany(Ean::class)->orderBy('type', 'asc')->orderBy('id', 'asc');
}
public function eans_type_1() {
return $this->hasMany(Ean::class)->where('type', 1)->orderBy('id', 'asc');
}
public function eans_type_2() {
return $this->hasMany(Ean::class)->where('type', 2)->orderBy('id', 'asc');
}
When I want to associate a new Ean model to the Item, I'm using create() :
$item->eans()->create(['ean' => $value, 'type' => 1]);
or
$item->eans()->create(['ean' => $value, 'type' => 2]);
Is there a way to define hasMany relation in a way that I'll be able to do this :
$item->eans_type_1()->create(['ean' => $value]);

Not without some serious overriding. When you call
$items->eans()
$items->eans_type_1()
$items->eans_type_2()
You're getting an Illuminate\Database\Eloquent\Relations\HasMany instance and when you call
$items->eans
$items->eans_type_1
$items->eans_type_2
You're getting an Illuminate\Database\Eloquent\Collection instance.
Just pass the value.

Related

Update relationship inside relationship hasMany values

So I was wondering how do I need to update relationship inside relationship values. For example I have first relationship:
class Code {
public function item()
{
return $this->hasOne(UserItem::class, 'code_id')
}
}
And then there is other nested relationship inside UserItem::class:
class UserItem {
public function serials()
{
return $this->hasMany(ItemSerial::class, 'user_item_id', 'id');
}
}
And then I recieve request values:
'item_serials' =>
array (
0 => 'test1',
1 => 'test2'
),
And I need to updateOrCreate values of serials relationship. Something like this:
foreach ($data['item_serials'] as $serial) {
$code->item->serials->updateOrCreate([
'serial' => $serial
]);
}
But this obviously doesn't work.
update or create method are static eloquent methods and for useing static methods from relationship you most use the relation method not property,so change your code to:
foreach ($data['item_serials'] as $serial) {
$code->item->serials()->updateOrCreate([
'serial' => $serial
]);
}

Why do I see an empty array returned from my laravel relationship model

I have 2 model, SurveyQuestion and SurveyQuestionOption
SurveyQuestionOption Model
public function opinions(){
return $this->hasMany('App\SurveyOpinions','option_id');
}
SurveyQuestion Model
public function options(){
return $this->hasMany('App\SurveyQuestionOption','question_id');
}
Controller
public function getQuestions(){
$data=SurveyQuestion::with('options')
->get();
if(count($data)>0)
{
return api::success(['data' => $data]);
}
return api::notFound(['errorMsg' => 'No Survey initiated yet!!!']);
}
When I hit get Question Api am getting an empty array from the model. I tried that by putting dd() for the $data Variable.

Laravel Nova Self-referential Relationship

In Laravel, if I want to create a self-referential relationship I can do the following:
class Post extends Eloquent
{
public function parent()
{
return $this->belongsTo('Post', 'parent_id');
}
public function children()
{
return $this->hasMany('Post', 'parent_id');
}
}
How can I make a Laravel Nova resource display this connection?
public function fields(Request $request)
{
return [
Text::make('Autor', 'author'),
Select::make('Type', 'type')->options([
'News' => 'news',
'Update' => 'update',
]),
BelongsToMany::make('Post') // does not work
];
}
You can achieve what you want like this:
BelongsTo::make('Parent', 'parent', \App\Nova\Post::class),
HasMany::make('Children', 'children', \App\Nova\Post::class),
This will allow to choose a parent post when you create or update a post. When you are in the detail page of a post, you can see all its children.
public function fields(Request $request)
{
return [
Text::make('Author', 'author'),
Select::make('Type','type')->options([
'News' => 'news',
'Update' => 'update',
]),
BelongsTo::make('Parent', 'parent', \App\Nova\Post::class),
HasMany::make('Children', 'children', \App\Nova\Post::class),
];
}
Note: Please note that the third param to BelongsTo::make() and HasMany::make() is a reference to the Post Resource, not Post model.
There is another situation, where you will find same issue, if you have parent column name parent and also relationship parent like
$table->bigIncrements('id');
$table->string('category');
$table->unsignedBigInteger('parent')->nullable();
and
In model
public function parent()
{
return $this->belongsTo(SELF::class, 'parent');
}
It will be unable to recognize the parent property and you will face this problem again, in that case, you can change the relationship name or column name, and it will work fine.
Also remember the arguments for Nova BelongsTo relationship
Argument 1. Name to display (e.g. Parent)
Argument 2. Name of the relationship as used in the model (e.g. parent)
Argument 3. The Nova Resource (e.g. App\Nova\Category)

Laravel eager load resource collection

How can I eager load a resource collection relationship? I've made a resource which calls gravel_pits relationship
class GravelTypeResource extends Resource
{
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'deleted_at' => $this->deleted_at,
'gravel_pits' => $this->gravel_pits,
];
}
}
On the model M:M relationship:
public function gravel_pits()
{
return $this->belongsToMany('App\GravelPit');
}
And from the API I am getting it back like this:
public function index()
{
return GravelTypeResource::collection(GravelType::all());
}
I can eager load it by doing
public function index()
{
return GravelTypeResource::collection(GravelType::with('gravel_pits'));
}
which works...but I can't control then what properties of gravel pits I actually want back, instead, eager load fetches them all. Is there a simple workaround to this?
you can use Resource Collections
GravelTypeResourceCollection::make($collection);
and since you can use load and loadMissing on eloquent collections you can do this
class GravelTypeResourceCollection extends ResourceCollection
{
$collects = GravelTypeResource::class;
public function __construct($resource){
$resource->loadMissing(['gravel_pits']);
parent::__construct($resource);
}
}
You can pass in a select to get just the fields you want. Just make sure you get the fields that the relationship is based on:
return GravelTypeResource::collection(GravelType::with('gravel_pits'=>function($query) {
$query->select(['id', 'gravel_type_id', 'column3', 'column4']);
});

Cannot save hasOne() model relationship

Visitor model:
public function group()
{
return $this->belongsTo('MyApp\Models\VisitorGroup', 'group_id');
}
VisitorGroup model:
public function visitors()
{
return $this->hasMany('MyApp\Models\Visitor');
}
So then I'm trying to create some Visitors for a group:
$mygroup = VisitorGroup::whereRaw('name LIKE "%mygroup%"')->first();
foreach(range(1, 10) as $i)
{
$v = Visitor::create(array('name' => 'Homer simpson'));
$v->group()->save($mygroup); // HERE trying to add this visitor to the group
}
But I'm getting this error:
[BadMethodCallException]
Call to undefined method Illuminate\Database\Query\Builder::save()
Am I doing something wrong?
That's because BelongsTo has no save() method. However it has an associate() method which is probably what you're looking for. Not that you have to explicitly save the model afterwards:
$v = Visitor::create(array('name' => 'Homer simpson'));
$v->group()->associate($mygroup);
$v->save();
Or you could just set the foreign key manually when creating to save db queries:
$v = Visitor::create(array('name' => 'Homer simpson', 'group_id' => $mygroup->id));
Or the probably most elegant way:
$mygroup->visitors()->create(array('name' => 'Homer simpson'));

Categories