For formatting some date column via casts, for example:
protected $casts = [
'deadline' => 'date:d/m/Y',
];
when getting column, it'll return carbon instance:
dd($model->deadline);
// Illuminate\Support\Carbon #1671235200 {#1542 ▶}
But even when it's casted to string, it won't be formatted as specified in cast:
dd( (string) $model->deadline );
// "2022-12-17 00:00:00"
Just when I can get formatted date, that whole model be casted toArray, or toJson,
dd($model->toArray()['deadline']);
// "17/12/2022"
So there isn't any easier way to get formatted date without casting whole model?
You can use a getter to overwrite your attribute :
public function getDeadlineAttribute()
{
return $this->deadline->format('d/m/Y');
}
If you want all your date formated that way for your model, you can use this :
protected function serializeDate(DateTimeInterface $date)
{
return $date->format('d/m/Y');
}
You can add to your model a new getter function like this:
public function getFormatedDateAttribute()
{
return $this->deadline->format('d/m/Y');
}
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()
I can find a number of discussions regarding this but no clear solution. Here are two links, although I will cover everything in my own question here.
Github Issues
Laravel.io discussion
Simple Explanation
This is a simple explanation of my problem for anyone already familiar with Laravel's polymorphic relationships.
When using $morphClass, the contents of $morphClass which is saved in the database as the morph "type" is used for the classname when trying to find the owner of a polymorphic relation. This results in an error since the whole point of $morphClass is that it is not a fully namespaced name of the class.
How do you define the classname that the polymorphic relationship should use?
More Detailed Explanation
This is a more detailed explanation explaining exactly what i'm trying to do and why i'm trying to do it with examples.
When using Polymorphic relationships in Laravel whatever is saved as the "morph_type" type in the database is assumed to be the class.
So in this example:
class Photo extends Eloquent {
public function imageable()
{
return $this->morphTo();
}
}
class Staff extends Eloquent {
public function photos()
{
return $this->morphOne('Photo', 'imageable');
}
}
class Order extends Eloquent {
public function photos()
{
return $this->morphOne('Photo', 'imageable');
}
}
The database would look like this:
staff
- id - integer
- name - string
orders
- id - integer
- price - integer
photos
- id - integer
- path - string
- imageable_id - integer
- imageable_type - string
Now the first row of photos might look like this:
id,path,imageable_id,imageable_type
1,image.png,1,Staff
Now I can either access the Photo from a Staff model or a Staff member from a Photo model.
//Find a staff member and dump their photos
$staff = Staff::find(1);
var_dump($staff->photos);
//Find a photo and dump the related staff member
$photo = Photo::find(1);
var_dump($photo->imageable);
So far so good. However when I namespace them I run into a problem.
namespace App/Store;
class Order {}
namespace App/Users;
class Staff {}
namespace App/Photos;
class Photo {}
Now what's saved in my database is this:
id,path,imageable_id,imageable_type
1,image.png,1,App/Users/Staff
But I don't want that. That's a terrible idea to have full namespaced class names saved in the database like that!
Fortunately Laravel has an option to set a $morphClass variable. Like so:
class Staff extends Eloquent {
protected $morphClass = 'staff';
public function photos()
{
return $this->morphOne('Photo', 'imageable');
}
}
Now the row in my database will look like this, which is awesome!
id,path,imageable_id,imageable_type
1,image.png,1,staff
And getting the photos of a staff member works absolutely fine.
//Find a staff member and dump their photos
$staff = Staff::find(1);
//This works!
var_dump($staff->photos);
However the polymorphic magic of finding the owner of a photo doesn't work:
//Find a photo and dump the related staff member
$photo = Photo::find(1);
//This doesn't work!
var_dump($photo->imageable);
//Error: Class 'staff' not found
Presumably there must be a way to inform the polymorphic relationship of what classname to use when using $morphClass but I cannot find any reference to how this should work in the docs, in the source code or via Google.
Any help?
There are 2 easy ways - one below, other one in #lukasgeiter's answer as proposed by Taylor Otwell, which I definitely suggest checking as well:
// app/config/app.php or anywhere you like
'aliases' => [
...
'MorphOrder' => 'Some\Namespace\Order',
'MorphStaff' => 'Maybe\Another\Namespace\Staff',
...
]
// Staff model
protected $morphClass = 'MorphStaff';
// Order model
protected $morphClass = 'MorphOrder';
done:
$photo = Photo::find(5);
$photo->imageable_type; // MorphOrder
$photo->imageable; // Some\Namespace\Order
$anotherPhoto = Photo::find(10);
$anotherPhoto->imageable_type; // MorphStaff
$anotherPhoto->imageable; // Maybe\Another\Namespace\Staff
I wouldn't use real class names (Order and Staff) to avoid possible duplicates. There's very little chance that something would be called MorphXxxx so it's pretty secure.
This is better than storing namespaces (I don't mind the looks in the db, however it would be inconvenient in case you change something - say instead of App\Models\User use Cartalyst\Sentinel\User etc) because all you need is to swap the implementation through aliases config.
However there is also downside - you won't know, what the model is, by just checking the db - in case it matters to you.
When using Laravel 5.2 (or newer) you can use the new feature morphMap to address this issue. Just add this to the boot function in app/Providers/AppServiceProvider:
Relation::morphMap([
'post' => \App\Models\Post::class,
'video' => \App\Models\Video::class,
]);
More about that: https://nicolaswidart.com/blog/laravel-52-morph-map
I like #JarekTkaczyks solution and I would suggest you use that one. But, for the sake of completeness, there's is another way Taylor briefly mentions on github
You can add a attribute accessor for the imageable_type attribute and then use a "classmap" array to look up the right class.
class Photo extends Eloquent {
protected $types = [
'order' => 'App\Store\Order',
'staff' => 'App\Users\Staff'
];
public function imageable()
{
return $this->morphTo();
}
public function getImageableTypeAttribute($type) {
// transform to lower case
$type = strtolower($type);
// to make sure this returns value from the array
return array_get($this->types, $type, $type);
// for Laravel5.7 or later
return \Arr::get($this->types, $type, $type);
// which is always safe, because new 'class'
// will work just the same as new 'Class'
}
}
Note that you still will need the morphClass attribute for querying from the other side of the relation though.
This is the way you can get morph class name(alias) from Eloquent model:
(new Post())->getMorphClass()
Let laravel put it into the db - namespace and all. If you need the short classname for something besides making your database prettier then define an accessor for something like :
<?php namespace App\Users;
class Staff extends Eloquent {
// you may or may not want this attribute added to all model instances
// protected $appends = ['morph_object'];
public function photos()
{
return $this->morphOne('App\Photos\Photo', 'imageable');
}
public function getMorphObjectAttribute()
{
return (new \ReflectionClass($this))->getShortName();
}
}
The reasoning I always come back to in scenarios like this is that Laravel is pretty well tested, and works as expected for the most part. Why fight the framework if you don't have to - particularly if you are simply annoyed by the namespace being in the db. I agree it isn't a great idea to do so, but I also feel that I can spend my time more usefully getting over it and working on domain code.
In order for eager loading of polymorphic relations eg Photo::with('imageable')->get(); it's necessary to return null if type is empty.
class Photo extends Eloquent {
protected $types = [
'order' => 'App\Store\Order',
'staff' => 'App\Users\Staff'
];
public function imageable()
{
return $this->morphTo();
}
public function getImageableTypeAttribute($type) {
// Illuminate/Database/Eloquent/Model::morphTo checks for null in order
// to handle eager-loading relationships
if(!$type) {
return null;
}
// transform to lower case
$type = strtolower($type);
// to make sure this returns value from the array
return array_get($this->types, $type, $type);
// which is always safe, because new 'class'
// will work just the same as new 'Class'
}
}
A simple solution will be to alias the value in imageable_type column in the db to the full class namespace as:
// app/config/app.php
'aliases' => [
...
'Order' => 'Some\Namespace\Order',
'Staff' => 'Maybe\Another\Namespace\Staff',
...
]
I am new to laravel 4 and I am trying to create a rest API following best practices defined by Apigee.
One of the best practice defined by apigee is to use camel case for json attribute keys, this way when using the API in Javascript the corresponding objects will follow attributes code convention (camel case).
I want to be able to define datatable columns following snake case but when retrieving eloquent objects though my api, the corresponding JSON has to follow camel case.
I read about a static variable $snakeAttributes that could be set in the model class and its documentation says "Indicates whether attributes are snake cased on arrays". I tried to override this variable and set it to false (MyResource class) but when executing the folowing code, the json still comes in snake case:
Code:
$resource = MyResource::find($id);
return Response::json($resource);
JSON:
{
first_name: 'Michael',
created_at: "2013-10-24 15:30:01",
updated_at: "2013-10-24 15:30:01"
}
Does someone have an idea on how to solve that?
Create BaseModel and a new method to help you with it:
class BaseModel extends \Eloquent {
public function toArrayCamel()
{
$array = $this->toArray();
foreach($array as $key => $value)
{
$return[camel_case($key)] = $value;
}
return $return;
}
}
Your model:
class MyResource extends BaseModel {
}
And then use it:
$resource = MyResource::find($id);
return Response::json( $resource->toArrayCamel() );
The way I see, you'll have to make a array, work manually on the keys (camel case) and then convert the array (not the result) on a JSON.
$resource = MyResource::find($id);
$array = array();
foreach($resource as $key => $value) {
$key = str_replace('_', '-', $key);
$array[$key] = $value;
}
return Response::json($array);
I guess that will do the job. :D
I want to return a JSON of an Eloquent model, but I'd like to change the array keys. By default they are set as the table field names, but I want to change them.
For example if I have a users table with two fields : id and user_name
When I return User::all(); I'll have a JSON with "[{"id" => 1, "user_name" => "bob}] etc.
I'd like to be able to change user_name to username. I haven't found the way to do it without an ugly foreach loop on the model.
I'm not sure why you would want to do this in the first place and would warn you first about the structure if your app/would it be better to make things uniform throughout.. but if you really want to do it.. you could do:
$user = User::find($id);
return Response::json(array('id' => $user->id, 'username' => $user->user_name));
That will return a JSON object with what you want.
You can also change the name of the key with:
$arr[$newkey] = $arr[$oldkey];
unset($arr[$oldkey]);
Just have a look at robclancy's presenter package, this ServiceProvider handles those things you want to achieve.
GITHUB LINK
Just set the $hidden static for you model to the keys you want to hide:
class User extends Eloquent
{
public static $hidden = 'id';
}
and name them the way you like with get and set functons.