I have this Comment model with belongs to relationship.
class Comment extends Model
{
public function user()
{
return $this->belongsTo('App\User');
}
}
While in my controller:
public function store(Request $request)
{
$comment = $this->dispatch(
new StoreCommentCommand($request->body, Auth::user()->id, $request->post_id)
);
return $comment;
}
When I return the $comment I also want nested user object, how can I do that?
You need to use the with() on Builder object, whereas currently you are using on eloquent object. This will be your working code.
return Comment::with('user')->where('id', $comment->id)->first();
Just eager load it...
return $comment->with('user');
In case anyone stumbles upon this, you can just assign the user to the comment before returning it.
$comment->user = Auth::user()
return $comment
The with eager-loading function isn't needed here.
Related
I need to be able to convert a hasMany() relation, which queries and return an array into a hasOne() relation which returns object|null.
Use case:
public function getItems() : \yii\db\ActiveQuery {
return $this->hasMany(Item::class, ['parent_id' => 'id']);
}
I want to create a relation which returns one specific Item object (or null if it does not exist).
I would like to do something like this:
public function getPrimaryItem() : \yii\db\ActiveQuery {
return $this->getItems()->andWhere(["primary"=>true])->toHasOne();
}
Please do not tell me to call ->one() on the original query, because that is not going to solve the problem. I need to be able to:
call $model->primaryItem and receive either Item or null
call $model->getPrimaryItem() and receive the relation's ActiveQuery
You can toggle it by multiple property of \yii\db\ActiveQuery
public function getPrimaryItem() : \yii\db\ActiveQuery {
$query = $this->getItems();
$query->multiple = false;
//Your logics
$query->andWhere(["primary"=>true])
return $query;
}
I have a customer table which has a field called 'policy_id', where policy_id points to policy table. It is a null-able field, ie. Some customers may not have a policy.
I have a relationship code like this in Customer.php
public function policy() {
return $this->hasOne('App\Models\Policy', "id", "policy_id");
}
But when I issue a search request I am getting error like this:
Illuminate\Database\Eloquent\ModelNotFoundException: No query results for model [App\Models\Policy]
If I modify the function like this:
public function policy() {
if ($this->getAttribute('policy_id')) {
return $this->hasOne('App\Models\Policy', "id", "policy_id");
} else {
return null
}
}
But I am getting an error like this:
Call to a member function getRelationExistenceQuery() on null
Here is my search code:
$c = new Customer();
return Customer::doesntHave('policy')->orWhere(function (Builder $query) use ($req) {
$query->orWhereHas('policy', function (Builder $query) use ($req) {
$p = new Policy();
$query->where($req->only($p->getFillable()))
->orWhereBetween("policy_period_from", [$req->policy_period_start_from, $req->policy_period_start_to])
->orWhereBetween("policy_period_to", [$req->policy_period_end_from, $req->policy_period_end_to])
->orWhereBetween("payment_date", [$req->payment_date_from, $req->payment_date_to]);
});
})->where($req->only($c->getFillable()))->get();
Am I missing something or are there any other ways to do this?
PS: While debugging the above search code is returning successfully, but the exception happening from somewhere inside Laravel after the prepareResponse call.
Thanks in advance.
return $this->hasOne('App\ModelName', 'foreign_key', 'local_key');
Change the order, put the foreign_key policy_id in front of id
In your Customer Model, you need to use belongsTo method:
public function policy() {
return $this->belongsTo('App\Models\Policy', "policy_id", "id");
}
And In your Policy Model, use hasOne:
public function customer() {
return $this->hasOne('App\Models\Customer', "policy_id", "id");
}
First of all, you placed the wrong params.
$this->belongsTo('App\Models\Policy', "FK", "PK");
public function policy() {
return $this->belongsTo('App\Models\Policy','policy_id', 'id');
}
And for null value of policy_id you can use withDefault();
public function policy() {
return $this->belongsTo('App\Models\Policy','policy_id', 'id')->withDefault([
'name' => 'test'
]);;
}
there's a number of problems there but can you perhaps specify the namespace and the class of both your models - Customer and Policy.
By default, the models you create with php artisan make:model will use the \App namespace e.g. \App\Customer and \App\Policy.
Just double check that.
Also, with regards to the relationship, if the Laravel conventions have been followed you could just:
In the Customer model
public function policy() {
return $this->belongsTo(Policy::class);
}
In the Policy model
public function customer() {
return $this->hasOne(Customer::class);
}
of if a multiple customers can be under one policy
public function customers() {
return $this->hasMany(Customer::class);
}
Good luck
i want to find post by slug also in url ..
but the comments must be found by post_id
Controller
public function post($slug,$id)
{
$post = Post::where('slug',$slug)->first();
$comments = Comment::where('post_id',$id)->get();
return view('content.post',compact('post','comments'));
}
Route
Route::get('post/{slug}', 'PagesController#post')->name('post.show');
Route::get('post/{slug}', 'PagesController#post')->name('post.show');
public function post($slug)
{
$post = Post::where('slug',$slug)->first();
$comments = Comment::where('post_id',$post->id)->get();
return view('content.post',compact('post','comments'));
}
Here you go:
Get post_id from the $post itself.
public function post($slug){
$post = Post::where('slug',$slug)->first();
$comments = Comment::where('post_id',$post->id)->get();
...
}
You can use Route Model Binding to ensure that routes will find your model based on the provided key.
Your Post model will require that you add the following method:
public function getRouteKeyName()
{
return 'slug';
}
Then, in your routes, you can just refer the model directly, and binding will happen automatically:
public function post(App\Post $post)
{
$comments = Comment::where('post_id',$post->id)->get();
return view('content.post',compact('post','comments'));
}
This enables you to to use the following route:
Route::get('post/{post}', 'PagesController#post')->name('post.show');
Now, additionally, to ease up your reference of the comments, add them as relations to your Post model:
public function comments()
{
return $this->hasMany(Comment::class);
}
and your Comment model:
public function post()
{
return $this->belongsTo(Post::class);
}
This will allow you to shorten your controller method even more:
public function post(App\Post $post)
{
return view('content.post',compact('post'));
}
and in your Blade view do the following instead:
#foreach($post->comments as $comment)
From: {{ $comment->name }} blah blha
#endforeach
in web.php:
Route::get('post/{slug}', 'PagesController#post')->name('post.show');
in controller:
public function post($slug)
{
$post = Post::where('slug',$slug)->first();
$comments = Comment::where('post_id',$post->id)->get(); //use founded_post_id to find it's comments
return view('content.post',compact('post','comments'));
}
If there is one controller yii2 with one model in which, for example, the outline only:
class MyController class extends Controller {
public function actionCreate() {
$valid = $model->validate();
}
}
Need the return from aftersave, which is a message indicating if the email was able to be sent or not, and all the attributes were inserted.
afterSave in the model:
public function afterSave($insert, $changedAttributes) {
if(!$this->isNewRecord) {
try {
Yii::$app->mailer->compose()
// email composition here
->send();
return 'mail sent';
catch (\Swift_SwiftException $exception) {
return 'email undeliverable'. $exception->getMessage();
}
}
}
Can the return from afterSave be accessed by the controller?
No, you will not be able to access any of those messages, because:
In the controller you are calling $model->validate() and afterSave() will never be called. You would need to call $model->save().
afterSave() is not supposed to return anything, so the value you are returning is lost. See the function definition in the official documentation here
No, it's not gonna trigger the afterSave event with your code. \yii\db\BaseActiveRecord::afterSave is being triggered in 2 places
\yii\db\BaseActiveRecord::updateInternal
\yii\db\ActiveRecord::insertInternal
and if you take a look at \yii\base\Model::validate you'll see that afterSave isn't calling in here.
I have this model for Author:
<?php
class Author extends Eloquent {
public function albums()
{
return $this->belongsToMany('Album')->withPivot('city');
}
}
And this model for Album:
<?php
class Album extends Eloquent {
public function artist()
{
return $this->belongsTo('Artist');
}
public function authors()
{
return $this->belongsToMany('Author')->withPivot('city');
}
}
To get a model I can easily do this:
$author = Author::where('name','=','Chester Bennington')->first()->toJson();
and it'll return something like this (as JSON):
{"id":3,"name":"Chester Bennington","created_at":"2014-06-29 16:10:21","updated_at":"2014-06-29 16:10:21"}
See that it won't return the albums related to it. To get the albums I would have to do this: $author->albums->toJson()
Since I'm doing an API and it returns everything as JSON, is there a way to get the model and ALL its attributes without specifying which ones to get??
If you eager load the relationships you want, it'll be included in your JSON:
Author::with('albums')->where('name', 'Chester Bennington')->first()->toJson();