Getting the number of rows considering a time frame - cakephp

I want to get the number of rows of a certain table considering a time frame.
I'm using CakePHP 3.7.
Here you can see my code (from the controller class) :
public function nbOfDefense($dateIn, $dateOut){
if($dateIn!=null && $dateFin!=null){
$conditions = array('thesis.date_end BETWEEN ? and ?' => array($dateIn, $dateOut));
$query = $this->Thesis->find('all',
array('conditions'=>$conditions));
die(strval($query->count()));
return $query;
}else{
$query = $this->Thesis->find('all');
die(strval($query->count()));
return $query->count();
}
}
I'm testing my function through my browser using this URL :
http://localhost:8888/thesis/nbOfDefense/2003-02-01/2019-04-13
What I want my function to do, is to, get in parameters two dates :
If those two dates are not null, you get the number of rows that between the two dates considering a date stored in the table you're consulting.
If the dates are null, then you get the total number of rows of the table.
And return an int, which is the number of rows that are between those two dates.
I feel like the problem here is how I handle my condition, because counting the total number of rows works perfectly (the else part of the code).
The error I have right now with this code is the following :
Cannot convert value of type array to string
it's pointing to this line :
die(strval($query->count()));
I guess the count function returns an array (weird because it doesn't when I count all rows without conditions). I also tried this :
die(strval(sizeof($query->count())));
But I get the same error as before (cannot convert array to string)
I must be missing something but I don't know what...

Try:
use Cake\ORM\Query;
use Cake\Database\Expression\QueryExpression;
class MyController extend AppController
{
public function nbOfDefense($dateIn = null, $dateOut = null)
{
$query = $this->Thesis->find();
if ($dateIn && $dateOut) {
$query->where(function (QueryExpression $exp, Query $q) use ($dateIn, $dateOut) {
return $exp->between('date_end', $dateIn, $dateOut);
});
}
$count = $query->count();
$this->set(compact('query', 'count'));
}
// ..
}
and read:
https://book.cakephp.org/3.0/en/orm/query-builder.html
https://book.cakephp.org/3.0/en/orm/retrieving-data-and-resultsets.html

Related

Laravel 7: Showing error while passing multiple variable in str_replace

I'm facing error while passing multiple variable in str_replace function.
Error: Argument 1 passed to Xenon\LaravelBDSms\SMS::shoot() must be of the type string, null given, called in
Message Body:
Hello #name#,
Total Amount Purchased : #total#
Previous Due: #previous_due#
Deposit: #deposit#
Total Due: #total_due#
Controller:
$id = 1;
$sms_settings = SmsSetting::findOrFail($id);
if($sms_settings->order_create == 1){
$name = $request->name;
$previous_due = $customer->due;
$deposit = $request->deposit;
$total = $request->total;
$total_due = $request->total_due;
$msgs = $sms_settings->order_create_sms;
$msg = str_replace(array('#name#', '#total#','#previous_due#','#deposit#','#total_due#'), array($name,$previous_due, $deposit, $total, $total_due), $msgs);
$send= SMS::shoot($request->mobile, $msg);
}
Shoot Function:
public function shoot(string $number, string $text)
{
$this->sender->setMobile($number);
$this->sender->setMessage($text);
return $this->sender->send();
}
Here I'm using a Laravel Package for sending SMS to mobile number. How can I pass multiple variable in str_replace?
$request->mobile is null, confirm if you are passing the same in the request. Thats why the error.
Also use $request->validated('mobile'), that is safer.
str_replace seems to be fine. Take a look at Example, but Look at examples again, it might break if characters are overlapping with other arguments
I think the variable $msgs = $sms_settings->order_create_sms; contain empty that's why str_replace couldn't replace the data that you given so
$msg = str_replace(array('#name#', '#total#','#previous_due#','#deposit#','#total_due#'), array($name,$previous_due, $deposit, $total, $total_due), $msgs); , will return null.
I recommend checking $msgs again.
$msgs = $sms_settings->order_create_sms;
Make sure $msgs is not null place is_null($msgs) condition before feeding to str_replace
check more about str_replace: https://www.php.net/manual/en/function.str-replace.php

How to design result according students

This is my first post. I am in a trouble in my laravel project
Here is my data table.
I have student Id like 1,2,3. every students have multiple results followed by courses.
I need to arrange them like that
I tried groupby and got this result
Is there any possible way to arrange them according to students.
Thank You
code: controller:
public function notification()
{
$auth_id = Auth::user()->id;
$teacher = Teacher::where('user_id', $auth_id)->first();
$teacher_id = ($teacher->id);
$batch = Batch::where('teacher_id', $teacher_id)->first();
$courses = AssignCourses::with('course')
->where('semester_id', $batch->semester_id)
->get();
$current_semester_results = Result::with(['student', 'course'])
->where('semester_id', $batch->semester_id)
->get()
->groupBy('student.id');
$batch_students = Student::with('result')
->where('semester_id', $batch->semester_id)
->get();
return view('users.teacher.my_batch.notification', compact(['current_semester_results', 'courses', 'batch_students']));
}
Just use the $batch_students and apply any aggregations on your PHP code, it is easier to do it.
$batch_students = Student::with('result')
->where('semester_id', $batch->semester_id)
->get();
$batch_students_grouped = $batch_students->groupBy('result.student_id');
Note: I could not test since I don't have the tables, so you might need to change the student_id nest/access index in the last line of code.
you can print out your $batch_students_grouped->all() and see how you should iterate your data and show it in frontend.

unexpected result in a query in laravel

I’m a beginner in Laravel but have a problem at first. I wrote this query and I’m waiting for Sonya Bins as result but unexpectedly I see ["Sonya Bins"]. what’s the problem?
Route::get('products', function () {
$articles=DB::table('users')->where('id','2')->get()->pluck('name');
return view('products',compact('articles'));
});
pluck will return array if you want to get only single value then use value
// will return array
$articles=DB::table('users')->where('id','2')->get()->pluck('name');
//will return string
$articles=DB::table('users')->where('id','2')->value('name');
// output Sonya Bins
here is an example from the documentation:
if you don't even need an entire row, you may extract a single value from a record using the value method. This method will return the value of the column directly:
$email = DB::table('users')->where('name', 'John')->value('email');
Read more about it here
Hope it helps.
Thanks
pluck() used to return a String before Laravel 5.1, but now it returns an array.
The alternative for that behavior now is value()
Try this:
Route::get('products', function () {
$articles=DB::table('users')->where('id','2')->get()->value('name');
return view('products',compact('articles'));
});
I think it's easier to use the Model + find function + value function.
Route::get('products', function () {
$articles = User::find(2)->value('name');
return view('products',compact('articles'));
});
pluck will return the collection.
I think id is your primary key.
You can just get the first record, and call its attribute's name:
DB::table('users')->where('id','2')->first()->name;
or
DB::table('users')->find(2)->name;
First thing is that you used invalid name for what you pass to view - you don't pass articles but user name.
Second thing is that you use get method to get results instead of first (or find) - you probably expect there is only single user with id = 2.
So to sum up you should use:
$userName = DB::table('users')->find(2)->name;
return view('products',compact('userName'));
Of course above code is for case when you are 100% sure there is user with id = 2 in database. If it might happen there won't be such user, you should use construction like this:
$userName = optional(DB::table('users')->find(2))->name;
($userName will be null if there is no such record)
or
$userName = optional(DB::table('users')->find(2))->name ?? 'No user';
in case you want to use custom string.

Apply Filter to Column with Numeric Values

I have a solution for filtering on this question.
This works perfectly with a column that has string values. When I try to filter a column with numeric values it will not work. I'm assuming it is because .setHiddenValues() will not accept numeric values. I could be wrong.
Let me explain my scenario:
The user inputs a value on an HTML interface, let's say 6634.
The HTML calls my function on .gs and passes the numeric value the user inputted.
google.script.run //Executes an Apps Script JS Function
.withSuccessHandler(updateStatus) //function to be called upon successfull completion of Apps Script function
.withFailureHandler(failStatus)
.withUserObject(button) //To pass the event element object
.projectSearch2(projectID); //Apps Script JS Function
return;
The function (on the linked question above) will take that value and bump it up against the values in a column deleting the value if it is found. What I am left with is an array of values that I do not want filtered.
function projectSearch2(projectID){
var ss = SpreadsheetApp.getActive();
var monthlyDetailSht = ss.getSheetByName('Data Sheet');
var monLastCN = monthlyDetailSht.getLastColumn();
var monLastRN = monthlyDetailSht.getLastRow();
var data = monthlyDetailSht.getRange(1,1,1,monLastCN).getValues();//Get 2D array of all values in row one
var data = data[0];//Get the first and only inner array
var projectIDCN = data.indexOf('Project Id') + 1;
//Pull data from columns before filtering
var projectIDData = monthlyDetailSht.getRange(2,projectIDCN,monLastRN,1).getValues();
//Reset filters if filters exist
if(monthlyDetailSht.getFilter() != null){monthlyDetailSht.getFilter().remove();}
//Start Filtering
var projectIDExclCriteria = getHiddenValueArray(projectTypeData,projectID); //get values except for
var rang = monthlyDetailSht.getDataRange();
var projectIDFilter = SpreadsheetApp.newFilterCriteria().setHiddenValues(projectIDExclCriteria).build();//Create criteria with values you do not want included.
var filter = rang.getFilter() || rang.createFilter();// getFilter already available or create a new one
if(projectID != '' && projectID != null){
filter.setColumnFilterCriteria(projectIDCN, projectIDFilter);
}
};
function getHiddenValueArray(colValueArr,visibleValueArr){
var flatUniqArr = colValueArr.map(function(e){return e[0];})
.filter(function(e,i,a){return (a.indexOf(e.toString())==i && visibleValueArr.indexOf(e.toString()) ==-1); })
return flatUniqArr;
}
That array is used in .setHiddenValues() to filter on the column.
Nothing is filtered however. This works for all columns that contain string values, just not columns with numeric values. At this point I'm lost.
Attempted Solutions:
Convert user variable to string using input = input.toString(). Did not work.
manually inserted .setHiddenValues for projectIDExclCriteria. Like this: var projectIDFilter = SpreadsheetApp.newFilterCriteria().setHiddenValues([1041,1070,1071,1072]).build(); That succeeded so I know the issue is before that.
Step before was calling getHiddenValueArray. I manually inserted like so: var projectIDExclCriteria = getHiddenValueArray(projectIDData,[6634]); It is not working. Is the issue with that getHiddenValueArray function not handling the numbers properly?
Here is a solution. Changing the following:
.filter(function(e,i,a){return (a.indexOf(e.toString())==i && visibleValueArr.indexOf(e.toString()) ==-1); })
To:
.filter(function(e,i,a){return (a.indexOf(e) == i && visibleValueArr.indexOf(e) == -1); })
That works! Thank you Tanaike. The next question is will this impact columns that are not numeric. I have tested that and it works as well.
How about this modification?
From :
.filter(function(e,i,a){return (a.indexOf(e.toString())==i && visibleValueArr.indexOf(e.toString()) ==-1); })
To :
.filter(function(e,i,a){return (a.indexOf(e) == i && visibleValueArr.indexOf(e) == -1); })
Note :
In this modification, the number and string can compared using each value.
If you want to use return (a.indexOf(e.toString())==i && visibleValueArr.indexOf(e.toString()) ==-1), you can achieve it by modifying from colValueArr.map(function(e){return e[0];}) to colValueArr.map(function(e){return e[0].toString();}).
In this modification, colValueArr.map(function(e){return e[0].toString();}) converts the number to string, so the number is used as a string.
Reference :
Array.prototype.indexOf()

cakePHP: Look for a row inside database by using other fields other than primary key?

I'm going to check if a row exists in my DB which one of its field matches a custom value.
e.g. consider table licences which contains fields: (id,serial,validity).
I'm going to check two conditions in my controller:
licence with serial 'xyz' is presents in db
licence with serial 'xyz' have validity field value 'valid'
How should i complete $option for this code:
public function validity($serial = null) {
$this->autoRender = false; // We don't render a view in this example
$options = ?????;
$license = $this->License->find('first', $options);
if ($license){
// it is valid and present
$data = array('validity' => 'valid');
);
}else{
//not present actions
$data = array('validity' => 'invalid');
}
$this->response->body(json_encode($data));
}
The options argument has a lot of parameters you can use like conditions, order and fields. In your case you need conditions
$options=array('conditions'=>array('License.serial'=>'xyz', 'License.validity'='valid'));
(by default it is AND between conditions)

Resources