Adding data to an eloquent collection? - laravel

Im getting various data out of my database.
Product::with('users');
I also have toe execute a complex raw query to get back some information. This is returned as an array.
In my method I would like to get products with users and then add on the data from my raw query to this collection, but this data comes back as an array. Something like:
Product::with('users');
Product->extraData = $rawQuery;
How can I add the raw query output to my Product Collection?

By using Eloquent Facade like Product:: you will get an Eloquent Model object as a result or an Eloquent Collection object as a result, including results retrieved via the get method or accessed via a relationship.
Now, if i understand correctly, you need to add a single extraData property to Eloquent Collection model alongside with Collection items? Or you need to add extraData for each Product ?
If you need to add additional property to Eloquent Collection object, maybe it is a good idea to use a Custom Collection. Please read this section: http://laravel.com/docs/5.1/eloquent-collections#custom-collections .
<?php namespace App;
use App\CollectionWithExtraData;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
public function newCollection(array $models = [])
{
return new CollectionWithExtraData($models);
}
}
And maybe your CollectionWithExtraData can have let's say a
public function setExtraData() {
}
or
public $extraData = array();
If you need extraData for each Product Eloquent Model, just create a new attribute within your Eloquent Model, make it public and set your extra data when needed. Make use of setExtraData() method and $extraData property from above

Related

Laravel, related model reuturened names

I have a model that has a related model
class A extends Model{
public function niceName()
{
return this->hasOne('App\NiceName2' ...);
}
In the controller when I retrieve data with submodel the result is like
a[nice_name_2] (using the table name) and I would like it to be a[NiceName2].
Is there a way to have an alias for the returned result? In cakePHP i know there is propertyName to set this on relations. Laravel has a similar feature?
Thanks
Laravel uses the convention of camelCase for method names and snake_case for attributes. I'm not sure there's an easy way around this.
When Laravel serializes the data, it converts relationships to snake_case, by convention. So NiceName2 would become nice_name2 when you execute toArray() or when the model is serialized (either in a JSON response or otherwise).
How this works is:
When you access $model->nice_name2 it converts the property name back to niceName2 to check for a relationship method with that name. When serializing, it converts the relationship niceName2 to the attribute name nice_name2.

Laravel: Eloquent "join", how to get only a property of the referred table

I have a model A and a model B.
I made the relations between them, so i can do A->B->property.
But now I'm facing some problems.
I need to make a query and get only that B->property, not the B object.
So i use this:
A::with(['B'])->get()
But then a get a property called B in A with the complete B model.
Is there anyway to achieve something like this.
A::with(['B->property'])->get()
So then in the B property inside A I get the B->property instead the B object.
Is it possible?
PS: I can't use the query builder because i need that eloquent model.
I think this article will help you out:
http://laraveldaily.com/why-use-appends-with-accessors-in-eloquent/
You can put
$appends = ['property'] in your model to add a property field to your model.
Then, with an accessor method in the model you can describe how to populate that field (ie: with a field from another model via relationship).
It seems like that ought to give you what you want.
Try below code
In your A model:
protected $appends = ['property'];
public function B()
{
return $this->hasOne('\App\B');
}
public function getPropertyAttribute()
{
return $this->B()->property;
}
then A->property will give you B->property. Change model name and property name as per your requirement.
The answer by #shoieb0101 did not work for me because I had a belongsTo relationship rather than hasOne. If this is the case for you too, you just need to modify the accessor function as illustrated below.
protected $appends = ['property'];
public function B()
{
return $this->belongsTo('\App\B');
}
public function getPropertyAttribute()
{
return $this->B()->first()->property;
}
Note: I added ->first() in since belongsTo returns an array of results, but we can get the property from a single result only.
You should be able to constrain eagerloaded queries:
try
A::with(["B" => function($query){
$query->select('property');
}])->get();

Laravel Eloquent Model Dynamic Stored Properties from and to a single serialized field

Using Eloquent L5.1
I'd like to not have to define a set of properties for a model. Instead having everything stored within the database as a serialized column.
In other words any property that is set to this model should before save be removed from the object and added to an array to be serialized and then saved in db to a "data" column.
In turn after retrieving the object from db the model should be hydrated with the de-serialized parameters from the data column.
I could override a good number of Illuminate\Database\Eloquent\Model methods to accomplish this and I'm willing to do so, was curious if anyone had an example of this.
An example of this might be for configuration objects that have virtually unlimited unknown values that have multiple itterations for different objects or for different users.
Put these accessors and mutators in your Model:
class YourModel extends Model
{
public function getDataAttribute($data)
{
return collect(json_decode($data,true));
}
public function setDataAttribute($data)
{
$data = (is_array($data) || is_object($data)) ? json_encode($data) : $data;
return $this->attributes['data'] = $data;
}
}
Now when you can pass data as json string, array or object
YourModel::create(['data'=>'{"working":"ok"}']);
YourModel::create(['data'=>['working'=>'ok']]);
It will work in all three cases.

Eloquent model method or attribute for calculation

I'm looking for a way to define a custom Eloquent method which only returns a calculation based on several columns in the according database table. I also tried setting it in the models attributes, but neither seem to work. Maybe I'm missing something, here's what I got so far:
<?php
use Illuminate\Database\Eloquent\Model;
class Team extends Model
{
public function difference() {
return $this->goals_f - $this->goals_a;
}
}
The error message I'm recieving is:
Relationship method must return an object of type Illuminate\Database\Eloquent\Relations\Relation
Your error makes it sound to me like you are trying to call your method like a property" $team->difference. You would instead need to call it like: $team->difference(). If you want to get the difference as if it was a property, then you would need to define an accessor:
public function getDifferenceAttribute(){
return $this->goals_f - $this->goals_a;
}
Then you could call it like $team->difference.
You could also define a protected $appends property to your model so that the difference property is subsequently visible in it's JSON representation:
protected $appends = ['difference'];
More information: https://laravel.com/docs/5.2/eloquent-mutators#accessors-and-mutators

'Method' vs 'Dynamic Property' in Eloquent ORM with Laravel?

I want to count the number of posts belongs to a tag. Should I use method or dynamic property?
<?php
class Tag extends Eloquent {
public function posts()
{
return $this->belongsToMany('Post');
}
public function postsCount()
{
return count($this->posts);
}
public function getPostsCountAttribute()
{
return count($this->posts);
}
}
So in template should I use dynamic property:
{{ $tag->postCount }}
or method:
{{ $tag->postCount() }}
Excerpt from the documentation of Laravel 4 regarding Eloquent's Dynamic Properties (accessor) in relationships (bold are mine):
Eloquent allows you to access your relations via dynamic properties. Eloquent will automatically load the relationship for you, and is even smart enough to know whether to call the get (for one-to-many relationships) or first (for one-to-one relationships) method. It will then be accessible via a dynamic property by the same name as the relation.
That said, using the method defined for the database relationship or the dynamic property (accessor) will behave differently.
If you issue the post count using the method as follows:
$count = $tag->posts()->count();
That will generate the proper SQL with the COUNT aggregate function.
In the other hand, if you issue the post count using the dynamic property (accessor) as follows:
$count = count($tag->posts);
That will fetch all the posts, convert them to an array of objects, then counting the number of element of the array.
In your case, the choice should depend of the usage of the posts related to a tag. If you just want to count, then use the method and the aggregate function. But, if apart from counting you will be doing something else with those posts, then use the dynamic property (accessor).

Resources