Jump to content
Xonox

Sort problem: Selector with date needs empty dates last

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!

Share this post


Link to post
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

Share this post


Link to post
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. ;)

Share this post


Link to post
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

Share this post


Link to post
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!

Share this post


Link to post
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

Share this post


Link to post
Share on other sites
32 minutes ago, tpr said:

I wonder whether the or-groups could help in this case:

Nope, sort is only evaluated for the main selector part, but not for/inside or-groups.

  • Like 1

Share this post


Link to post
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?

Share this post


Link to post
Share on other sites
On 6/28/2016 at 0:30 PM, LostKobrakai said:

This one would also work, especially if you need pagination: https://github.com/LostKobrakai/Paginator

Hi LostKobrakai

Looks interesting, thanks for pointing it out. For my current project is too much, I think, but I it will be useful in the future.

Share this post


Link to post
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

Share this post


Link to post
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

  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By Roberts R
      I have simple page structure:
      category subcategory simple-product simple-product simple-product simple-product subcategory .... category2 so Im at category page and running
      $pages->find("template=simple-product, has_parent=$page, limit=8"); and it returns 0 pages
       
      but this returns 4 pages
      $pages->find("template=simple-product, has_parent=$page"); Can someone explain why limit does not work here?
      EDIT:
      So I did some tests and it seems that any limit=n where n is >= actual page count that is possible ... selector return 0 results.
    • By jds43
      Hello, I have a Page Reference by template radio button field to promote a certain page (only two options), but I'd like to target the page that isn't selected. This would be used dynamically throughout the site.
      Does anyone know how I could accomplish this? Would I use something like remove() or not()?
       
    • By Hubris
      Hi there!
      I'm using some page reference fields to create lists of tags, categories, years, etc.. I'm able to find the pages like so:
      $pages->find("template=project, {$filter}={$page->title}"); Which dynamically does something like: 
      $pages->find("template=project, tags=Experimental"); Only if the value (the page name, like "Experimental") starts with letters. If it starts with numbers, find returns nothing.
      Why is this and how can I fix it?
    • By Elchin
      Hi.
      I want select pages where now between date and end_date or now bigger than date and end_date is empty.
      I have five tried variants:
      $start = strtotime(date('Y-m-d') . " 00:00:00"); $results = $page->children("foo=(date<$start,date_end=''),bar=(date<$start,date_end>=$start),sort=-date,limit=12"); $start = strtotime(date('Y-m-d') . " 00:00:00"); $results = $page->children("date<$start,(date_end='',date_end>=$start),sort=-date,limit=12"); $start = strtotime(date('Y-m-d') . " 00:00:00"); $results = $page->children("date_end=''|date_end>=$start,date<$start,sort=-date,limit=12"); $start = strtotime(date('Y-m-d') . " 00:00:00"); $results = $page->children("!date_end|date_end>=$start,date<$start,sort=-date,limit=12"); $start = strtotime(date('Y-m-d') . " 00:00:00"); $results = $page->children("date_end>=$start|!date_end,date<$start,sort=-date,limit=12"); All this variants not worked for me and returned zero results.
×
×
  • Create New...