Eloquent - groupBy and sum() of hasManyThrough relationship - database

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);
}

Related

How to get customer_id from different table and avoid duplications with correct method in laravel?

Hi I am trying to get customer _id from different tables Purchase order ,Sale Order and Consignments
Then I am looping through these Ids . Method I am using for this purpose is working perfectly but . I am afraid if there is a lot of data this method may get failed. Here is my method .
$consignmentCustomerIds = Consignment::select('customer_id')->where('is_repeat', 0)->whereDate('created_at','>',date('2021-03-06'))->whereRaw('(is_group = "parent" or is_group is null)')->where('finalize', 0)->where('invoice_id', null)->distinct()->pluck('customer_id')->toArray();
$poCustomerIds = PurchaseOrder::select('customer_id')->whereDate('created_at','>',date('2021-03-06'))->where('invoice_id', null)->distinct()->pluck('customer_id')->toArray();
$soCustomerIds = SaleOrder::select('customer_id')->whereDate('created_at','>',date('2021-03-06'))->where('invoice_id', null)->distinct()->pluck('customer_id')->toArray();
$spCustomerIds = StoragePeriod::select('customer_id')->whereDate('created_at','>',date('2021-03-06'))->where('invoice_id', null)->distinct()->pluck('customer_id')->toArray();
$ids = array_merge($consignmentCustomerIds, $poCustomerIds, $soCustomerIds, $spCustomerIds);
$customers = Customer::whereIn('id', $ids)->get();
foreach ($customers as $customer) {
CreateInvoiceOneByOne::dispatch($customer)->onQueue('invoice');
}
Is there any better way of doing so?
The main thing is to change ->get() to ->cursor() in the iteration:
// $customers = Customer::whereIn('id', $ids)->get();
$customers = Customer::whereIn('id', $ids)->cursor();
The cursor method may be used to significantly reduce your application's memory consumption when iterating through tens of thousands of Eloquent model records.
More info: https://laravel.com/docs/8.x/eloquent#cursors
IF YOUR RELATIONS ARE SET PROPERLY
I suggest to reduce database query. You can do this by chaning whereHas and orWhereHas within the customer request.
Querying Relationship Existence
$date = date('2021-03-06');
$customers = Customer::whereHas('consignment', function($query) use($date) {
$query->where('is_repeat', 0)->whereDate('created_at','>',$date)->whereRaw('(is_group = "parent" or is_group is null)')->where('finalize', 0)->where('invoice_id', null);
})->orWhereHas('purchase_order', function($query) use($date) {
$query->whereDate('created_at','>',$date)->where('invoice_id', null);
})->orWhereHas('sale_order', function($query) use($date) {
$query->whereDate('created_at','>',$date)->where('invoice_id', null);
})->orWhereHas('storage_period', function($query) use($date) {
$query->whereDate('created_at','>',$date)->where('invoice_id', null);
})->get();
foreach ($customers as $customer) {
CreateInvoiceOneByOne::dispatch($customer)->onQueue('invoice');
}
I set the $date variable before the query, so this way you can manipulate it at one place.
P.S. I am currently assuming the name of the relations.

How to save data in the database using codeigniter?

public function registration_insert($data) {
//$this->db->trans_start();
//echo "<pre>";print_r($_POST);die;
// Query to check whether username already exist or not
$condition = "user_name =" . "'" . $data['user_name'] . "'";
$this->db->select('*');
$this->db->from('user_login');
$this->db->where($condition);
$this->db->limit(1);
$query = $this->db->get();
// Query to insert data in database
$this->db->insert('user_login', $data);
if ($this->db->affected_rows() > 0) {
return true;
}
This is my program. It is not executing this code. I want to store the data in the database. Explicitly, with print_r(), it is posting the data but it is not storing it in the database and it is showing error.
First of all, i want to check your $data variable , if $data is not an object that have the sames attribute name like your database table column that will give you a problem.
I mean, for exemple if your user_login table have tow column (id , user_name), you should have in the $data object the same name of attributes
and to verify if your query work correctly just your code will be like this :
$q = $this->db->insert('user_login', $data);
if ($q) {
return $this->db->insert_id();
} else {
return false;
}

db query in codeigniter active record returing object

I'm trying to pull a column out of the database, simple enough right? I'm using codeigniter's active record.
My Model Function
public function getcolumn($field, $table, $kfield, $key)
{
$this->db->select($field);
$this->db->from($table);
$this->db->where($kfield, $key);
$query = $this->db->get();
$results = $query->result();
return $results;
}
My Controller has:
public function users()
{
$body['handle'] = $this->admin->getcolumn('handle', 'users', 'userid', $userid)
$this->load->view('template/header');
$this->load->view('admin/users', $body);
$this->load->view('template/footer');
}
now when I print_r that variable in my view I get "Array ( [0] => stdClass Object ( [handle] => Zanigade ) ) "
Since I'm trying to use this function as a global "grab and go" function without writing a ton of functions, why won't it just return the name? What am I doing wrong? I've been playing with the output for 3 hours and I know this is a stupid easy fix and I'm just missing the mark.
Any help will be appreciated.
Put it all together using the "chaining" capability like so
$results = this->db->get()->row()->$field;
We get() one row() which (should) contain a field named $field.
It seems you are returning the result instead of single row, try this
public function getcolumn($field, $table, $kfield, $key)
{
$this->db->select($field);
$this->db->from($table);
$this->db->where($kfield, $key);
$query = $this->db->get();
return $query->row()->$field;
}
For More Information, Check the codeigniter user guide
https://www.codeigniter.com/userguide3/database/examples.html

Define and access virtual properties in cakePHP - where and how?

In an application a lecture hasMany slides and a slide belongsTo a lecture. When the index function of lecture is called we would like to add a column which displays the amount off slides belonging to a certain lecture.
I tried to define this as as a $virtualFields in the lecture model like this:
public $virtualFields = array(
'slides_amount' => 'SELECT COUNT(*) AS `count` FROM `eflux`.`slides` AS `Slide` LEFT JOIN `eflux`.`lectures`
AS `Lecture` ON (`Slide`.`lecture_id` = `Lecture`.`id`)
WHERE lecture_id = \''.$id.'\'')';
The problem is that I am not able to access the current $id of the object and therefore MySQL returns an error.
My next try was to use the controller for this:
$lectures = $this->Lecture->findByCourseId($course_id);
for ($i = 0; $i < count($lectures); $i++) {
$slide_amount = $this->Lecture->Slide->find('count', array('conditions' => 'lecture_id = \' '.$id.'\''));
$slide_amounts[$i] = $slide_amount;
}
I was also not able to access the id of the current $lecture-object to determin the amount of slides belonging to that lecture.
Finally I did it in the view:
for ($i = 0; $i < count($slides_helper); $i++) {
if ($slides_helper[$i]['slides']['lecture_id'] == $lecture['Lecture']['id']) {
echo $slides_helper[$i][0]['count'];
}
}?>
Only here I could acces the id of the current object or the $lectures array. But I feel that the view is not the place to handle this.
What is best practice to achieve this goal?
in your controller, you can try:
$lectures = $this->Lecture->find('all', array('conditions'=>array('Lecture.course_id'=>$course_id)));
foreach ($lectures as &$lecture){
$lecture['Lecture']['slide_count'] = count($lecture['Slide']);
}
$this->set('lectures', $lectures);
and then access the count in your view with
foreach ($lectures as $lecture){
echo $lecture['Lecture']['slide_count'];
}
The code might not be exact... you can help us give more accurate code by pasting the results of the following code:
Place this in your controller:
$lectures = $this->Lecture->find('all', array('conditions'=>array('Lecture.course_id'=>$course_id)));
pr($lectures);
EDIT FOR PAGINATION:
Something like this might work for your pagination
$this->paginate['conditions'] = array('Lecture.course_id'=>$course_id);
$this->paginate['limit'] = '10';
$lectures = $this->paginate('Lecture');
//PERFORM THE LOOP TO ADD SLIDE COUNT
$this->set('lectures', $lectures);

Cakephp using two models

In my CakePHP forms_controller I have:
var $uses=array('Form','Field');
// ...
$this->set('retrived',$this->Field->find("all",array('conditions'=>array('Field.formname'=>$formname,))));
and in the view:
<?php foreach ($retrived as $r): ?>
<?php echo $r['Field']['fieldname']; ?><br>
<?php endforeach; ?>
I'm not getting the answer for it
Actually my table fields wil be like:
fieldname
formname
type
value
More details from my forms_controller:
function views()
{
if (!empty($this->params['form']))
{
$this->set('fieldctr',$this->params['form']['formfieldctr']);
$fieldctr=$this->params['form']['formfieldctr'];
if(!empty($this->params['form']['formnameelements']))
{
$this->set('formname',$this->params['form']['formnameelements']);//formname
$this->Form->saveField('name',$this->params['form']['formnameelements']);
}
else
{
$this->set('formname','MyForm');//formname
$this->Form->saveField('name','MyForm');
}
$this->Form->saveField('body',$this->params['form']['formelements']);//inserts into database
$ret = $this->Form->query("Select id from forms order by id DESC LIMIT 1");
$newid=$ret[0]['forms']['id'];echo $newid;
$upd=$this->Form->query("update forms set ctr=$fieldctr where id= $newid");
$formname=$this->params['form']['formnameelements'];
$n="$formname";
$array = $this->params['form']['formfieldnameelements'];
$comma_separated = explode(",", $array);
for($i=0;$i<$fieldctr;$i++)
{
echo $comma_separated[$i];
echo " ";
$n="$comma_separated[$i]";
//insert the fields of each form to the table fields
$this->data['Field']['fieldname'] = $comma_separated[$i];
$this->data['Field']['formname'] = $formname;
$this->Field->saveAll($this->data);
}
The above method is where I'm inserting the formname in my forms table.
And inserting that formname with their fieldsname in the fields table:
function formupdate()
{
$this->set('fieldctr',$this->params['form']['formfieldctr']);
$fieldctr=$this->params['form']['formfieldctr'];
$this->set('formname',$this->params['form']['formnameelements']);//formname
$formname=$this->params['form']['formnameelements'];
$ret = $this->Field->query("SELECT fieldname FROM fields WHERE fields.formname = "."'$formname'"."order by id ASC");
for($q=0;$q<$fieldctr;$q++)
{
$fieldname[$q]=$ret[$q]['fields']['fieldname'];
}
$this->set('retrived',$this->Field->find("all",array('conditions'=>array('Field.formname'=>$formname))));
$array = $this->params['form']['formfieldvalueelements'];
$comma_separated = explode(",", $array);
for($i=0;$i<$fieldctr;$i++)
{
echo $comma_separated[$i];
echo " ";
$n="$comma_separated[$i]";
echo $fieldname[$i];
$this->Field->updateAll(array('Field.value' => "'$comma_separated[$i]'"),array('Field.fieldname' => $fieldname[$i],'Field.formname'=>$formname));
}
$this->set('retrived',$this->Field->find("all",array('conditions'=>array('Field.formname'=>$formname,))));
} // end of function formupdate
In the above formupdate method I'm inserting the values of the corresponding values of that fields in the fields table... All the values are inserted correctly - but in my formupdate.ctp view:
Nothing is displayed in my view... eventhough the content is there in the table..
Please resolve my problem
By the names of your models, I think it's safe to conclude that you're trying to ouput some HTML. Since the question isn't really complete (where is the code?), we can't tell what's wrong with it.
A wild guess would be that something is being stripped there or ignored by your browser.
Aruna,
Please post the code you're using! It's possible that the error is something small, but without knowing what you're doing, it's impossible to help more than dr. Lecter did.
When you say that the fields table is updated correctly, do you mean that you can safely invoke the Model::save() method? Are you then calling Model::read() or Model::find() in the controller, then using the returned values from that to set a variable that can be accessed in the view?

Resources