Good day gorgeous friends on the internet!
I have a query to get data from database per week. Now I can get a result as you can see in the picture below.
Query:
return static::selectRaw('SUM(total) as total')
->selectRaw('COUNT(*) as total_orders')
->whereBetween('created_at', [now()->startOfWeek(), now()->endOfWeek()])
->whereNotIn('status', ['canceled', 'refunded'])
->selectRaw('EXTRACT(DAY FROM created_at) as day')
->groupBy(DB::raw('EXTRACT(DAY FROM created_at)'))
->orderby('day')
->get();
and in my controller
return response()->json([
'data' => Order::salesAnalytics(),
]);
RESULT
The problem is how can I show it to my chartjs like this see picture below.
You can use this array to determine the day name from day number
days_numbers = [
0 => 'saturday',
1 => 'sunday',
2 => 'monday',
3 => 'thuesday',
4 => 'wednesday',
5 => 'thursday',
6 => 'friday',
];
you can use this for getting day index:
$day_index = fmod($day_number, 7);
Related
I have employees, working_hours, & appointments table. with the following details:
Employees | working_hours | appointment
id, name | id, day, start_time, end_time, employeeable_id, employeeable_type | id, employee_id, start_date_time, end_date_time
Relation:
class Employee extends Model
{
public function workingHours()
{
return $this->morphMany(WorkingHour::class, 'employeeable');
}
}
class WorkingHour extends Model
{
public function employeeable()
{
return $this->morphTo();
}
}
class Appointment extends Model
{
public function employee()
{
return $this->belongsTo(Employee::class);
}
}
Employee A has the following working hours:
[
{ day: 1, start_time: '08:00:00', end_time: '17:00:00' },
...
{ day: 5, start_time: '08:00:00', end_time: '17:00:00 }
]
Employee A has an appointment on May 23, 2022 09:00:00 till 09:30:00 (each appointment duration is 30 minutes)
Question:
If admin requests for available slots from May 22, 2022 to June 1, 2022 for Employee A, I expect response like this:
[
{ '2022-05-22': ['08:00', '08:30', '09:00', ..., '17:00'] },
{ '2022-05-23': ['08:00', '08:30', '09:30'] } // 09:00 notice excluded.
...
{ '2022-06-01, [] }
]
How to define the above query? All I can think of is to loop every working hours time from employee A and check if the time is available or not.
I suggest you don't handle time with queries.
this is my solution:
public function index()
{
$appointment = [
'id' => 1,
'name' => 'Appointment 1',
'start_date_time' => '2022-05-23 09:00:00',
'end_date_time' => '2022-05-23 09:30:00'
];
// Employee A working hours
$workingHours = collect([
['day' => 1, 'start_time' => '08:00:00', 'end_time' => '17:00:00'],
['day' => 2, 'start_time' => '08:00:00', 'end_time' => '17:00:00'],
['day' => 3, 'start_time' => '08:00:00', 'end_time' => '17:00:00'],
['day' => 4, 'start_time' => '08:00:00', 'end_time' => '17:00:00'],
['day' => 5, 'start_time' => '08:00:00', 'end_time' => '17:00:00'],
['day' => 6, 'start_time' => '08:00:00', 'end_time' => '17:00:00'],
['day' => 0, 'start_time' => '08:00:00', 'end_time' => '17:00:00'], // carbon for sunday default is 0
]);
$dateArray = [];
$startDate = Carbon::parse('2022-05-22');
$endDate = Carbon::parse('2022-06-01');
while ($startDate->lte($endDate)) {
// seach for working hours that match the day of the week
$workingHour = (array) $workingHours->firstWhere('day', $startDate->dayOfWeek);
// generate time for each day
$times = $this->generateTimes($workingHour);
// extract date from appoint start date time
$appointmentDate = Carbon::parse($appointment['start_date_time'])->format('Y-m-d');
if ($appointmentDate === $startDate->format('Y-m-d')) {
// remove time according to appointment time
$times = $this->removeTime($times, $appointment);
}
// add time to date array
$dateArray[$startDate->format('Y-m-d')] = $times;
// increment date
$startDate->addDay();
}
dd($dateArray);
}
private function generateTimes(array $workingHour)
{
// the working time of the workers must be reduced by at least 1 hour.
// because there is no way for you to have an appointment on your end working time.
$startTime = Carbon::parse($workingHour['start_time']);
$endTime = Carbon::parse($workingHour['end_time'])->subHour();
$times = [];
while ($startTime->lte($endTime)) {
$times[] = $startTime->format('H:i');
$startTime->addMinutes(30);
}
return $times;
}
private function removeTime($times, $appointment)
{
$startTime = Carbon::parse($appointment['start_date_time']);
$endTime = Carbon::parse($appointment['end_date_time']);
$startTime = $startTime->format('H:i');
$endTime = $endTime->format('H:i');
$times = array_diff($times, [$startTime, $endTime]);
return $times;
}
How can i build query with subexpression, without using yii\db\Expression and raw sql. For example this:
SELECT * FROM user WHERE archived = 3 AND ((group = 2 AND status = 3) OR (group = 3 AND status = 2));
You can build such condition using array expressions:
$users = (new Query())
->from('user')
->where(['archived' => 3])
->andWhere([
'or',
[
'group' => 2,
'status' => 3,
],
[
'group' => 3,
'status' => 2,
],
])
->all();
I have the following query in a Cakephp 2.4 model:
$scores = $this->WorkInfo->find('list', array(
'conditions' => array('WorkInfo.work_id' => $work_ids),
'fields' => array('WorkInfo.date', 'SUM(WorkInfo.score)'),
'group' => array('WorkInfo.date')
));
Which generates the following query:
SELECT
`WorkInfo`.`date`,
SUM(`WorkInfo`.`score`)
FROM
`home`.`work_infos` AS `WorkInfo`
WHERE
`WorkInfo`.`work_id` IN (4, 7, 8, 12, 9, 11, 13, 10, 14, 6, 5)
GROUP BY
`WorkInfo`.`date`
The result I get in my application is:
'2014-03-24' => null
'2014-03-25' => null
'2014-03-26' => null
'2014-03-27' => null
'2014-03-28' => null
'2014-03-31' => null
While the result I get from pasting this very query in the mysql console is:
'2014-03-24' => 0
'2014-03-25' => 36
'2014-03-26' => 0
'2014-03-27' => 164
'2014-03-28' => 0
'2014-03-31' => 0
What is going on here? It is supposed that same queries output same results, isn't it?
I have read something about creating virtual fields for this, but I do not want to overkill, it should be possible to perform a simple aggregation query through Cakephp using the find function.
Thanks!
Try this
$scores = $this->WorkInfo->find('all', array(
'conditions' => array('work_id' => $work_ids),
'fields' => array('date', 'SUM(score) AS score'),
'group' => array('date')
));
then with Set::combine you can format your array cakephp find list
$scores = Set::combine($scores, '{n}.WorkInfo.date', '{n}.0.score');
prints=>
'2014-03-24' => 0
'2014-03-25' => 36
'2014-03-26' => 0
'2014-03-27' => 164
'2014-03-28' => 0
'2014-03-31' => 0
Ok, sadly, I think what you want to do can't be done as you want to do it.
Let's see, you use the find('list') method, so that's here in the API. Code looks normal, and as you said, query is ok, returns everything you want. Problem is in line 2883
return Hash::combine($results, $query['list']['keyPath'], $query['list']['valuePath'], $query['list']['groupPath']);
That line organizes the returned array after the query is done. And seeing the doc for that function, we have
Creates an associative array using a $keyPath as the path to build its
keys, and optionally $valuePath as path to get the values. If
$valuePath is not specified, or doesn’t match anything, values will be
initialized to null.
Which is what happens to you. Now, debugging, the query result before applying the Hash::combine function is something like this
Array
(
[0] => Array
(
[WorkInfo] => Array
(
[date] => 2013-04-01
)
[0] => Array
(
[SUM(`WorkInfo`.`score`)] => 24
)
)
)
so you see, you get the results. And the respective Hash::combine
Array
(
[groupPath] =>
[valuePath] => {n}.SUM(WorkInfo.score)
[keyPath] => {n}.WorkInfo.date
)
which probably causes problem with the dot inside the parenthesis. And the combine function doesn't find the valuePath, and you get null, and you get sad.
If you change your query to 'SUM(WorkInfo.score) AS score' (leaving everything as is), you have almost the same problem with valuePath
Array
(
[groupPath] =>
[valuePath] => {n}.SUM(WorkInfo.score) as score
[keyPath] => {n}.WorkInfo.date
)
//respective result array
Array
(
[0] => Array
(
[WorkInfo] => Array
(
[date] => 2013-04-01
)
[0] => Array
(
[score] => 24
)
)
)
You might think that doing 'SUM(score) AS score' (without the dot) will solve it, but the code of find('list') adds the alias if it doesn't find a dot (in line 2865).
So... I guess what I'm saying is: do a virtual field, or listen to Isaac Rajaei, or create a custom find function. But with find('list') and SUM() you won't have luck :(
I am using cakephp 1.3. I have date field in incomes table. I am trying to get total income per month in a loop. The following is my query.
$income_and_hst = $Income->find('all', array(
'fields' => array('SUM(Income.amount) as income',
'SUM(Income.hst_amount) as hst',
'MONTH(date) as month'),
'conditions' => array(
'Income.income_account_id' => array(1,2,3,4),
'Income.user_id' => $this->Auth->user('id'),
'Income.account_id' => $this->Session->read('Account.default_account'),
'Income.date >' => $starting_date,
'Income.date <' => $ending_date,
),
'group' => 'MONTH(date)',
)
);
This gives me 5 months of income. Because the income were from 5 months. I need to show all 12 months even there is no income in other months. If there is no income i want 0 for that month.
Could someone give me a direction please?
Thank you.
My guess is that you cannot do that using that interface. You either need to dive into raw SQL (and a cross join), or add the missing months in the surrounding php code. I suggest the latter something like this should work (pseudocode, i don't remember php syntax):
for ($row in $income_and_hst) {
$income_and_hst_all[$row['month']] = $row
}
for ($month = 1;$month <= 12; $month++) {
if ($income_and_hst_all[$month] == nil) {
$income_and_hst_all[$month] = Array (
'income' => 0,
'hst' => 0,
'month' => $month
)
}
}
Right now, I'm doing:
$posts = get_posts(array('post_type' => 'page', 'post__in' => array(1, 3, 2, 9, 7)));
and am having two issues:
Post 3 is of 'post_type' => 'post', so it doesn't get selected, but I want it! If I leave out 'post_type' => 'page', then only post 3 is selected (because it must assume 'post_type' => 'post'.).
I want to be able to order the posts arbitrarily by their ids. If I knew how to use MySQL, I could do:
SELECT * FROM wp_posts WHERE ID IN (1, 3, 2, 9, 7)
ORDER BY FIND_IN_SET(ID, '1,3,2,9,7');
But, how should I do this with WordPress?
First fetch all posts arbitrarily by their ids and then loop through all the posts
You can do in this way:-
$posts=$wpdb->get_results("SELECT ID FROM $wpdb->posts WHERE ID IN (1, 3, 2, 9, 7)
ORDER BY FIND_IN_SET(ID, '1,3,2,9,7')");
$count=count($posts);
for ($counter=0 ; $counter < $count; $counter++)
{
$post=get_post( $posts[$counter]->ID, $output );
//do your stuffs with posts
}
Hope this helps
Kawauso on the #wordpress IRC channel informed me that "post_type takes an array of values." From that, I found that the following also selects post 3:
So, I did the following:
$post_ids = array(1 => 0, 3 => 1, 2 => 2, 9 => 3, 7 => 4);
$posts = get_posts(array('post_type' => array('post', 'page'),
'post__in' => array_keys($post_ids)));
$ordered_posts = array(0,0,0,0,0); // size of five; keeps order
foreach ($posts as $p) {
setup_postdata($p);
$ordered_posts[$post_ids[$p->ID]] = array(
'permalink' => get_permalink($p->ID),
'title' => $p->post_title,
'excerpt' => get_the_excerpt(),
'date' => date('F j, Y', strtotime($p->post_date)));
}
According to this thread, you can use this code and then use the classic WordPress loop:
$args = array(
'post_type'=>'page',
'orderby'=>'menu_order',
'order'=>'ASC'
);
query_posts($args);