Set global where clause when I retrive data using laravel eloquent - laravel

I have a table content. So when I retrive anything from that table using laravel eloquent, I need to set a global where clause Content::where('is_playlist', 1)->get();, so that every time I retrieve data from that table, I should automatically filtered with that particular where clause.

You can create a scope function in the model to filter that out e.g:
public function scopePlaylist($query)
{
return $query->where('is_playlist', 1);
}
This means you can easily call, Content::playlist()->get() and you'll have only playlist content.
I hope this is useful?

Related

Laravel mutators on specific situations

As I understand, mutators change your attribute on save function (create or update). Can I make mutator just for atrribute display to users, but leave default values on save function ?
In Eloquent Model when you do this:
public function getSomeNameAttribute($value)
{
return ucfirst($value);
}
That ^ will mutate the value for showing it later in views and it won't affect what is stored in DB table.
And also if you use a setter setSomeNameAttribute($value) you can pull the actual value from db table with:
$model->getOriginal('attribute_name'); // Laravel V. ^5.*
or
$model->getRawOriginal('attribute_name'); // Laravel V. ^8.*

Laravel Auditing - How To Get Specific Column Using Eloquent Model Method

I'm using Laravel Auditing Package to trace changes on my models.
I want to get a specific column of the foreign key in it's primary table before recording the events (create, update, delete) in the audit table.
There is a way the package helps get all the attribute of the foreign key, it's called Audit Transformation but it generates an error for me when displaying the details in the table i want to know if there's any eloquent model method to get the specific column info i need instead of using getattribute() method which gets the entire row of the item_id.
Audit Transformation Method
public function transformAudit(array $data): array
{
if (Arr::has($data, 'new_values.item_id')) {
$data['old_values']['item_name'] = Item::find($this->getOriginal('item_id'));
$data['new_values']['item_name'] = Item::find($this->getAttribute('item_id'));
}
return $data;
}
This is how it's stores in the database ephasis on the item_name.
{"item_id":"1","qty_received":"2","delivered_by":"John",
"received_by":"Abi","supplier":"Stores","date":"2019-11-26","item_name":{"item_id":1,"item_name":"Toner","colour":"Black","status":"Active",
"created_at":"2018-10-25 17:55:26","updated_at":"2018-10-25 17:55:26"}}
And this is the Item table schema
So in my scenario i'd want to store the item_name as Toner not the entire row of the item_id
Any suggestion will be welcomed, thanks in advance.
Add ->item_name->item_name after the function of Find.
if (Arr::has($data, 'new_values.item_id')) {
$data['old_values']['item_name'] = Item::find($this->getOriginal('item_id'))->item_name->item_name;
$data['new_values']['item_name'] = Item::find($this->getAttribute('item_id'))->item_name->item_name;
}

Laravel Backpack : Storing Belongs To Many relationships using custom view

I have a flight class and this flight has a custom view field like so:
This represents a belongs to many relationship which stores website_id / flight_id and pricing as pivot data in a pivot table.
The custom view uses JS to send this data back to the controller in this format:
{"1":{"price_adult":"434","price_child":"545"},"2":{"price_adult":"323","price_child":"324"},"3":{"price_adult":"434","price_child":"43"}}
Trying to send this data with the request doesn't create the relations fields, and because I do not have a flight ID at the point of creating this within the controller I can not loop this JSON to make the relations manually.
Can anyone point out what the best course of action is or if there is support for this? I took a look at the docs but they are woefully short and patchy in terms of being much help.
EDIT:
I should have said I can probably make this work using a custom name attribute on the model for the relation, then add a set mutator to loop this data and update the prices relation but I don't want to go down this route if there is support for this I am missing out of the box in backpack.
EDIT2:
Someone asked about the relation:
$this->belongsToMany(Website::class, 'website_pricing')->withPivot('price_adult', 'price_child');
This is working fine its not a problem with the relation working its how can I get backpack to store the data as a relation when the flight has no ID yet, or how can I pass the data I posted above in such a way that the backpack crud controller can handle it?
You may need to create a flight first, if no flight id is being provided. Can you explain the database relational structure more?
Basically thought I should post what I did because no one could provide an answer to this.
So basically you have to copy the store / update functions from the parent, changing a few lines.
$this->crud->hasAccessOrFail('create');
// fallback to global request instance
if (is_null($request)) {
$request = \Request::instance();
}
// replace empty values with NULL, so that it will work with MySQL strict mode on
foreach ($request->input() as $key => $value) {
if (empty($value) && $value !== '0') {
$request->request->set($key, null);
}
}
// insert item in the db
$item = $this->crud->create($request->except(['save_action', '_token', '_method']));
$this->data['entry'] = $this->crud->entry = $item;
// show a success message
\Alert::success(trans('backpack::crud.insert_success'))->flash();
// save the redirect choice for next time
parent::setSaveAction();
return parent::performSaveAction($item->getKey());
Basically any line which references a function in the parent class using $this->method needs to be changed to parent::
This line is what I used to submit the relations JSON string passed to the controller as relations $item->prices()->sync(json_decode($request->input('prices'), true));
This is done after the line containing $item = $this->crud->create as the item id that just got stored will be available at that point.

Laravel 5.3 - caching information schema queries

I use multiple domains for the same site structure, so almost all tables have the domain_id column. So, to NOT define the domain_id condition every time I am using the following approach (not sure if this is the best one)
I created BaseModel that other models are extending from and have this in boot method of that BaseModel
parent::boot();
static::addGlobalScope(new DomainScope());
and here is the apply method's content according to docs
if (Schema::hasColumn($model->getTable(), 'domain_id')) {
$builder->where('domain_id', '=', DOMAIN_ID);
}
This works great, however if I have e.g. 5 find queries on the same page, to the same table (just as an example) in debug panel I see 5 queries like this
select column_name from information_schema.columns where table_schema = 'my_db_name' and table_name = 'my_table_name'
Now, I perfectly understand that to check whether the column exists in the table it gets the information from information schema, but why it is making the same query for the same table over and over again. I would presume It should make one request and then cache it, and for subsequent requests just read from cache.
q1) Does laravel internally cache this query ? I am thinking maybe because debug is enabled, that is why each time its making a query ? but cant find any verification of this
q2) and if it does not cache, can I cache it manually. I checked the laravel docs for adding a cache, but the problem here that query is not done by me, so I cant figure out to simply use Cache::remember
Thanks
Well, I would suggest not to fire a query for checking if domain_id exists in the table every time. You can do this by simply adding a variable to your model that defines whether the model is a multi-domain model (has a domain_id column) or single domain model (no domain_id column) like so:
// In BaseModel.php
public $multiDomain = true; // override to false in your child model class if it's a single domain model
// In DomainScope apply method
if ($model->multiDomain)) {
$builder->where('domain_id', '=', DOMAIN_ID);
}
If you don't want to use the above, you can cache like so:
if(Cache::remember($model->getTable() . "_domain", $minutes, function() use($model) {
return Schema::hasColumn($model->getTable(), 'domain_id');
}) {
$builder->where('domain_id', '=', DOMAIN_ID);
}

Laravel / Eloquent hasMany relationship with no foreign key

I have a model (Client) with a hasMany relationship to another (Client_option).
The two tables are in different databases (so there is a list of clients, and then each client has their own database with an options table within).
In my Client class I want my options() method to return the entire contents of the options table (it knows which client db to look for). As it is I get an error because the column client_id does not exist in the options table. I can of course create that column and populate every row with the client's id, but I'd only be doing it to keep Eloquent happy so would rather avoid that little messiness.
Thanks in advance for any input!
Geoff
This will allow you to work with it as a relation, call it as dynamic property $user->options, bulk save with push method and so on:
public function options()
{
// it will use the same connection as user model
$options = ClientOption::on($this->getConnectionName())->get();
// if options model has its own, then simply
// $options = ClientOption::get();
$this->setRelation('options', $options);
return $options;
}
public function getOptionsAttribute()
{
return (array_key_exists('options', $this->relations))
// get options from the relation, if already loaded
? $this->getRelation('options')
// otherwise call the method and load the options
: $this->options();
}

Resources