Laravel 8 Model not updating when using cviebrock/eloquent-sluggable - laravel

Using Laravel 8 with cviebrock sluggable, my models do not update when I made a change.
When I remove the use of sluggable from my models, they work! Showing that sluggable is the cause.

It turns out that there is a breaking change, which occurred on Laravel 8 for me.
Solution
The solution is to add the following code to each model for which you use sluggable on:
public function sluggableEvent(): string
{
return SluggableObserver::SAVED;
}
One can find a reference to the breaking change on the cviebrock/eloquent-sluggable github page: https://github.com/cviebrock/eloquent-sluggable
Slug no default value error, as a consequence of this change
You may get an error that your slug field has no default value, when SAVING, that is because the model will be updated without the slug, which will be updated when the model is SAVED.
To solve this problem, you can set the slug field to nullable() in the migration file, or at the database level make the field nullable and set the default value to NULL.
Observer event changes
Previously, one could check for slug changes using EventObserver#updating. This no longer works.
Instead, one can register a model event for 'slugging' or 'slugged' in AppServiceProvider.php.
For example (I have a model for events called Event, whereby I change the slug if an event date or title is changed):
Event::registerModelEvent('slugged', static function($event) {
// $event->slug (the new slug)
// $event->getOriginal('slug') (the old slug)
}
Bare in mind, for a newly created DB row for a model, $event->getOriginal('slug') will be NULL.
The "slugging" event is fired just before the slug is generated.
The "slugged" event is fired just after a slug is generated.

Related

when using laravel scout, searchable() isn't updating related models

I am having an issue getting related models to update with scout elastic search.
$event->priceranges()->delete();
$event->priceranges()->Create([
'price' => $ticket['ticket_price']
]);
$event->update([
'show_times' => $request->showtimes,
]);
$event->searchable();
In my database I see the event and price range tables update. However when I look at my elastic search data, only data on the event has been updated. Any related models are not updated.
If I make a second update to the model and price range model, then the elastic search data shows my data from the first update I made (it is always one update behind for related models)
I tried doing
$event->pricerange->searchable()
but gives me an error because I don't have a searchable index for pricerange, I am just using my event model and its relationship to index. Is there a way to force the update other than searchable()?
Looks like your relationship is being indexed in the Event model index, correct?
Probably it's not being updated because the relationships are already loaded, and Laravel doesn't update the relationship data that is already loaded, for example:
$event = Event::with('priceranges')->first()
var_dump($event->priceranges->count()): // outputs for example 5
$event->priceranges()->create([...]);
var_dump($event->priceranges->count()): // still outputs 5, meaning that the created pricerange is not loaded
So, to fix this issue you can reload the model before calling searchable():
$event = $event->fresh();
$event->searchable();
But, note that everytime you update, the searchable method is already being called, so you will be indexing it two times on every update.
So, alternatively you can update your toSearchableArray() method in Event model to get a fresh model before returning the data (I'm assuming that you are using the babenkoivan/scout-elasticsearch-driver).

TYPO3 cache behaviour with updated models

I have this weird behaviour from Typo3 6.2 LTS.
In my extension I have a Model with a FileReference Property. This property has a vaule != 0. This value does exist in sys_file_reference table.
Not the weird magic happens. If I try to access this file, I do only get a nullvalue instead of a FileReference- / FileObject.
We already cleared our cache (server and browser) but nothing. It's still null.
I appreciate every kind of help!
Greetz, Paddaels
I remember it was always hard to make a 1:1 relation from a domain model to a FileReference. I suggest you to use existing patterns and work with a ObjectStorage for that purpose.
You can copy the neccessary TCA from the existing tca of the tt_content table (field image for example). The Property annotation should look like:
/**
* #var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\Vendor\Extension\Domain\Model\FileReference>
* #lazy
* #cascade remove
*/
protected $propName;
Of course you have to create the FileReference Model in your own namespace. But you can extend the Extbase basemodel, so you dont have to write any methods.
To map your model to the sys_file_reference table you have to add some typoscript.
For that purpose create a ext_typoscript_setup.txt in your extensions folder and insert the following code (adjust namespace and modelname)
config.tx_extbase.persistence.classes {
Vendor\Extension\Domain\Model\FileReference.mapping {
tableName = sys_file_reference
}
}
After clearing the caches in the install tool (and making database migrations of course) it should work.
Explanations:
#lazy: Typo3 wont fetch all references at once, only if the property is accessed.
#cascade remove: Extbase will delete all sys_file_reference records related to your domain model once the model is deleted.

Using custom name of `name` field of Zizaco/entrust Package

I am working in a project that has a large postgreSQL database. The previous project was developed in Java from scratch. We are now developing that in Laravel. The previous system had user management system similar to Zizaco/entrust. So, we used in our system as well. The previous table had module table instead of permission table used in entrust. We have already configured that by changing the table name in config/entrust.php. However, the previous system has permission_name instead of name field used in entrust. How do I config entrust to use the unique permission_name instead of name field.
I am looking for a solution, so that we don't have to change in the sources of entrust because then upgrading it would break the system. Can it be configured in the model?
The Entrust package is hardcoded to use the name attribute, so there is no configuration value or anything to change that. However, one thing you can attempt is to define an accessor and mutator for the name attribute.
In your App\Permission model, define the following functions:
class Permission extends Model {
// accessor
public function getNameAttribute($value) {
return $this->permission_name;
}
// mutator
public function setNameAttribute($value) {
$this->attributes['permission_name'] = $value;
}
}
Documentation for accessors and mutators: http://laravel.com/docs/5.0/eloquent#accessors-and-mutators

creating a form field populated by a relationship in Laravel 4

I am trying to build a form for a Happening. The Happening references a Places table by place_id.
e.g. happening "OktoberFest" has a place_id 123 which corresponds in table Places to München
These are the relationships declared in the models:
For model Place:
public function happenings()
{
return $this->hasMany('Happening');
}
For model Happening:
public function place()
{
return $this->belongsTo('Place');
}
model Happening has a place_id field linking it to Place.
I am also using {{Form::model($happening, array('route' => array('happenings.update', $happening->id)...}} as form opening
Problem 1: how to create a {{Form::text('......')}} that will be properly prefilled with München when editing the happening Oktoberfest ?
Problem 2: I was trying to get that field to work as an ajax autosuggest (i.e. starting to pull suggestions from the Places table as soon as 3 characters have been entered). I have checked a few implementations but they don't seem to mix correctly with Problem 1
To try and solve Problem 1, I have tried the solution here
Laravel 4 Form builder Custom Fields Macro
but I was unable to make it work.
Long question, it's my very first on stack overflow, please be patient :)
If a Happening is linked to Place via the column 'place_id' you have to supply an id to save in your model/table.
There are a couple of ways that I can think of:
make a list of availble Places in a radio of select, the name will be 'place_id', the value the id of the Place en something like title for the value.
instead of displaying radio's or a select a textfield with autocomplete is a great solution if you got a lot of places. I won't go into detail how to implement it but the general idea is to autocomplete the typed in placename and on selection of that place to put the id of that place in a hidden field named 'placed_id'
After saving the form save your model with the posted place_id
(and check that id if it's valid and existing, never trust user input )

Validating unique field with HABTM join table

I'm struggling to work out how to validate a field in Model A that should be unique when combined with a field from Model B.
Here's an example to clarify my question:
Page hasMany SitesPage
SitesPage belongsTo Page, belongsTo Site
Page has a slug field which should be unique across a site. Pages can be attached to any site.
Page.id
Page.slug
SitesPage.id
SitesPage.site_id
SitesPage.page_id
I have a checkUniqueSlug() custom validation method in my Page model but can't validate the slug is unique to the site as the site_id is stored in SitesPage which isn't available in the Page model validate method ($this->data only contains Page model data).
I can't do the validation in the SitesPage model as SitesPage doesn't have a slug field and I can't see the Page post is SitesPage.
How do I create a custom validation to check the slug is unique to the site?
One solution is to move the slug into the SitesPage model but we need all shared pages to have the same slug. i.e. A shared "About Us" page must have an "about_us" slug irrespective of which site the page is attached to.
Another solution is to perform the validation in the controller before I save which would work but that feels wrong as the validation should be done in the model.
As there have been no answers and someone else might be looking for help, here's how I ended up with a solution:
As the controller is the only place where both model data is present in the data array, the call to validate has to be done there.
I offloaded the validation code to the model and called it with the following:
if (!empty($this->request->data)) {
if ($this->Model->specialMultiModelValidate($this->request->data) && $this->Model->save($this->request->data)) {
// model has validated and saved
}
else {
// model has failed to validate and save
  }
}
Hope someone finds this useful.

Resources