I have two tables one called "Events" and another one "Dependences", a dependency can have several events, that is the relation between them, what I try to do is show the data of an event, but also show the data of the dependency to which is related.
This is my controller where I bring the event:
class WelcomeController extends Controller
{
public function evento($slug){
$event = Event::where('slug', $slug)->first();
return view('evento', compact('event'));
}
This is the event model:
class Event extends Model
{
protected $table = 'events';
protected $fillable = [
'admin_id', 'dependence_id', 'place_id', 'name', 'slug', 'excerpt', 'body', 'status', 'file'
];
public function dependences(){
return $this->belongsTo('App\Dependence', 'dependence_id');
}
dependence model:
class Dependence extends Model
{
protected $table = "dependences";
protected $fillable = [
'name', 'slug'
];
public function events(){
return $this->hasMany('App\Event');
}
so I try to show it in the view:
#foreach($event->dependences as $dependence)
<a href="#">
{{$dependence->name}}
</a>
#endforeach
but I get this error: Trying to get property 'name' of non-object
these are the tables in the database:
enter image description here
the routes are fine, but I do not know what the problem is, I hope for your help, thank you very much.
There is only one dependency for every event. So you no need to use foreach.
$events->dependency->name
And you should change the relationship name from dependences to dependency.
class Event extends Model
{
public function dependency()
{
return $this->belongsTo('App\Dependence', 'dependence_id');
}
}
In view:
#foreach($events as $event)
{{ $event->dependency->name }}
#endforeach
You should access directly, as:
$event->dependence->name;
Since, belongsTo relationship brings one item.
Also add a check to see if the object is null, as in:
#if($event->dependece)
$event->dependence->name;
#endif
You could also use an #else in case you want to manage the null case somehow
Related
So I have Laravel Notifications setup and it's working perfectly fine.
However, I've extend the migration to include an additional id field:
$table->integer('project_id')->unsigned()->nullable()->index();
Thing is, I don't see how I can actually set that project_id field. My notification looks like this:
<?php
namespace App\Notifications\Project;
use App\Models\Project;
use App\Notifications\Notification;
class ReadyNotification extends Notification
{
protected $project;
public function __construct(Project $project)
{
$this->project = $project;
}
public function toArray($notifiable)
{
return [
'project_id' => $this->project->id,
'name' => $this->project->full_name,
'updated_at' => $this->project->updated_at,
'action' => 'project-ready'
];
}
}
So ya, I can store it in the data, but what if I want to clear the notification specifically by "project" instead of by "user" or by "notification".
For instance if they delete the project, I want the notifications for it cleared, but there is no way to access that unless I do some wild card search on the data column.
So is there anyway to insert that project_id in the notification ?
You could create an Observer to update the field automatically.
NotificationObserver.php
namespace App\Observers;
class NotificationObserver
{
public function creating($notification)
{
$notification->project_id = $notification->data['project_id'] ?? 0;
}
}
EventServiceProvider.php
use App\Observers\NotificationObserver;
use Illuminate\Notifications\DatabaseNotification;
class EventServiceProvider extends ServiceProvider
{
public function boot()
{
parent::boot();
DatabaseNotification::observe(NotificationObserver::class);
}
}
And you should be able to access the table using the default model to perform actions.
DatabaseNotification::where('project_id', 11)->delete();
this is my scenario:
I'm using Laravel 5.5.x.
I have two models, linked in one to many way.
class Artwork extends Model
{
//It has timestamps
protected $table = 'artworks';
protected $fillable = [
'artwork_category_id'
];
public function artworkCategory()
{
return $this->belongsTo('App\Models\ArtworkCategory');
}
}
class ArtworkCategory extends Model
{
use SoftDeletes;
protected $touches = ["artworks"];
/**
* #var string
*/
protected $table = 'artwork_categories';
protected $fillable = [
'category_name',
'acronym',
'deleted_at'
];
public function artworks()
{
return $this->hasMany('App\Models\Artwork');
}
}
Touch works correctly, so when I update an artwork category the related artworks updated_at field is updated.
But I need to listen the "touch" event on each artwork.
I've tried inserting "updated" listener on boot method in AppServiceProvider, but it is not fired.
Artwork::updated(function ($model){
\Log::debug("HERE I AM");
});
I've tried using an observer, but no luck.
class ArtworkObserver
{
public function updated(Artwork $artwork)
{
dd($artwork);
}
}
Boot method in AppServiceProvider:
Artwork::observe(ArtworkObserver::class)
Question:
Could somebody show me the right way to do it? Or tell me where am I wrong?
I was not good enough to find an example that helps me how to do it.
Update
I need to achieve this because I have to "fire" Scout to save updated data on Elasticsearch on Artwork index.
Most probably $touches uses mass update, and if you check Events section of Eloquent you'll find following:
When issuing a mass update via Eloquent, the saved and updated model events will not be fired for the updated models. This is because the models are never actually retrieved when issuing a mass update.
The best that I can think of is that, you update Artworks manually (instead of $touches) when a ArtworkCategory is updated:
class ArtworkCategory extends Model
{
use SoftDeletes;
protected $fillable = [
'category_name',
'acronym',
'deleted_at'
];
public function artworks()
{
return $this->hasMany('App\Models\Artwork');
}
public static function boot()
{
parent::boot();
static::updated(function($artworkCategory)
{
$artworkCategory->artworks->each(function($artwork) {
$artwork->setUpdatedAt($artwork->freshTimestamp());
$artwork->save(); /// Will trigger updated on the artwork model
});
});
}
}
I am trying to save a field from the created model event but for some reason the stripe_coupon_id column is never being saved. The created event does run as I've tested by trying a dd inside it and it does fire the event but just does not save that column.
class DiscountRate extends Model
{
public $table = "discount_rates";
public $primaryKey = "id";
public $timestamps = true;
public $fillable = [
'id',
'name',
'rate',
'active',
'stripe_coupon_id'
];
public static function boot()
{
parent::boot();
self::created(function ($discountRate) {
$coupon_id = str_slug($discountRate->name);
$discountRate->stripe_coupon_id = $coupon_id;
});
}
}
In my controller I simply call a service function which calls the default Laravel model create function:
public function store(DiscountRateCreateRequest $request)
{
$result = $this->service->create($request->except('_token'));
if ($result) {
return redirect(route('discount_rates.edit', ['id' => $result->id]))->with('message', 'Successfully created');
}
}
discount_rates table:
The created event is triggered after your model is created. In this case, you need to to call $discountRate->save() in the end in order to update the model which you just created.
As alternative, you can use creating event instead. In this case you don't need to call save() in the end because the model is not yet saved in your database.
A big difference in creating event is that the model does not have an id yet if you use auto-incrementing which is default behavior.
More info about events you can find here.
you have to set stripe_coupon_id before creating. So replace static::creating instead of self::created in boot method of DiscountRate model.
Trying to get Accessors in query builder but throwing error "Undefined property: stdClass::$shorcontent "
//controller
public function index(){
$articles = DB::table('articles')->paginate(10);
return view('articles.index', ['articles' => $articles], compact('articles'));
}
Here is the Model file with Accessors
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Article extends Model
{
protected $fillable = [
'user_id', 'content', 'live', 'post_on'
];
protected $guarded = ['id'];
public function getShortContentAttribute()
{
return substr($this->content,0, random_int(60, 150));
}
}
Here is the View
//article/index.blade.php View
<td class="col-md-6">{{ $article->shortcontent }} </td>
The same code working when i use eloquent instead of query builder, like this
public function index()
{
$articles = Article::paginate(10);
return view('articles.index', ['articles' => $articles], compact('articles'));
}
This answer is late and you might have found your solution, but hope it helps someone else.
Short answer, the DB facade doesn't have access to accessors and mutators defined in the model. Only objects made by instances of the model can have access to accessors and mutators.
I believe the issue here is that using the DB facade only creates the Query Builder without any reference to accessors or mutators you have set in the Article Model. DB facade only queries the database using the query builder and returns an object independent from the Article Model.
However, the Model facade will build a query builder but the instance of the object created will have access to accessors and mutators as it is an object instance of the Article Model class.
Check out this SO answer:
Difference between DB and Model facade
Accessors are only accessed once you attempt to retrieve the value of the attribute from the model instance, for example:
$article = Article::find(1);
$shortContent = $article->short_content;
This is explained further here
Thus if you wish to access accessors, then you would have to use the Model facade i.e. Article::paginate(10).
You are missing to append short_content attribute. Just add this
namespace App;
use Illuminate\Database\Eloquent\Model;
class Article extends Model
{
protected $fillable = [
'user_id', 'content', 'live', 'post_on'
];
protected $appends = ['short_content'];
protected $guarded = ['id'];
public function getShortContentAttribute()
{
return substr($this->content,0, random_int(60, 150));
}
}
I am trying to create a custom attribute inside of a Laravel Model. This attribute would be the same for all of the Model instances (static?). The goal is to use this attribute to populate a select dropdown when creating a Model instance. Example:
class User extends Model
{
protected $table = 'users';
protected $guarded = [ 'id' ];
public $timestamps = true;
protected $genders = ['male'=>'Male', 'female'=>'Female']; //custom
public static function getGenderOptions() {
return $genders;
}
}
Then when building out the form, I could do something like:
// UserController.php
$data['select_options'] = User::getGenderOptions();
return view('user.create', $data);
// create.blade.php
{!! Form::select( 'gender', $select_options ) !!}
This causes me to get the error:
Undefined variable: genders
I am trying to prevent cluttering my Controller with all of the select options, as there are also a few others I haven't included.
Thanks.
Modify Your protected $genders element and make it public+static. So then You can access it directly like so: User::$genders.
But...my personal decision would be to move constants to config file or some kind of helper.
I guess it should be
public function getGenderOptions() {
return $this->genders;
}
Or simply declare $genders as a static variable and use return self::$genders
Check the docs - Variable scope and Static Keyword