boot self::creating() not working with insert in laravel - laravel

I want to insert multiple rows using
Model::inset($dataArray)
but it's not firing boot method.
self::creating()
Is there any solution ?
I want to insert multiple rows at once to save time but its not calling laravel observer method self::creating().

Use createMany to achieve this on relationShips:
https://laravel.com/docs/9.x/eloquent-relationships#the-create-method
If you want to do this on the model directly, you can just create the function:
ExampleModel:
public static function createMany($records){
foreach($records as $record) {
$this->create($record);
}
}
If you look at the create() function in the model:
Illuminate\Database\Eloquent\Builder;
/**
* Save a new model and return the instance.
*
* #param array $attributes
* #return \Illuminate\Database\Eloquent\Model|$this
*/
public function create(array $attributes = [])
{
return tap($this->newModelInstance($attributes), function ($instance) {
$instance->save();
});
}
it uses the save() function that dispatches the event "creating": https://laravel.com/docs/9.x/eloquent#events
Save() will call $this->performInsert($query)
and
performInsert does $this->fireModelEvent('creating') as well as $this->updateTimestamps()
As #Techno mentioned: https://laravel.com/docs/9.x/eloquent#upserts:~:text=When%20issuing%20a,a%20mass%20update

Related

How to detect update event in model in Laravel 8

Good day to all
The situation is as follows
In the controller, in the update method, I try to update the object
There is an image in the fields of this object
Wrote a trait to process this field and load an image
In the model itself, I called the update method, which just determines the event of updating the object
The problem lies in the following image in the specified directory is loaded and the entry itself in the database does not change
Here is my code
Controller
Model
Trait
There is extra code in the model
public function update(Request $request, MainHeader $mainHeader): RedirectResponse
{
$mainHeader->update([
'language_id' => $request->language_id,
'brandLogoImage' => $request->file('brandLogoImage'),
'homeTitle' => $request->homeTitle,
'ourProjectsTitle' => $request->ourProjectsTitle,
'contactTitle' => $request->contactTitle,
'feedbackTitle' => $request->feedbackTitle,
]);
return redirect()->route('admin.header.index')->with('success', 'Данные успешно обновлены');
}
public function setBrandLogoImageAttribute($value): string
{
return $this->uploadImage('brandLogoImage', $value);
}
public function update(array $attributes = [], array $options = [])
{
$this->uploadImage('brandLogoImage', $attributes['brandLogoImage']);
$this->setBrandLogoImageAttribute($attributes['brandLogoImage']);
return parent::update($attributes, $options); // TODO: Change the autogenerated stub
}
protected function uploadImage(string $attr, $value): string
{
$uploadDir = public_path('uploads/');
$imageDir = public_path('uploads/image/');
if (!file_exists($uploadDir)){
mkdir($uploadDir);
}
if (!file_exists($imageDir)){
mkdir($imageDir);
}
if (!file_exists(public_path("uploads/image/$this->table/"))){
mkdir(public_path("uploads/image/$this->table/"));
}
$imageName = Str::random(12) . '.png';
Image::make($value)->save(public_path("uploads/image/$this->table/$imageName") , 100);
return $this->attributes[$attr] = (string) "uploads/image/$this->table/$imageName";
}
if you call the update methode in your model then you are overriding the default update() of the model class , its not listening to the event it simply runs your code before parent:: , so you need to make sure that the changes you are making does not get overwitten by the parent call .
regarding your question on how to detect update , if you want to perform anything before update than i advise you to use eloquent events or use observers , Observers listen to various events regarding your model like updating or updated .. but i think if its only for updating event than you should use event using closure
for example :
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
/**
* The "booted" method of the model.
*
* #return void
*/
protected static function booted()
{
static::updating(function ($user) {
// do what you want
});
}
}
If your pupose

Laravel relationship with additional where statement

I know I can define a relationship by
Class Users extends Model{
function profile(){
return $this->hasOne(Profile::Class);
}
}
is there a way like adding extra query to the relationship like other than foreign key and local key that is available to define, I want to only get those records of Profile model that field active contains a value of 1. Profile model has a field named active. Any help, ideas is greatly appreciated, thank you in advance.
you can simply try
return $this->hasOne(Profile::Class)->where('active', 1);
but better approach will be using Scope like this.
create a folder app/Scopes and add a new file ActiveUserOnly.php
place this code there
namespace App\Scopes;
use \Illuminate\Database\Eloquent\Builder;
use \Illuminate\Database\Eloquent\Scope;
use \Illuminate\Database\Eloquent\Model;
class ActiveUsersOnly implements Scope {
/**
* #inheritdoc
*
* #param Builder $builder
* #param Model $model
*
* #return Builder|void
*/
public function apply( Builder $builder, Model $model ) {
return $builder->where( 'active', '=', true );
}
}
add this code to the top of Profile model.
use App\Scopes\ActiveProfilesOnly;
add this code in your Profile model.
protected static function boot() {
parent::boot();
static::addGlobalScope( new ActiveProfilesOnly() );
}
then this code will work in your User model.
Class Users extends Model{
function profile(){
return $this->hasOne(Profile::Class);
}
}

Laravel/Livewire: Use withTrashed() on model route binding on to show deleted records

In the list I display the latest topic, including those that is deleted.
function latest()
{
return Topic::withTrashed()->latest();
}
For displaying a single topic I have a Livewire component with that topic passed into it.
class ShowTopic extends Component
{
public $topic;
public function mount(Topic $topic)
{
$this->topic = $topic;
}
public function render()
{
return view('livewire.show-topic', [
'topic' => $this->topic,
]);
}
}
But when I go to a single topic that is deleted, it doesn't show. How can I use withTrashed() on model route bindings to show deleted records with my Livewire component?
You can overwrite the resolveRouteBinding() method on your Eloquent model, and conditionally remove the SoftDeletingScope global scope.
Here I'm using a policy for that model to check if I can delete the model - and if the user can delete it, they can also see it. You could implement any logic you want, or remove the global scope for all requests if that is more suitable for your application.
use Illuminate\Database\Eloquent\SoftDeletingScope;
class Topic extends Model {
// ...
/**
* Retrieve the model for a bound value.
*
* #param mixed $value
* #param string|null $field
* #return \Illuminate\Database\Eloquent\Model|null
*/
public function resolveRouteBinding($value, $field = null)
{
// If no field was given, use the primary key
if ($field === null) {
$field = $this->getKey();
}
// Apply where clause
$query = $this->where($field, $value);
// Conditionally remove the softdelete scope to allow seeing soft-deleted records
if (Auth::check() && Auth::user()->can('delete', $this)) {
$query->withoutGlobalScope(SoftDeletingScope::class);
}
// Find the first record, or abort
return $query->firstOrFail();
}
}

Laravel Model binding including SoftDeleted values

I have a Route::resource('sheeps', 'SheepsController') with a show function returning a resource:
public function show(Sheep $sheep)
{
return new SheepResource(
$sheep->load('farm')
);
}
So when I call /api/sheeps/123 should I get Sheep 123, but... I don't get it, because it's softdeleted.
How to fix the resource that it also searches in softdeleted results?
You should use this :
in your RouteServiceProvider :
/**
* Define your route model bindings, pattern filters, etc.
*
* #return void
*/
public function boot()
{
parent::boot();
Route::bind('sheep', function ($value) {
return Sheep::withTrashed()->find($value);
});
}
Try this:
public function show($id)
{
$sheep = Sheep::withTrashed()->findOrFail($id);
and update your route
or
public function show(int $sheep)
{
$sheep = Sheep::withTrashed()->findOrFail($sheep);
or
use Explicit Binding

Relationships in InfyOm Generator

I have News and NewsCategories models which I have generated CRUD for using the relationship option.
I now need to generate a select list for the News model to select the NewsCategory it belongs to.
I know how to do this in the model but no idea how to do it using the repository pattern.
I can't see any examples in the docs so any help with this would be appreciated.
Thanks
NewsRepository
/**
* Configure the Model
**/
public function model()
{
return News::class;
}
News Model
/**
* #return \Illuminate\Database\Eloquent\Relations\BelongsTo
**/
public function newsCategory()
{
return $this->belongsTo(NewsCategory::class);
}
News Controller
/**
* Show the form for creating a new News.
*
* #return Response
*/
public function create()
{
return view('news.create');
}
/**
* Store a newly created News in storage.
*
* #param CreateNewsRequest $request
*
* #return Response
*/
public function store(CreateNewsRequest $request)
{
$input = $request->all();
$news = $this->newsRepository->create($input);
Flash::success('News saved successfully.');
return redirect(route('news.index'));
}
If your repository extends InfyOm\Generator\Common\BaseRepository. The repository should update the model relations by it self. Just pass the relation values alongside the other inputs with the correct keys.
However, for deleting and reading (let's call them actions), you will need to query your data.
You can do that using repository methods, scope queries, or criteria classes.
(and call those filters).
Repository Methods:
// inside your controller
// some repository filtering method
$this->repository->whereHas('newsGroup', function($query){...});
$this->repository->hidden(['field_to_hide']);
...
// some action: delete, all or findWhere...
$this->repository->delete();
Scope Queries are callbacks that apply some queries on the model eloquent and return it.(unlike Eloquent scopes which accept and return Database\Eloquent\Builder)
$this->repository->scopeQuery(
function ($model){ return $model->where(...);
});
Or your
// some action: delete, update or findWhere...
$this->repository->delete();
The Criteria Way: you will create a class responsible on querying. It is an overkill for the simple use-cases.
// inside the controller
$this->repository->pushCriteria(new NewsBelongingToCategory ($group_id));
// App\Criteria\NewsBelongingToCategory.php
class NewsBelongingToCategory implements CriteriaInterface {
private $group_id;
public function __construct($group_id){
$this->group_id = $group_id;
}
public function apply($model, NewsRepositoryInterface $repository)
{
$group_id = $this->group_id;
$model = $model->whereHas('newsCategory',
function ($query) use ($group_id){
$query->where('group_id', '=', $group_id);
});
return $model;
}
}
// in your controller
$this->repository->delete();
Note that some actions ignore specific filters. For example, delete(id) and update($attributes, $id) does not use criteria, in the other hand lists($column, $key) does not use scopes.

Resources