laravel 5 model method not working - laravel-5

I have a table with rows with column contain string "this\dIs\dA\dString"
$callPlans = CustomerCallPlan::where('customer_id', $customer->id)->get();
I get the values like above and expected string 'thisXIsXAXString'
as you guess I replace '\d' with 'X'. to do this I use method below inside model class.
class CustomerCallPlan extends Model
{
protected $table = 'customer_callplan';
protected $fillable = [
'template',
'priority',
'customer_id',
'strip',
'add_number',
'actiontype',
'data'
];
public function getNumbertemplateAttribute() {
return str_replace('\d', 'X', $this->attributes['template']);
}
}
But somehow data comes to model without replaced.. what might be cause this ??

This is called an accessor and it'll automatically be called by Eloquent when attempting to retrieve the value. The method name should be the camel cased name of the column you wish to access, prepended by get and followed by Attribute, for example getColumnNameAttribute() will take the column colum_name.

Related

Laravel 8 - I have an error in when using method in Model when using paratheses with the method

I have two models [The relation is one-many / Category-Trip]:
Category Model Code:
class Category extends Model
{
use HasFactory;
protected $fillable = [
'id',
'category_name',
'category_desc',
'category_img',
];
public function trip() {
return $this->hasMany(Trip::class);
}
}
Trip Model Code:
class Trip extends Model
{
use HasFactory;
protected $fillable = [
'name',
'description',
'max_visitors',
'price',
'date',
'image',
'guide_id',
'category_id',
];
public function category()
{
return $this->belongsTo(Category::class);
}
}
when I use this code, I will get this error:
TypeError Symfony\Component\HttpFoundation\Response::setContent():
Argument #1 ($content) must be of type ?string,
Illuminate\Database\Eloquent\Relations\BelongsTo given, called in
C:\Users\Orange\Desktop\ON
GITHUB\Tours-Booking\vendor\laravel\framework\src\Illuminate\Http\Response.php
on line 72
$trip = Trip::findOrFail(1);
return $trip->category();
But when write this without paratheses, i will not get this error, what is the problem?
$trip = Trip::findOrFail(1);
return $trip->category;
As a user explained (but not fully):
You are returning a relationship in your controller, but that is not valid (based on the error). Because BelongsTo cannot be serialized to a string, it tries to return the BelongsTo object, hence giving you that error (look, it is saying it is wanting null or a string, but you are returning BelongsTo).
When you do $model->relation (without ()), that means it will try to get all the data that satisfies the relation and store it as a Category in $model->relation (because it is a BelongsTo), but when you use $model->relation() you creating a query so you can query the relation with whatever you want/need, like $model->relation()->where('status', 'Active')->get()...
You have 2 solutions: either return $trip->category (it is going to be a Category object/model) or $trip->category()->get() or any query but use ->get() (will return a Collection) or ->first() (will return a Category model) at the end...
Read the documentation again so you understand better now: Relationships and First vs Get and BelongsTo documentation.
When you call the method its instantiating a eloquent instance in which you can extend it to a query which will give you a Category model
example (this might not be the most appropriate example)
$trip = Trip::findOrFail(1);
return $trip->category()->where('category_name', 'something')->first();
And the latter returns a collection.

Laravel updateOrCreate ignores 1 field

I have the following updateOrCreate:
protected $fillable = ['type', 'token', 'expires_on'];
$access = Ebaytoken::updateOrCreate(
['type' => 'access_token'],
['token' => $request->access_token, 'expires_on' => $request->access_token_expires_on]
);
However it gives this error:
SQLSTATE[23000]: [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]Cannot insert the value NULL into column 'type', table 'toolkit.dbo._ebaytokens'; column does not allow nulls. INSERT fails. (SQL: insert into [_ebaytokens] ([token], [expires_on], [updated_at], [created_at]) values (access token goes here, 2020-03-09 09:01:02, 2021-07-12 14:18:31.031, 2021-07-12 14:18:31.031))
It's ignoring the type column in my query.
What have I done wrong here?
You have defined your own constructor on your model which is not its default constructor it gets from the Model class. The constructor on Model takes the attributes as an array and fills them on the instance. This way you can create a new instance of a Model with attributes. This is the important part of that constructor:
public function __construct(array $attributes = [])
{
...
$this->fill($attributes);
}
Without that you wouldn't be able to create a new Model instance with attributes filled.
This is what updateOrCreate is doing:
public function updateOrCreate(array $attributes, array $values = [])
{
return tap($this->firstOrNew($attributes), function ($instance) use ($values) {
$instance->fill($values)->save();
});
}
It is retrieving by the attributes or creating a new instance with the attributes (first argument). Eventually down those method calls you get to Model::newInstance which is doing this:
$model = new static((array) $attributes);
So without that constructor it can't create that new instance of the Model with those attributes, which in this case because of calling updateOrCreate is the first array you pass to updateOrCreate. It can fill the instance with the second array though as that is just a call to fill on the Model instance.
I would suggest to not override the constructor on a Model but if you really need to you could show what you are trying to do and perhaps you could get some advice or ideas on how to go about it.

Laravel - How to change response format for specific fields

I've "Product" model.
And need to change some value formats for only responses.
For example;
I've "price" on database as decimal (11,2).
I want this as "1.000.000,00" format on response.
Or created_at field to "Carbon::parse($this->created_at)->toDayDatetimeString()"
Or I want to add 3 specific columns with my user attribute, on response. (is_allowed etc.)
How can this be possible on model?
How can I response like that?
You can use Mutator and Accessor to set format :
https://laravel.com/docs/8.x/eloquent-mutators#accessors-and-mutators
public function setDateAttribute($date) {
$this->attributes['date'] = Carbon::createFromFormat('Y-m-d', $date);
}
public function getFirstNameAttribute($value)
{
return ucfirst($value);
}
As a best practice in Laravel you can use Eloquent Resources: Eloquent Resources
It's basically a "transformer" between models data and API/Responses Output.
The only one thing to notice is that in the Resource files yout must specify all fields and relations (if needed) of the Model manually.
In the toArray() function you can modify the type of all data of your model as you prefer.
If not, you can access the new field by $model->my_custom_field (Laravel can resolve the name of the getter function automatically).
public function toArray($request)
{
$editedFieldValue = doSomething();
return [
'my_field' => $editedFieldValue,
'other_field' => '',
];
}
If you want to do that in Model, you can create customs fields:
class MuModel extends Model
{
protected $appends = ['my_custom_field'];
public function getMyCustomFiledAttribute(){
$newData = doSomething($this->existent_field);
return $newData;
}
}
The $appends variable add the new fields to all responses generated from the Model, as a normal database field.
P.S.: You can create a getAttribute() function for existent database attribute and return the value as you want!
For example: getCreatedAtAttribute()

Additional attributes in Laravel all request

Good day.
For example, I have a model People with fields/attributes:
name
surname
and the model also has this method:
public function FullName()
{
return "{$this->name} {$this->surname}";
}
if I make the next request:
$p = $people->all();
I'll get collection with names and surnames as attributes
how i can make function execution for each in all() request?
What is the best practice?
Well, depends on what kind of result do you want.
OPTION A: Have name, surname and full_name in all the items of the array.
Eleazar's answer is correct, but a little bit incomplete.
1. Define a new accessor in your model.
This will define a new attribute in your model, just like name or surname. When the new attribute is defined, you can just do $user->full_name to get the attribute.
As the documentation says, to define an accessor you need to add a method in your model:
// The function name will need to start with `get`and ends with `Attribute`
// with the attribute field in-between in camel case.
public function getFullNameAttribute() // notice that the attribute name is in CamelCase.
{
return $this->name . ' ' . $this->surname;
}
2. Append the attribute to the model
This will make the attribute to be considered just like any other attribute, so whenever a record of the table is called, this attribute will be added to the record.
To accomplish this you'll need to add this new value in the protected $appends configuration property of the model, as you can see in the documentation:
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
/**
* The accessors to append to the model's array form.
*
* #var array
*/
// notice that here the attribute name is in snake_case
protected $appends = ['full_name'];
}
3. Make sure that this attribute is visible
Notice this important part of the docs:
Once the attribute has been added to the appends list, it will be
included in both the model's array and JSON representations.
Attributes in the appends array will also respect the visible and
hidden settings configured on the model.
4. Query your data.
When doing the following:
$p = $people->all();
The $p array should have name, surname and also the new full_name attribute for each item.
OPTION B: Just get the full_name for specific purposes.
You can do the following when querying, iterate each result to get the attribute.
Now to do this you can iterate the collection with a foreach sentence, but given that whenever querying data, the array returned is always a Collection instance, so you simply use the map function:
$full_names = $p->map(function ($person) {
// This will only return the person full name,
// if you want additional information just custom this part.
return $person->fullname;
});
Using collection higher order messages it can be even shorter:
$full_names = $p->map->fullname;
I use the following:
public function getFullNameAttribute()
{
return "{$this['name']} {$this['lastname']}";
}
and then, I add it in appends:
class User extends Authenticatable {
protected $appends = ['fullname'];
}
What do you think?
In your model write a function to concatenate the name
public function getFullNameAttribute() {
return ucfirst($this->first_name) . ' ' . ucfirst($this->last_name);
}
now you can call it this way
$user = User::find(1);
echo $user->full_name;
or
Auth::user()->full_name;

custom `id` name using `insertGetId` fluent method of Laravel

According to Laravel's documentation:Inserts
Note: When using PostgreSQL the insertGetId method expects the auto-incrementing column to be named "id".
So, is there a workaround for a custom id name while using inserGetId. i.e.
$id = DB::table('users')->insertGetId(
['email' => 'john#example.com', 'votes' => 0]
);
You can use the Eloquent method Model::create() to return the object inserted, and obtain the object id, whatever his name is.
Try this:
$user = User::create(['email'=>'john#ecample.com','votes'=>0]);
$id = $user->custom_id;
This works if your User model is like:
class User extends Eloquent {
//This custom_id column needs to be of type serial in your table
protected $primaryKey = 'custom_id';
protected $fillable = ['email','votes'];
//...more code ...
}
I hope this works for you

Resources