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

  On 6/27/2016 at 11:30 AM, Wanze said:

Hi Xonox,

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

Expand  

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

  On 6/27/2016 at 3:22 PM, 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.

Expand  

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 11:15 AM, 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"

Expand  

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

  On 6/30/2016 at 10:47 AM, 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?

Expand  

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...