Can not access object in laravel and has "0" indexes when appliying toArray() - arrays

I have these tables
clientes
id
nombre_rz
ced_rif
telefono
id_usuario
solicitantes
id
nombre
email
telefono
id_cliente
cliente->hasMany('solicitante')<br>
solicitante->belongsTo('cliente')<br>
^ This is well written in the models, just trying not to make a wall of text.
After Authenticating, when i do
$cliente = Cliente::where('usuario_id','=',Auth::id())->with('solicitante')->get();
dd($cliente);
or
$cliente = Cliente::where('usuario_id','=',Auth::id())->with(array('solicitante' => function($query)
{
$query->where('cliente_id', '=', '35');
}))->get();
dd($cliente);
i get this obect
Object from query
And using toArray() i get this
Array from object
And if access index 0 of that array like
$array = $cliente->toArray(); dd($array['0']);
i get
[Index 0 of array][3]
As far as i can see the queries are correct, and the data i need is there, but i don't know why i can't access the object like
$cliente->id; $cliente->telefono, $cliente->solicitante->nombre, $cliente->solicitante->email
It always throws
Undefined property: Illuminate\Database\Eloquent\Collection::$telefono
Can't Understand this behavior.

You are returning an array of objects, because you asked Laravel for a group. You can either do
foreach ($cliente as $client)
{
echo $client->telefono;
foreach ($client->solicitante as $solicitante)
{
$solicitante->nombre;
}
}
OR you can specify that you only want one result
$cliente = Cliente::where('usuario_id','=',Auth::id())->with('solicitante')->first();
echo $cliente->telefono;
foreach ($client->solicitante as $solicitante)
{
$solicitante->nombre;
}

Related

How to convert two level array to one level array in laravel

I have a array of array data which is came from database. And my "array to xml converter" can convert only one level array.
Basicly I want to convert my database table to xml file.
public function downloadXml()
{
$fields = ['created_at', 'updated_at'];
$products = Product::where('user_id', auth()->id())
->exclude($fields)->get()->toArray();// this is returnin array of array like [0 => [], 1 => []]
$products = array_collapse($products);
$result = ArrayToXml::convert($product, 'product');
}
The problem is array_collapse method trim the one level array but give me only last array not all arrays. How can I get all arrays? Any help appreciated..
Edit: when dd(Product::where('user_id', auth()->id())
->exclude($fields)->get()->toArray(););
Output1 = array:2 [▼ 0 => array:18 [▶] 1 => array:18 [▶] ]
When dd(array_collapse(Product::where('user_id', auth()->id())
->exclude($fields)->get()->toArray());)
Output2 = array:18 [▶]
I need something like output2 but the problem is output2 assuming there is only one product but actualy there is two product.
When performing a database query using Eloquent (Laravel ORM) the results are returned inside a Collection (one per row). This is the 'first level' array you are mentioning.
Unfortunately, a 'second level' array is needed to define the attributes (among others) for every row.
So you either have to:
extend your ArrayToXml converter to work with Laravel collections (i.e. print xml tag, loop through the elements and print the closing xml tag)
Split your xml converter into two pieces: a wrapper for the xml tag opening and closing and your current ArrayToXml::convert inside a map function.
Let me illustrate the latter:
public function downloadXml()
{
return Product::where('user_id', auth()->id())
->get()
->map(function (Product $product){
return ArrayToXml::convert($product->only('id', 'user_id'), 'product');
})
}

Eloquent - groupBy and sum() of hasManyThrough relationship

I have 3 models Job, Diary, Resource.
Jobs has relation with Diary and Diary has relation with Resource.
I wanted to get all Resource associated with a Job and did this using
public function labourers()
{
return $this->hasManyThrough(Resource::class, Diary::class, 'job_id');
}
On my Job class.
Now I want to group the results by User who's user_id is a column in Resource and then show the total hours.
This is the closest I can get.
$job = Job::where('job_number', 3007)->first();
$labour = $job->labourers()->get();
$results = $labour->groupBy('user_id');
echo $results;
foreach($results as $result)
{
$hours = $result->sum('hours');
echo $result[0]->user_id." - ";
echo $hours.". ";
}
This gets me the user_id and the sum of the hours but I am unable to access the user name through the relationship set up on the resource model
public function user()
{
return $this->belongsTo(User::class);
}
with
$result->user->name;
This produces
Property [user] does not exist on this collection instance.
How can I return a collection which allows me to access the users name and the sum of the hours.
The reason you're not able to access the user like that is because (in this case) groupBy is a method on the collection that returns another collection.
Firstly, eager load the user relationship on so that your code is a bit more efficient:
$labour = $job->labourers()->with('user')->get();
Secondly, since you have a collection you can use first() instead of [0]:
$result->first()->user_id
Lastly, you would have to access the user in the same way you're accessing the user_id:
$result->first()->user
So, you would end up with something like:
$job = Job::where('job_number', 3007)->first();
$labourers = $job->labourers()->with('user')->get();
$results = $labourers->groupBy('user_id');
foreach($results as $result)
{
echo $result->first()->user->name . ' - ' . $result->sum('hours') . '.';
}
You can try this
$job = Job::where('job_number', 3007)->with(['labourers' => function($query){
$query->select('id','user_id', DB::raw('sum(hours) as hours'))->groupBy('user_id');
}, labourers.user])->first();
$results = $job->labourers;
foreach($results as $result){
print_r($result->user);
print_r($result->hours);
}

Indirect modification of overloaded element of Illuminate\Support\Collection has no effect

im quite new in laravel framework, and im from codeigniter.
I would like to add new key and value from database
static function m_get_promotion_banner(){
$query = DB::table("promotion_banner")
->select('promotion_banner_id','promotion_link','about_promotion')
->where('promotion_active','1')
->get();
if($query != null){
foreach ($query as $key => $row){
$query[$key]['promotion_image'] = URL::to('home/image/banner/'.$row['promotion_banner_id']);
}
}
return $query;
}
that code was just changed from codeigniter to laravel, since in codeigniter there are no problem in passing a new key and value in foreach statement
but when i tried it in laravel i got this following error :
Indirect modification of overloaded element of Illuminate\Support\Collection has no effect
at HandleExceptions->handleError(8, 'Indirect modification of overloaded element of Illuminate\Support\Collection has no effect', 'C:\xampp\htdocs\laravel-site\application\app\models\main\Main_home_m.php', 653, array('query' => object(Collection), 'row' => array('promotion_banner_id' => 1, 'promotion_link' => 'http://localhost/deal/home/voucher', 'about_promotion' => ''), 'key' => 0))
please guide me how to fix this
thank you (:
The result of a Laravel query will always be a Collection. To add a property to all the objects in this collection, you can use the map function.
$query = $query->map(function ($object) {
// Add the new property
$object->promotion_image = URL::to('home/image/banner/' . $object->promotion_banner_id);
// Return the new object
return $object;
});
Also, you can get and set the properties using actual object properties and not array keys. This makes the code much more readable in my opinion.
For others who needs a solution you can use jsonserialize method to modify the collection.
Such as:
$data = $data->jsonserialize();
//do your changes here now.
The problem is the get is returning a collection of stdObject
Instead of adding the new field to the result of your query, modify the model of what you are returning.
So, assuming you have a PromotionBanner.php model file in your app directory, edit it and then add these 2 blocks of code:
protected $appends = array('promotionImage');
here you just added the custom field. Now you tell the model how to fill it:
public function getPromotionImageAttribute() {
return (url('home/image/banner/'.$this->promotion_banner_id));
}
Now, you get your banners through your model:
static function m_get_promotion_banner(){
return \App\PromotionBanner::where('promotion_active','1')->get();
}
Now you can access your promotionImage propierty in your result
P.D:
In the case you are NOT using a model... Well, just create the file app\PromotionImage.php:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class PromotionImage extends Model
{
protected $appends = array('imageAttribute');
protected $table = 'promotion_banner';
public function getPromotionImageAttribute() {
return (url('home/image/banner/'.$this->promotion_banner_id));
}
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'promotion_banner_id','promotion_link','about_promotion','promotion_active'
];
just improving, in case you need to pass data inside the query
$url = 'home/image/banner/';
$query = $query->map(function ($object) use ($url) {
// Add the new property
$object->promotion_image = URL::to( $url . $object->promotion_banner_id);
// Return the new object
return $object;
});
I've been struggling with this all evening, and I'm still not sure what my problem is.
I've used ->get() to actually execute the query, and I've tried by ->toArray() and ->jsonserialize() on the data and it didn't fix the problem.
In the end, the work-around I found was this:
$task = Tasks::where("user_id", $userId)->first()->toArray();
$task = json_decode(json_encode($task), true);
$task["foo"] = "bar";
Using json_encode and then json_decode on it again freed it up from whatever was keeping me from editing it.
That's a hacky work-around at best, but if anyone else just needs to push past this problem and get on with their work, this might solve the problem for you.

Accessing individual properties from Realm database RLMResults - SWIFT

I want to know the best way to access individual properties from RLMResults. I have a Realm "Jobs" database containing several properties i.e jobTitle, jobDescription, jobStartedDate. I've got an array that I query and the query returns the jobs from the database. I want to know how I could access the individual properties, say "jobTitle" only and print to the console.
for job in reportedJobsPDF {
var titles = Jobs.objectsWhere("jobTitle == '\(job)' ")
println("\(titles)")
}
This returns output to console as below:
RLMResults <0x7ff5dbd38790> (
[0] Jobs {
jobDescription = 34 desc;
jobTitle = New jobs 34;
jobStarted = 2014-11-28 21:14:24 +0000;
}
I want to be able to access those properties individually or is it possible to add the results to a swift dictionary?
use RLMResults.count to get the count of your results, and RLMResults.objectAtIndex to get individual objects:
for job in reportedJobsPDF {
var titles = Jobs.objectsWhere("jobTitle == '\(job)' ")
var firstJob = titles.objectAtIndex(0) as Jobs
println("\(firstJob.jobTitle)")
}

drupal_write_record doesn't take object

In drupal 6 i used to do something like this:
<?php
/*
* CLASS Example
*/
class example {
var $id = NULL;
var $title;
var $body;
.....
// Save
function save() {
$primary_key = ($this->id == NULL ? NULL : 'id');
if (drupal_write_record('mytabble', $this, $primary_key)) {
return TRUE;
} else {
return FALSE;
}
}
}
?>
This worked quite well. But in Drupal 7, the drupal_write_record only takes an array and no longer the object $this. The new db_merge also only takes an array.
Since i want to save the properties of my object to the database, the above code was very handy and generic for all kinds of classes.
Is there an alternative way to write an object to database, or a method to place objectproperties into a an array?
Any help will be appreciated!
Robert
drupal_write_record does take an object or an array. Guess your problem is caused somewhere else.
drupal_write_record($table, &$record, $primary_keys = array())
$record: An object or array representing the record to write, passed in by reference. If inserting a new record, values not provided in $record will be populated in $record and in the database with the default values from the schema, as well as a single serial (auto-increment) field (if present). If updating an existing record, only provided values are updated in the database, and $record is not modified.
More info on drupal_write_record for D7.

Resources