compare jalali dates in cakephp - cakephp

I need to get users which their payment_time is between startDate and endDate in cakePHP.dates are in jalali format :
۱۳۹۷ - ۰۱ - ۱۴
and my controller is as follows:
public function search(){
if ($this->request->is('post')){
if(!empty($this->request->data['User']['start_date'])&&
!empty($this->request->data['User']['end_date'])){
$start_date = $this->request->data['User']['start_date'] ;
$end_date = $this->request->data['User']['end_date'];
$this->Paginator->settings['conditions']['AND'] = array(
'User.payment_time >= ' => $start_date,
'User.payment_time <= ' => $end_date);
$this->set('users', $this->Paginator->paginate());
}
}
But users is view page is null. Is this method can help for jalali dates?

Simply make a snippet to replace the Urdu/English numerals with English/Urdu numerals then parse the dates.

Related

Cakephp 3 - 'matching' - how to filter the data for the booking system?

I have 'accommod_units' and 'accommod_bookings' table and I want to check the availability of accommodation units for a certain period. For example, Date of arrival: 2019-08-20 and Departure date: 2019-08-27.
'accommodation_units' table is shown below:
'accommod_bookings' table is shown below:
This code does not work:
$this->loadModel('AccommodUnits');
$this->conditionBookings = [
'NOT' => [
[
'AccommodBookings.date_start >=' => '2019-08-20',
'AccommodBookings.date_end <=' => '2019-08-27'
],
]
];
$accommodUnits = $this->AccommodUnits
->find('all')
->distinct(['AccommodUnits.id'])
->contain([
'AccommodBookings' => function ($q) {
return $q->where($this->conditionBookings);
},
])
->where($conditionUnits)
->matching('AccommodBookings', function ($q) {
return $q->where($this->conditionBookings);
});
Their associations are:
$accommodUnits->hasMany('AccommodBookings');
How to solve this problem?
Simple you must overlaps booking periods
[
'AccommodBookings.date_start <=' => '2019-08-27', // Here put end date greater than start date <=
'AccommodBookings.date_end >=' => '2019-08-20' // Here put start date smaller than end date >=
],
Now:
$this->loadModel('AccommodUnits');
$accommodBookings = [
'AccommodBookings.date_start <=' => '2019-08-27', // not match start date lower than end date
'AccommodBookings.date_end >=' => '2019-08-20' // not mach end date greater than start date
];
$accommodUnits = $this->AccommodUnits
->find() // if empty default is 'all'
->where(['AccommodUnits.id' => 124]) // find units 124 where not matching:
->notMatching('AccommodBookings', function ($q) use ($accommodBookings) {
return $q->where($accommodBookings);
});
RESULT is null if unit 124 has overlaps booking date period.
Using notMatching()
The opposite of matching() is notMatching(). This function will change
the query so that it filters results that have no relation to the
specified association:
// In a controller or table method.
$query = $articlesTable
->find()
->notMatching('Tags', function ($q) {
return $q->where(['Tags.name' => 'boring']);
});
The above example will find all articles that were not tagged with the
word boring.
Poz

Contain complex query date_format and between

Code Update 2017/07/20
I followed the recommendations of #Arcesilas (here) with the use of date_format of MySQL.
I upgraded my data structure by merging start_month and start_day (ex 2017-01-16 = 0116)
[...]
->contain([
'Bookings',
'Amenities',
'Periodicities' => function ($q) use ($check_in, $check_out) {
$start = $q->func()->date_format([
'Periodicities.start' => $check_in->format('Ymd'),
"'%m%d'" => 'literal'
]);
$end = $q->func()->date_format([
'Periodicities.end' => $check_out->format('Ymd'),
"'%m%d'" => 'literal'
]);
return $q
->where(function ($exp) use ($start) {
$exp->between($start, 'Periodicities.start', 'Periodicities.end');
return $exp;
})
->orWhere(function ($exp) use ($end) {
$exp->between($end, 'Periodicities.start', 'Periodicities.end');
return $exp;
});
}
])
[...]
Cakephp SQL Log
SELECT
PeriodicitiesRooms.id AS `Periodicities_CJoin__id`,
PeriodicitiesRooms.periodicity_id AS `Periodicities_CJoin__periodicity_id`,
PeriodicitiesRooms.room_id AS `Periodicities_CJoin__room_id`,
PeriodicitiesRooms.price AS `Periodicities_CJoin__price`,
Periodicities.id AS `Periodicities__id`,
Periodicities.name AS `Periodicities__name`,
Periodicities.start AS `Periodicities__start`,
Periodicities.end AS `Periodicities__end`,
Periodicities.price AS `Periodicities__price`,
Periodicities.modified AS `Periodicities__modified`
FROM
periodicities Periodicities
INNER JOIN periodicities_rooms PeriodicitiesRooms ON Periodicities.id = (
PeriodicitiesRooms.periodicity_id
)
WHERE
(
date_format('20170726', '%m%d') BETWEEN 'Periodicities.start'
AND 'Periodicities.end'
OR (
PeriodicitiesRooms.room_id in ('1', '2', '3')
AND date_format('20170720', '%m%d') BETWEEN 'Periodicities.start'
AND 'Periodicities.end'
)
)
This does not give me any more result because ORM of CakePHP adds apostrophes (') to the end of BETWEEN' Periodicities.start 'AND' Periodicities.end'
If in my database I paste the CakePHP query without the apostrophes (') it works. Do you have any idea what changes to make to the end of my query so that it looks like this: BETWEEN 'Periodicities.start' AND 'Periodicities.end' to BETWEEN Periodicities.start AND Periodicities.end ?
'SELECT * FROM periodicities WHERE date_format(' . $check_in->format('Ymd') . ', '%m%d') BETWEEN start AND end'
EDIT
From your comment I see you don't want to store years because the year is not relevant.
In that case, you can still store all your dates as a specific year and then hard code that year into the query. I have modified the query to use year 2000.
ORIGINAL
The conversation is unclear to me but I will attempt to answer the question I believe you are asking.
It appears you want to know how to find Periodicities between the checkin time or Periodicities between the checkout time.
It also appears you want to know the best way to store the dates.
Just store the dates as dates. No need to make it complicated
Between is also overly complicated.
This will do what you need it to do without being confusing.
[...]
->contain([
'Bookings',
'Amenities',
'Periodicities' => function ($q) use ($check_in, $check_out) {
$q->where([
'Periodicities.start >' => $check_in->format('2000-m-d'),
'Periodicities.end <' => $check_in->format('2000-m-d')
]);
$q->orWhere([
'Periodicities.start >' => $check_out->format('2000-m-d'),
'Periodicities.end <' => $check_out->format('2000-m-d')
]);
return $q;
}
])
[...]
I solved my problem with this query :
->contain([
'Bookings',
'Amenities',
'Periodicities' => function ($q) use ($check_in, $check_out) {
$q->where(function ($exp) use ($check_in, $check_out) {
$exp->gte('Periodicities.start', $check_in->format('md'));
$exp->lte('Periodicities.end', $check_out->format('md'));
});
return $q;
}
])
I keep storing in database dates with the month and day md format
Ex: 0901 < 1030
01 September < 30 October

time array converson cakephp3

I have a simple question as I just want to convert the time (in array format) to a 24hr time string. The issue I get the time from user input and it places it in an array object which the formatting isnt working .
I couldnt find the answer from https://book.cakephp.org/3.0/en/core-libraries/time.html#conversion
time format inputted from a form
'start_time' => [
'hour' => '02',
'minute' => '00',
'meridian' => 'pm'
],
view//
echo $this->Form->input('start_time', ['label' => 'Class Start Time','type' => 'time',
'interval' => 5,'timeFormat'=>12,'value'=>$startTime,]);
//controller
if ($this->request->is('post')) {
debug($this->request->data['start_time']->i18nFormat('HH:mm:ss'));//cant use on an array
//this works but is there a better way
$startTime = $this->request->data['start_time']['hour'].":".$this->request->data['start_time']['minute']." ".
$this->request->data['start_time']['meridian'];
$this->request->data['start_time'] = date("H:i:s", strtotime( $startTime));
debug($this->request->data);
You should create a Time instance, because $this->request->data['start_time'] is not formated:
use Cake\I18n\Time;
...
$StartTimeHour = $this->request->data['start_time']['hour'];
$StartTimeMinute = $this->request->data['start_time']['minute'];
$StartTimeMeridian = $this->request->data['start_time']['meridian'];
$time = new Time("${StartTimeHour}:${StartTimeMinute} ${StartTimeMeridian}");
echo $time->i18nFormat('HH:mm:ss');
*Tested and working.

Cakephp 3.0 REST API add conditions in API response

Can we set conditions in xml response. Like there is status fields in database that is in numeric like 0,1,2,3 and we want to show it like below
0 for => Complete
2 for => Cancelled
2 for => Return
5 for => Refund.
How can we add a new fields in xml response if the fields does not exist in database ?
Lets suppose you are fetching the sales report from Sales table in Cakephp 3.0 Using rest API.
If you want to customize, rename, add few fields in response of Rest API You can do it like below
REST API URL will be something like below
https://example.com/api/index.json?fromdate_utc=2016-10-03&todate_utc=2016-10-03
And functino in controller be something like below:-
public function index($fromdate = null, $todate = null)
{
//set date range for
if(!empty($_GET['fromdate_utc']) && !empty($_GET['todate_utc'])){
// if from amd to date are same add +1 day in to date to get result
$to_date = date('Y-m-d', strtotime($_GET['todate_utc'] . ' +1 day'));
$dateRage = array('Sales.SalesDate >= ' => $_GET['fromdate_utc'], 'Sales.SalesDate <=' => $to_date);
}else{
$dateRage = array();
}
$conditions = array(
'and' => array($dateRage),
);
//$this->Auth->allow();
$sales = $this->Sales->find('all', array(
'conditions' => $conditions
))
->select(['SalesNo', 'SalesDate', 'TotalValue', 'TotalDiscount', 'NetTotal', 'PaymentMode', 'Status'])
->where(['StoreId' => '8','Status !=' => '2','Status !=' => '4'])->andWhere(['Status !=' => 1])->andWhere(['Status !=' => 4]);
//->limit(3);
$salesResponse = array();
//echo '<br/>Count no of output => '.$sales->count();
if($sales->count() >0 ){
foreach($sales as $key=>$salesData){
//re generate the array as per your requirements
$salesResponse[$key]['SalesNo'] = $salesData->SalesNo;
$salesResponse[$key]['SalesDate'] = $salesData->SalesDate;
$salesResponse[$key]['TotalValue'] = $salesData->TotalValue;
$salesResponse[$key]['TotalDiscount'] = $salesData->TotalDiscount;
$salesResponse[$key]['NetTotal'] = $salesData->NetTotal;
$salesResponse[$key]['SaleTax'] = 0; // add new fields that does not exist in database
$salesResponse[$key]['PaymentMode'] = $salesData->PaymentMode;
// change the status from numeric to character and pass it to response
if($salesData->Status == 5){
$salesResponse[$key]['Status'] = 'Refund';
}elseif($salesData->Status == 3){
$salesResponse[$key]['Status'] = 'Return';
}elseif($salesData->Status == 2){
$salesResponse[$key]['Status'] = 'Cancelled';
}elseif($salesData->Status == 0){
$salesResponse[$key]['Status'] = 'Complete';
}
}
}else{
$salesResponse = array('Error ! sorry not found any record.');
}
$this->set([
'sales' => $salesResponse,
'_serialize' => ['sales']
]);
}
If you're okay with having a slightly different name for the status in the XML, you could create a virtual field called, for example, status_text. Add a protected function _getStatusText in your Sale entity class which returns the desired text based on the status integer, and also add protected $_virtual = ['status_text']; to the Sale class, and you should start getting the status text in your XML.

Group by query of Eloquent in laravel

I need a query which group by hour then return data.i have a column in database with name time and the value in time column is like 13:12:43.so how can group by hour.And i need the result with order by hour.I'm trying the given query but this query return sum of all units.But i need sum of units on the base of hour like [{ hour:1,unit:0.2232},{ hour:2,unit:0.3232},..so on]
$response = PowerConsumption::groupBY('time')
->selectRaw('round(sum(unit),4) as yAxis')
->where(['device_id' => 2])
->where('date',Carbon::now()->ToDateString)
->orderBy('time')->get();
from you controller :
$response = PowerConsumption::selectRaw('HOUR(time) as hour')
->where(['device_id' => 2])
->where('date',Carbon::now()->ToDateString)
->orderBy('time')->get()->groupBy('hour');
$results = [];
foreach ($response as $hour => $value) {
$results[] = ['hour'=> $hour, 'unit' => round($value->sum('unit'), 4)]
}
you can just do the results foreach in your view if you are not using ajax

Resources