Jump to content

getTotal() returns wrong value


LostKobrakai
 Share

Recommended Posts

I'm currently rebuilding a pagination to a custom one. Now I have an issue with $list->getTotal(). If I ommit the limit selector I count 16 entries, but getTotal() return me 17. After testing it, it seems my manual sorting is playing tricks. 
 

	$conversations = $page->children($selector);

	var_dump(count($conversations), $conversations->getTotal());

	$notRead = new PageArray();
	foreach($conversations as $conversation){
		//Check children (messages) for read status
		if(count($conversation->children("read_by!=$user"))){ 
			$notRead->prepend($conversation);
			$conversations->remove($conversation);
		}
	}

	var_dump(count($conversations), $conversations->getTotal(), count($notRead), $notRead->getTotal());

	$conversations->prepend($notRead);

	var_dump(count($conversations), $conversations->getTotal());

This outputs:

13, 13
11, 11, 2, 2
13, 14

Has anyone else noticesed something similar? To me it seems, like theres something wrong with the calculation.

Link to comment
Share on other sites

This behaviour is documented here: http://processwire.com/api/arrays/page/

$p->getTotal()

Get the total number of pages that were found from a $pages->find("selectors, limit=n") operation that led to this PageArray. The number returned may be greater than the number of pages actually in this PageArray instance, and is used for calculating pagination. Whereas $p->count() will always return the number of pages actually in this PageArray instance.

Link to comment
Share on other sites

I notices the wrong getTotal() value, while working with a limit. I removed it, so I can use count to check that there's indeed not a single page more in the pagearray than there should be. It was just a matter of finding out where the error was. 

Nobody an idea why this kind of sorting does change the total number?

Link to comment
Share on other sites

PageArray->prepend($item) originally was only for one item and import() was only for adding PageArray. This was added to support arrays for all add() prepend() append() etc.

Looks like the prepend() has a bug where it counts ++ when prepending multiple items.

It works correct if using append() or add(). If you use foreach to add via prepend(item) it works also correct. Maybe file an issue?

  • Like 1
Link to comment
Share on other sites

This is the current

public function prepend($item) {
    parent::prepend($item);
    $this->numTotal++;
    return $this;
}

and should be maybe like this rather

public function prepend($item) {
    parent::prepend($item);
    $this->numTotal = $this->count;
    return $this;
}

in PageArray.php

Link to comment
Share on other sites

Or simply do a foreach

foreach($notRead as $n) $conversations->prepend($n);

I think regarding what you seem to be doing, you add a children page to a page with a reference to a user read the article? This may create performance problems and you already doing work to get it out list via a double searching/filtering. Not sure what would be a better way, since you seem to like the notread on top? So a sorting by it is difficult. Maybe some more thinking would reveal a more scalable/easier way to do this..

Anyway if the children grow and you do it the way you do it will create performance issue:

This:

(count($conversation->children("read_by!=$user"))

Should be 

if($conversation->count("read_by!=$user")) ...

Or this

if($conversation->child("read_by!=$user")) 
Link to comment
Share on other sites

It's not about articles. I have conversations with all the messages as children. The messages all do have a pagefield, which stores the people who have already "read" this message. In this bit I load all the conversations a user is part of and sort the conversations, which do have unread messages, first. I don't know if there would be a better way to sort the conversations this way. The only one I can imagine right know is by using two different selectors.

Link to comment
Share on other sites

Regarding selectors, don't know if OR-groups, Group, sub-selectors would be relevant in your case?

https://processwire.com/talk/topic/3768-processwire-dev-branch/page-10#entry64049

https://processwire.com/talk/topic/7370-search-for-one-field-or-another-but-with-different-values/

https://processwire.com/talk/topic/3768-processwire-dev-branch/page-9#entry58722

Edit...hmmm, maybe not...not sure these would be helpful...

Edited by kongondo
Link to comment
Share on other sites

Ah. Well difficult one. 

All I know is that this is possible, but doesn't help and work in this case.

$pages->find("template=basic-page, sort=-children.count");

After some thinking, the best (I think) way with stuff already there, would be to mabye store the conversations to a page field on the user. Then remove read conversations from the page field. If a message is created, the conversation/topic page will be added to all users page field once (the overhead has to go somewhere? And if done via direct sql to insert id's to page field it's fast even for thousands of users).

// get the unread messages ids (1231|32232|2323|1233...)
$unreadIDs = $user->unread_conversations;

// OR groups either ids or parent
$conversations = $pages->find("(id=$unreadIDs), (parent=/conversations_parent/), limit=3");

// output entries, ids unread should be on top? (can't test here)
foreach($conversations as $conv){
     $class_unread = $user->unread_conversations->has($conv) ? "unread" : "read";
     echo "<p class='$class_unread'>$conv->title</p>";
}

// render pager 
echo $res->renderPager();
Link to comment
Share on other sites

Shouldn't something like this work? messages is a PageTable field, which includes all the children aka messages.

The first one should get all conversations without the ones where all messages were read by the user. 

The second one should get all the conversations which don't have a message, which the user not read.

$unread = $pages->find("…, users=$user, limit=10, !messages.read_by=$user");
$read = $pages->find("…, users=$user, limit=10, !messages.read_by!=$user");
Link to comment
Share on other sites

@soma

I added the read_by field to the conversations as well, so I can query by conversation not read as well as message not read. I also tried your idea with the or group, but it does not work. The pages as neither sorted by read / unread nor by time.

	// Conversationes the user is part of
	$selector = "template=conversation, users=$user, sort=-time";

	if($input->whitelist("conversation-search")){
		$q = $input->whitelist("conversation-search");
		$selector .= ", (title|messages.text_singular*=$q), (users.firstname|users.lastname=$q)";
	}

	$unread = $pages->find($selector.", read_by!=$user");
	$conversations = $pages->find("(id=$unread), (".$selector.", read_by=$user), limit=10");
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

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...