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)
Related
I have started using laravel and I am loving it.
I write APIs for mobile developers.
I use lot of tables with joins on id_user.
thus I always need id_user.
I have table users which has columns as follows:
1. id
2. token
3. full_name
I do validation as follows:
$result=$request->validate([
'token' => 'required|unique|exists:users'
]
]);
with above code I always get true or false in $result.
but I want the id of this token, which I use as unique in other tables.
thus
I fire the below query as follows:
$users=DB::table('users')
->whereExists(function ($query) {
$query->select(DB::raw(1))
->from('orders')
->whereRaw('orders.user_id = users.id');
})
->get();
$id_user=$users->id;
but my question is if in laravel validation, "unique|exists:users" checks for unique record existing in users table, and when it finds the record, it validates this constraint and (returns true), it must be storing this unique record somewhere.
Where can I get this record?
If laravel doesn't have this feature they must add it.
Why should I join user table (or fire another query again?) and make the process expensive?
you need to create models and set relationships (User and Order)
class User extends Authenticatable{
protected $fillable = [
'name', 'email','token', 'password',
];
public function order()
{
return $this->hasMany(Order::class);
}
}
class Order extends Model
{
public function user()
{
return $this->belongsTo(User::class);
}
}
set foreign key on orders table
$table->foreign('user_id')->references('id')->on('users');
then this should be the query
'token' => 'required|unique:users|exists:users'
$order = Order::find(1)->user()->where('token_in_orders_table', 'token_in_users_table')->first();
return $order;
Or create a Resource for the Order Model
class OrderController extends Controller
{
public function index(Request $request)
{
//validate token
'token' => 'required|unique:users|exists:users'
//then
return new OrderResource(Order::find(1));
}
}
Resource
class OrderResource extends JsonResource
{
public function toArray($request)
{
return [
'id' => $this->id,
'order_details' => $this->order_details,
'user' => $this->user()->where('token', $request->token)->first(),
];
}
}
enter image description here
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.
Recently I've been trying to create Nova resource which depends on the other resource which provides the information for the main resource.
I have a table contest_entries which has the following fields:
id
contest_id
user_id
with the following relations
public function contest() : BelongsTo {
return $this->belongsTo(Contest::class, 'contest_id', 'id');
}
public function user() : BelongsTo {
return $this->belongsTo(User::class, 'user_id', 'id');
}
Also, i have a table contest_submissions with the following fields:
id
entry_id
task_id
comment
approved
declined
with the following relations:
public function entry() : BelongsTo {
return $this->belongsTo(ContestEntry::class, 'entry_id', 'id');
}
public function user() : BelongsTo {
return $this->entry->user();
}
public function contest() : BelongsTo {
return $this->entry->contest();
}
public function task() : BelongsTo {
return $this->belongsTo(Task::class, 'task_id', 'id');
}
I have no problem in fetching this data on the index and details view of Nova, everything 'just works', however, when I try to update the resource, I'm getting the error that user() or contest() is called on null.
I've tried the following,
return [
BelongsTo::make('Contest', 'contest', Contests::class)->exceptOnForms(),
BelongsTo::make('Task', 'task', ContestTasks::class)->exceptOnForms(),
BelongsTo::make('User', 'user', AccountUsers::class)->exceptOnForms(),
]
But for some reason, Nova is still trying to fetch these relationships ever when i explicitly tell it not to.
Any ideas are greatly appreciated, because it works everywhere, except on the update view (create view is explicitly disabled since the submissions are created by the user on the frontend)
You should also chain a hideWhenUpdating() constraint to it.
return [
BelongsTo::make('Contest', 'contest', Contests::class)
->hideWhenUpdating()
->exceptOnForms(),
BelongsTo::make('Task', 'task', ContestTasks::class)
->hideWhenUpdating()
->exceptOnForms(),
BelongsTo::make('User', 'user', AccountUsers::class)
->hideWhenUpdating()
->exceptOnForms(),
]
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']);
});
I have users table with id on it.
My project model has $fillable fields:
protected $fillable = [
'title',
'description',
'visibility_level',
'creator_id'
];
relationship:
public function user()
{
return $this->belongsTo('App\User');
}
In Users model relationship:
public function projects()
{
return $this->hasMany('App\Project');
}
Now creator_id is refering to user_id. I have set up my project model table with:
$table->foreign('creator_id')->references('id')->on('users')
->onUpdate('cascade')->onDelete('cascade');
But then I try to store data, it still tried to add user_id:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'user_id' in 'field list'
My store() method:
public function store(ProjectRequest $request)
{
$project = new Project($request->all());
Auth::user()->projects()->save($project);
flash()->success('Project have been created');
return redirect('news/');
}
Am I searching In wrong place or what? I dont understand why its "user_id" where is this "user_id" generated name comes from?
The user_id key comes from the name of your class (User). All laravel does is snake case it and append _id to it. To fix your issue, use the second, optional, parameter for hasMany on your User class:
public function projects()
{
return $this->hasMany('App\Project', 'creator_id');
}
This should solve your problems now but, to use the relationship the other direction, you'll also need to make some changes on your Project model. You have two choices:
Rename your relationship method:
public function creator()
{
return $this->belongsTo('App\User');
}
Override the key by passing it as second parameter to belongsTo:
public function user()
{
return $this->belongsTo('App\User', 'creator_id');
}
Given what you are trying to achieve, I'd recommend you go with the first option.