I have a Laravel application that contains an entity with a HasOne relationship from parent to child.
I'm now introducing Laravel Nova, and would like the parent's detail view to include all the fields from the child without my user having to click into it as you do with a Nova BelongsTo or HasOne field. They would look like a single record.
Assuming that I cannot modify the structure of the application, is there an existing method to do this? Can I override the detail screen with my own code? The Nova documentation doesn't address this specific use case, nor can I find any other questions on this topic online.
I don't care about needing to create or edit the entries, Nova will just be used to view them in this case.
Thanks
There is not an easy way to display all of the child's details in the parent's details view.
The best solution is to use the title attribute on the child. This lets you customize the text representation of the child in the parent's index view and details view.
By default, you have:
public static $title = 'id';
Can be replaced this with:
public static $title = 'name';
Or:
public function title()
{
return $this->name . '(' . $this->email . ')';
}
Source: https://nova.laravel.com/docs/1.0/resources/relationships.html#title-attributes
Related
I am a newbe in Laravel. The docs show how to use relationships like this:
One To Many (Inverse) / Belongs To
Now that we can access all of a post's comments, let's define a relationship to allow a comment to access its parent post. To define the inverse of a hasMany relationship, define a relationship method on the child model which calls the belongsTo method:
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Comment extends Model
{
/**
* Get the post that owns the comment.
*/
public function post()
{
return $this->belongsTo(Post::class);
}
}
Once the relationship has been defined, we can retrieve a comment's parent post by accessing the post "dynamic relationship property":
use App\Models\Comment;
$comment = Comment::find(1);
return $comment->post->title;
My question is: Where is this code? In a controller or in a view?
If you use MVC structure, you should understand that
Model is layer where you store your data
View is layer where you should only display your data
and Controller is layer where you can keep your logic.
If you have a lot of difficult logic or big application, you should better to use Services, as layer between Controllers And Models.
Receiving Comments from model and prepeare them should be in controller level. In view level you just define how to show them to user.
I hope it will help you to understand difference between logic layers.
you can access this relationship in controller or view like this-
suppose you want to make relation between product model and brand model:-
in product model:-
public function brand(){
return $this->belongsTo('App\Model\Brand','brand_id','id');
}
now you are able to see which product belongs to which brand without any query or using loop.
just do in controller:-
$product=Product::with('brand')->get();
here you get all the data...
and when you use it on **view **just do it:
{{$product->brand->brand_name}}
//brand name should the column name
I hope you understood...
Happy Learning!
Imagine the following 3 models with fields:
Listing:
id
ListingTranslation:
id
listing_id
language_id
title
Language:
name
iso
Inside my ListingTranslation create/update form how can I filter the language selector to NOT SHOW the languages that have been already translated?
(i.e. If I have 2 languages ES (id 1) and EN (id 2) and if I have a listing with id 1 and this listing already has a listing_translation with id 1, listing_id 1 and language_id 1, the language selector should only show EN as an option).
Language selector:
BelongsTo::make('Language')
Laravel Nova documentation provides the following method to filter the queries that are used to populate relationship model selection menus:
public static function relatableQuery(NovaRequest $request, $query)
{
return $query->where('user_id', $request->user()->id);
}
However, I do not know how to access something like listing_id from this method.
Instead of creating Nova resource for pivot table ListingTranslation, you can make use of BelongsToMany relation.
Under Listing Nova resource fields add BelongsToMany::make('Languages'). Assuming you have already defined the relationship in Listing model.
At this point when you attach a language which is already attached, you will see an error message The language is already attached
But if you still want to stop listing the already attached languages you can add relatableQuery given below under Listing nova resource.
public static function relatableLanguages(NovaRequest $request, $query)
{
$listing = $request->findResourceOrFail();
return $query->whereNotIn('id', $listing->languages->pluck('id'));
}
Hope this will help you.
I am developing a Web application using Laravel. For the admin panel, I am using Laravel Nova. What I am trying to do now is that I need to use data from the table which has relationship through another table. To be, clear, see my database structure below.
items
=====
id
name
price
sub_category_id
sub_categories
==============
id
name
parent_category_id
parent_categories
=================
id
name
What I am trying to achieve inside the Nova is that I want to display the parent category name of the item on the item index/list page. The first thing is that I do not want to create custom attribute something like this in the model
protected $appends = [
'parent_category_name'
];
function getParentCategoryNameAttribute()
{
//code here
}
Therefore, there are two solutions I can think of. The first solution is using the HasThrough relationship. But I cannot find it in Nova. So, I cannot use it. The second solution is that overriding the field value on render. Something like this.
Text::make("fieldname")->fillUsing(function($request, $model, $attribute, $requestAttribute) {
//$model->sub_category->parent_category - then I can return a value
return "Parent category name";
})->onlyOnIndex()
But the above code is not working. So, what would be the best approach to handle the has-through relationship in Nova?
Assuming you have defined the relationship sub_category & parent_category properly.
Define the relationship in Item model as below
public function parent_category()
{
return $this->sub_category->parent_category();
}
Then use it in Item resource as below.
BelongsTo::make('Parent Category')
->hideWhenCreating()
->hideWhenUpdating(),
Hello how are you all? i enter here because i not found the reply in the documentation, i have a relation 1-1 in my ddbb, is there some way to show this linked in the same view crud? Then with a button that open the eloquent model related in a dialog. Or something in this way without load in. New windows reload, or by example show the details of the parent eloquent and show just in the line down tabulated the children table, there are some. Example that how to do this?
If I understood correctly you ask if something like this is possible?
Controller:
$blogpost= Blogpost::where('id', '=', $id)
->with('comments')
->with('reactions')->first();
return view('blogpost_single','blogpost' => $blogpost);
Then in your view you can access the blogpost variable itself:
Blog title: {{$blogpost->title}}
and the children
Blog comment 1: {{$blogpost->comments[0]->text}}
Blog comment 2: {{$blogpost->comments[1]->text}}
Example:
In Users Model:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
/**
* Get the phone record associated with the user.
*/
public function phone()
{
return $this->hasOne('App\Phone');
}
}
If you want get one user you can try:
User::find(1)->phone
If you want get all users with phone of this user you can try
User::with('phone')->all();
After you see result object and let see it
I have a flight class and this flight has a custom view field like so:
This represents a belongs to many relationship which stores website_id / flight_id and pricing as pivot data in a pivot table.
The custom view uses JS to send this data back to the controller in this format:
{"1":{"price_adult":"434","price_child":"545"},"2":{"price_adult":"323","price_child":"324"},"3":{"price_adult":"434","price_child":"43"}}
Trying to send this data with the request doesn't create the relations fields, and because I do not have a flight ID at the point of creating this within the controller I can not loop this JSON to make the relations manually.
Can anyone point out what the best course of action is or if there is support for this? I took a look at the docs but they are woefully short and patchy in terms of being much help.
EDIT:
I should have said I can probably make this work using a custom name attribute on the model for the relation, then add a set mutator to loop this data and update the prices relation but I don't want to go down this route if there is support for this I am missing out of the box in backpack.
EDIT2:
Someone asked about the relation:
$this->belongsToMany(Website::class, 'website_pricing')->withPivot('price_adult', 'price_child');
This is working fine its not a problem with the relation working its how can I get backpack to store the data as a relation when the flight has no ID yet, or how can I pass the data I posted above in such a way that the backpack crud controller can handle it?
You may need to create a flight first, if no flight id is being provided. Can you explain the database relational structure more?
Basically thought I should post what I did because no one could provide an answer to this.
So basically you have to copy the store / update functions from the parent, changing a few lines.
$this->crud->hasAccessOrFail('create');
// fallback to global request instance
if (is_null($request)) {
$request = \Request::instance();
}
// replace empty values with NULL, so that it will work with MySQL strict mode on
foreach ($request->input() as $key => $value) {
if (empty($value) && $value !== '0') {
$request->request->set($key, null);
}
}
// insert item in the db
$item = $this->crud->create($request->except(['save_action', '_token', '_method']));
$this->data['entry'] = $this->crud->entry = $item;
// show a success message
\Alert::success(trans('backpack::crud.insert_success'))->flash();
// save the redirect choice for next time
parent::setSaveAction();
return parent::performSaveAction($item->getKey());
Basically any line which references a function in the parent class using $this->method needs to be changed to parent::
This line is what I used to submit the relations JSON string passed to the controller as relations $item->prices()->sync(json_decode($request->input('prices'), true));
This is done after the line containing $item = $this->crud->create as the item id that just got stored will be available at that point.