Jump to content

Sort problem: Selector with date needs empty dates last


Xonox
 Share

Recommended Posts

Hi,

I'm having a sorting problem that I need to solve. I have the following code:

$today = time();
$trainings = $pages->get('/formacao/')->find("template=training, limit=6, !training_start<$today, sort=training_start");

It's working fine, except for one little problem: I need to show the trainings that have training_start filled first and then the one's that don't. This solution shows the empty ones first! :(

Is there any way to do this with a simple selector? Or do I have to find twice?

To understand better:

Result that I have now:
Footbal: Date not set yet!
Ragueby: Date no set yet!
Volleyball: 1-Apr-2016
Handball: 5-Apr-2016
Running: 10-Apr-2016
Jumping: 15-Apr-2016

Result needed:
Volleyball: 1-Apr-2016
Handball: 5-Apr-2016
Running: 10-Apr-2016
Jumping: 15-Apr-2016
Footbal: Date not set yet!
Ragueby: Date no set yet!

Link to comment
Share on other sites

Hi Xonox,

You could create a new PageArray and append the pages without the training start time at the end:

$today = time();
$parent = $pages->get('/formacao/');
$trainings = $pages->find("parent=$parent, template=training, limit=6, !training_start<$today, sort=training_start");
$_trainings = new PageArray();
$empty = new PageArray();  
foreach ($trainings as $training) {
    if ($training->training_start) {
      $_trainings->add($training);
    } else {
      $empty->add($training);
    }
}
$_trainings->import($empty);

I'm sure there are more elegant solutions :)

  • Like 2
Link to comment
Share on other sites

32 minutes ago, Wanze said:

Hi Xonox,

You could create a new PageArray and append the pages without the training start time at the end:

Hi Wanze,

Most of the times ProcessWire has an elegant solution. I was hoping that someone would give me an insight about some hidden sort option that would allow me to avoid the array processing.

However, your solution mentioned the $p->import($pages), that I was unaware of and it looks like it really fits my needs.

Thanks a lot for your reply, I'll be using your code. ;)

Link to comment
Share on other sites

In MySQL NULLs are considered lower than any non-NULL value. So if you order ASC then NULLS come first. To change this you would use maybe something like this in MySQL:

ORDER BY ISNULL(yourfield) ASC, yourfield ASC;

But i don't think ISNULL is somehow implemented in PW's selector engine sorting. I've never needed this myself but maybe it's worthwhile to add this.

A very ugly workaround could be to set the  'no date' items to a date of let's say 31-12-9999.

I think a second find for empty items and appending them to the original PageArray wouldn't hurt too much either. You could compare performance against solutions like Wanze's.

  • Like 1
Link to comment
Share on other sites

18 hours ago, SiNNuT said:

A very ugly workaround could be to set the  'no date' items to a date of let's say 31-12-9999.

I think a second find for empty items and appending them to the original PageArray wouldn't hurt too much either. You could compare performance against solutions like Wanze's.

I thought of that workaround but, as you stated, is quite ugly and, as you might know, the clients tend to not understand "why is that date there".

A second find with an append might be another good solution. In terms of performance might be worth it because I'm showing a total of 6 items and if those six have dates, I don't need to get the one's that don't. I'll do some testing.

Thanks SiNNuT!

Link to comment
Share on other sites

Or add a checkbox to the template and when saving a page check for date and if empty set the checkbox. Then use "sort=hasdate_checkbox, sort=training_start, sort=id"

  • Like 1
  • Thanks 1
Link to comment
Share on other sites

On 6/28/2016 at 0:15 PM, Soma said:

Or add a checkbox to the template and when saving a page check for date and if empty set the checkbox. Then use "sort=hasdate_checkbox, sort=training_start, sort=id"

Hi Soma,

Your solution looks elegant. To me, it looks like the method you propose can be useful for more situations. Can you share link to a resource on how to do this? I looked for such a feature in the backoffice but couldn't find it so I figure it must be done via PHP, or am I wrong?

Link to comment
Share on other sites

9 hours ago, Xonox said:

Hi Soma,

Your solution looks elegant. To me, it looks like the method you propose can be useful for more situations. Can you share link to a resource on how to do this? I looked for such a feature in the backoffice but couldn't find it so I figure it must be done via PHP, or am I wrong?

You need to add the checkbox in the backoffice. Then you need to do some PHP stuff. It might seem fancy, but believe me it's quite easy once you'll get a hold of this hooking stuff.

Create a ready.php in your /site/ folder. Then place this:

<?php

// You can hook into the saving process => https://processwire.com/api/hooks/
$pages->addHookAfter('saved', function($event) {
	
	// We grab the current object (the page being saved) and store it in $page
	$page = $event->object; 
	
	// Only run this script on training templates
	if ($page->template !== 'training') return; 
	
	// Only run this script on empty dates
	if (!empty($page->training_start)) return; 

	// Save field hasdate_checkbox and set value to checked/1
	$page->setAndSave('hasdate_checkbox', 1); 
	
});

Written in browser, so not tested. But following the links provided above you will get an idea. 

  • Like 4
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...