I need to use created_at field in two different type
public function getCreatedAtAttribute($value)
{
$time = new \Verta($value);
return $time->formatDifference();
}
this is my code and I need to use default created_at value as well
please help me
You can try to make another accessor with a different name (created_at_diff perhaps) for your special format:
public function getCreatedAtDiff()
{
return (new \Verta($this->attributes['created_at']))->formatDifference();
// or $this->created_at instead of $this->attributes['created_at']
}
Then you can access it via $model->created_at_diff.
Related
I have a MySQL table that receives many different Jotform reports in JSON payloads. This has helped tremendously in capturing queryable data quickly without adding to the front-end developer's workload.
I created an eloquent model for the table. I now would like to be able to create models that extend it for each Jotform we create. I feel like it will increase the readability of my code drastically.
My eloquent model is called RawDataReport. It has created_at, updated_at, data, and report name columns in the table. I want to create the model ShiftInspectionReport extending the RawDataReport.
I have two JotForm reports one is called Shift Inspection Report and one is called Need Inspection Report. Both are part of the ShiftInspectionReport model.
So I need to query the RawDataReports table for any reports matching those names. I frequently need to query the RawDataReports report_name column with either one or more report names.
To help with this I created a local scope to query the report name which accepts either a string report name or an array of string report names. Here is the local scope on the RawDataReports model.
protected function scopeReportName($query, $report_name): \Illuminate\Database\Eloquent\Builder
{
if (is_array($report_name)) {
return $query->orWhere(function ($query) USE ($report_name) {
ForEach($report_name as $report) {
if (is_string($report) === false) {
throw new \Exception('$report_name must be an array of strings or a string');
}
$query->where('report_name', $report);
}
});
} else {
if (is_string($report_name) === false) {
throw new \Exception('$report_name must be an array of strings or a string');
}
return $query->where('report_name', $report_name);
}
}
EDIT - after comments I simplified the reportName scope
protected function scopeReportName($query,array $report_name): \Illuminate\Database\Eloquent\Builder
{
return $query->whereIn('report_name',$report_name);
}
Now in my ShiftInspectionReport model, I'd like to add a global scope that can use that local scope and pass in the $report_name. But according to this article, Laravel 5 Global Scope with Dynamic Parameter, it doesn't look like Laravel global scopes allow you to use dynamic variables.
I could just create a local scope in ShiftInspectionReport but the readability would look like
$reports = ShiftInspectionReport::shiftInspectionReport()->startDate('2021-05-15')->get()
when I'd really like to be able to just call
ShiftInspectionReport::startDate('2021-05-15')->get()
Any suggestions or comments would be appreciated.
Thank you
Thanks to IGP I figured out that I can just call the local scope right from my boot function.
My extended class looks like this now and it works.
class ShiftInspection extends RawDataReport
{
use HasFactory;
protected static function booted()
{
static::addGlobalScope('shift_inspection_report', function(\Illuminate\Database\Eloquent\Builder $builder) {
$builder->reportName(['Shift Safety Inspection','Need Safety Inspection']);
});
}
}
Im trying to give model attribute values another value when they are blank,
At the moment this is what I'm working with in my model:
public function getAttribute($property){
if(blank($this->attributes[$property])){
return $this->attributes[$property] = '-';
}else{
return $this->attributes[$property];
}
}
It works, but I dont think this is the right way to do it.
Im looking for a proper way of doing this.
example:
lets say the value in the database is NULL,
I want it to show "-" when displaying, but I dont want to save "-" in the database.
(I also don't want to use "get...Value" mutators for every value)
Solution 1
Since PHP 7 there is a new feature called the Null Coalescing operator. It returns the first operator when it exists and is not NULL:
{{ $model->attribute ?? '-' }}
Which is the same as this:
{{ isset($model->attribute) ? $model->attribute : '-' }}
Solution 2
Another solution would be a little bit harder, but doable:
Create a base model to which you extend all the other models:
class BaseModel extends Model {
protected $emptyAttributes = [];
protected function getAttribute($property)
{
if (in_array($property, $this->emptyAttributes) && blank($this->attributes[$property])) {
return '-';
}
else {
return $this->attributes[$property];
}
}
}
Now extend all the models you want to this new class and create an array of 'attributes to replace':
class User extends BaseModel {
protected $emptyAttributes = ['name', 'email'];
}
This should automatically replace the attributes name and email when they are empty, NULL or a string of only spaces.
Side note:
You could also move the functionality to a trait (which could be a more elegant solution, but that's up to you).
Im trying to use a laravel accessor to modify the content of a column when retrieving it. Im doing it like this:
On my model:
public function getMyColumnAttribute($value)
{
//Modify the content
return $value.'tttt';
}
On my controller:
public function test()
{
return MyModel::select('my_column')->find(1);
}
This works perfectly when the column in my DB is named 'my_column', but my entire database use camel case, so the actual name of the column is myColumn and the accessor just dont work in that case, I mean, it does return the value of my column, but without the modification I did in the accessor. I think it must be a way to it but I cant find how.
Thanks for the help
EDIT
I just realized that while this doesnt work: (myColumn is of type time on a MySql DB)
public function test()
{
return MyColumn::select('myColumn')->find(1);
//returns {"myColumn":"08:00:00"}
}
This acctually do what I expect
public function test()
{
$result = MyColumn::select('myColumn')->find(1);
return $result->myColumn;
// returns 08:00:00tttt
}
accessor doesnt modify the column raw data, it is used on create a new Attribute
use Mutator, save the modifyed raw data to db
use Accessor, get the raw data and modify it and assign to a new attribute
in your case
public function getMyColumnAttribute()
{
//Modify the content
return $this->attributes['type_column_name_here'] . 'tttt';
}
public function test()
{
// myColumn = the column name
$result = MyColumn::select('myColumn')->find(1);
// this is return the column value 08:00:00
return $result->myColumn;
// this will return accessor value 08:00:00tttt
return $result->my_column;
}
getMyColumnAttribute will convert to my_column
Is it possible to load additional attributes into model instance without multiple queries or hackery? Let me explain:
// I got a tiny model with only id loaded
$model = Model::first(['id']);
// Then some code runs
// Then I decide I'd need `name` and `status` attributes
$model->loadMoreAttributes(['name', 'status']);
// And now I can joyously use name and status without additional queries
$model->name;
$model->status;
Does Eloquent have something similar to my fictional loadMoreAttributes function?
Notice kindly that I'm not a novice and am very well aware of Model::find($model->id) and such. They're just too wordy.
Thanks for your attention in advance.
You may extend the Eloquent model to have this loadMoreAttributes method like so:
use Illuminate\Database\Eloquent\Model;
class YourModel extends Model
{
public function loadMoreAttributes(array $columns)
{
// LIMITATION: can only load other attributes if id field is set.
if (is_null($this->id)) {
return $this;
}
$newAttributes = self::where('id', $this->id)->first($columns);
if (! is_null($newAttributes)) {
$this->forceFill($newAttributes->toArray());
}
return $this;
}
}
This way you can do this on your model:
$model = YourModel::first(['id']);
$model->loadMoreAttributes(['name', 'status']);
LIMITATION
However there's a limitation to this hack. You may only call loadMoreAttributes() method if the unique id of your model instance is already fetched.
Hope this help!
I'm not sure this is a real relation. I will try to explain the best way I can.
So first of all, I have three models :
Appartement,
AppartementPrice
The AppartementPrice depends on :
- appartement_id
I would like the AppartementPrice to be retrieve like that :
If there is a specific price for the appartement, then retrieve it, If not retrieve the price for all appartement which is stored in the database with an appartement_id = 0.
So basically what I would like is to do something like that :
public function price()
{
if(isset($this->hasOne('AppartementPrice')->price) // Check that relation exists
return $this->hasOne('AppartementPrice');
else
return $this->hasOne('AppartementPrice')->where('appartement_id', '0');
}
But this is not working.
It does not retrive me the default price.
I guess anyway this is not a best practice ?
I first tried to get the informations like that :
//Check if appartment has a specific price or retrieve default
if($priceAppartement = AppartementPrice::getPriceByCompanyAppartement($this->id))
return $priceAppartement;
else
return AppartementPrice::getDefaultPrice();
But I had this error :
Relationship method must return an object of type Illuminate\Database\Eloquent\Relations\Relation
when doing :
echo $app->price->price;
How can I check that a relation exists ? And is there a way to do as I describe ?
Thank you
You can't replace relation like this, as what you intend is not logical - you want to retrieve relation that doesn't exist.
Instead you can do this:
public function getPriceAttribute()
{
return ($this->priceRelation) ?: $this->priceDefault();
}
public function priceDefault()
{
// edit: let's cache this one so you don't call the query everytime
// you want the price
return AppartmentPrice::remember(5)->find(0);
}
public function priceRelation()
{
return $this->hasOne('AppartementPrice');
}
Then you achieve what you wanted:
$app->price; // returns AppartmentPrice object related or default one
HOWEVER mind that you won't be able to work on the relation like normally:
$price = new AppartmentPrice([...]);
$app->price()->save($price); // will not work, instead use:
$app->priceRelation()->save($price);
First of all something really important in Laravel 4.
When you do not use parentheses when querying relationship it means you want to retreive a Collention of your Model.
You have to use parentheses if you want to continue your query.
Ex:
// for getting prices collection (if not hasOne). (look like AppartementPrice)
$appartment->price;
// for getting the query which will ask the DB to get all
//price attached to this appartment, and then you can continue querying
$priceQuery = $appartment->price();
// Or you can chain your query
$appartment->price()->where('price', '>', 0)->get() // or first() or count();
Secondly, your question.
//Appartement Model
// This function is needed to keep querying the DB
public function price()
{
return $this->hasOne('AppartementPrice')
}
// This one is for getting the appartment price, like you want to
public function getAppartmentPrice()
{
$price_object = $this->price;
if (!$price_object) // Appartment does not have any price {
return AppartementPrice->where('appartement_id', '=', 0)->get();
}
return $price_object;
}