[Solved] Add extra condition for return specific results

Hi all

The code below puts data into an array, sorts it then displays as a list of articles/data. The problem is that the result lists a selection of different articles from different categories, what I need is to only show the articles that match a certain column. The column I need to match is ext_column_1.

I was thinking something like $cat = isset($activePage->ext_column_1), though I’m not sure how to add another function or what to do here.

My question, how do I only show the page items that match the ext_column_1 column?

$overAllArray2Sort = array();

foreach ($topPages as $topPage){
$articlePages = $topPage->getChildren(null,true);
  foreach ($articlePages as $articlePage){
      $overAllArray2Sort[] = array('pageid' => $articlePage->page_id, 'date'=>strtotime($articlePage->ext_column_4));
  }
}
usort($overAllArray2Sort, 'rcmp');

$i = 0;
foreach($overAllArray2Sort as $item) {
if($i > 9) {
    break;
}
$articlePage = $pageNav->getPage($item['pageid']);
$i++;

Any help, advice or example much appreciated thanks,
Barry

Try [FPHP]array_filter[/FPHP]'ing your $articlePages.

Are you pulling it from the database? If so you can add a where clause, if not use a loop and and an inner if statement and build a new array filled with the desired data.

Thanks guys!

After chatting with a colleague who helped me, array_filter is what we needed, as @StarLion also mentioned, and thanks @animedreamz73. First time I’ve used array_filter. Not sure exactly how this code is working, though have a good idea whats happening, everything works :smile:

Full solution:

function cat($element){
  global $cat;
  return($element['cat']==$cat);
}

$cat = $activePage->ext_column_1; 

Then further down where I loop through the results:

$overAllArray2Sort = array();

foreach ($topPages as $topPage){
$articlePages = $topPage->getChildren(null,true);
  foreach ($articlePages as $articlePage){
    $overAllArray2Sort[] = array(
      'pageid' => $articlePage->page_id,
      'date'=>strtotime($articlePage->ext_column_4),
      'cat'=>$articlePage->ext_column_1,
      );
  }
}
$overAllArray2Sort = array_filter($overAllArray2Sort, "cat");
usort($overAllArray2Sort, 'rcmp');

$i = 0;
foreach($overAllArray2Sort as $item) {
if($i > 9) {
    break;
}
$articlePage = $pageNav->getPage($item['pageid']);
$i++;

Nice to hear any views on this, else thanks for getting involved.
rcmp is another small function I use for the sorting if anybody is wondering.

Barry

I would have filtered before the foreach.

$articlePages = array_filter(topPage->getChildren(null,true),"only_this_cat");

function only_this_cat($element) {
  global $activePage;
  return $activePage->ext_column_1 == $element->ext_column_1;
}

As for what array_filter does, consider it doing this:

array_filter($array,“a_function”) is the same as:

foreach($array AS $key => $element) {
  if(a_function($element) == false) {
    unset($array[$key]);
  }
}

(Note: Do not ever do this as written. Messing with the array in the middle of a foreach is a no-no.)

Impressive! Thanks @StarLion, I’ll make note.
Might try to modify this if this would improve things. Everything works, don’t want to mess with things just yet :smile:

I would have filtered before the foreach.

What is the benefit?

And one thing I keep seeing, and you’ve just used it yourself is unset()

From php.net

unset() destroys the specified variables

Why do we do this, and what is it achieving?
And what would happen if we don’t unset?

Thanks, Barry

So it’s about iterations and object sizes.

Lets say topPage->getChildren gets… 100 records. These are now an array, which you put into $articlePages.
Next, you foreach that array; So that’lll be 100 loops through the code.
Now you store all the relevant information about EVERY article into your $overAllArray2Sort array. So it’s got 100 entries in it at the end, and looks an awful lot like your original array. At this point, you’re using up basically double the memory to hold the same piece of information. Oh and you also ran strtotime function on all 100 dates.
Then you array filter. Now you throw away everything that doesnt match your filter - in this case, that the category matches. So now your overallArray2Sort contains… lets say 20 items.

However, if you filter FIRST, you can wheedle this down a lot easier.
Now when you ‘create’ your first array, it’s got 20 items in it.
At this point, you… dont really need to do anything with date, because you never use it in this script. For that matter, you dont seem to need the second array at all, given what you’ve shown us – there’s certainly a lot more optimizing of code that can be done here! But even if you wanted to create the second array for other things you do, now you only have to do 20 loops to cover all of the data - only 20 calls to strtotime, 20 array entry creations, etc - saving script execution time, and memory usage.

Narrowing down the data to the relevant data before doing work on it will save in the long run.

1 Like

Thank you! One of the best explanation I’ve had for some time, really helps.

After reading this, I see exactly what you’re saying now, and does make perfect sense. Previously I was working with this code before introducing the $overAllArray2Sort array, this was needed because of the cms and not being able to sort these columns from the database. Though won’t go into that, had a major thread some time back.

The reason I’m using the date is because I’m displaying articles and sorting them by date, also displaying the date as show below, this is what sits underneath. Are you saying I don’t need that now?

<article class="<?=$articlePage->ext_column_1 ?>">
   <a href="<?= $articlePage->url ?>" class='article-border'>
      <?php if (!empty($articlePage->ext_column_2)) : ?>
          <img src="<?=$articlePage->ext_column_2 ?>" alt="">
        <?php else: ?>

      <?php endif ?>
        <header>
            <h3>
                <?= $articlePage->ext_column_3 ?>
            </h3>
        </header>
        <footer>
            <p>
              <?php echo date("d F Y", strtotime($articlePage->ext_column_4))."<span class='sprite article-link ".$articlePage->ext_column_1."'></span>" ?>
            </p>
        </footer>
    </a>
</article>

I also have the sorting function:

//Ascending  
function rcmp($a, $b)
    {
        if ($a['date'] == $b['date']) {
            return 0;
        }
        return ($a['date'] < $b['date']) ? 1 : -1;
    }

Hope this makes sense, does this change anything now from your perspective regarding the date?

And again, appreciate the detailed explanation thanks.

Barry

What format is the date in when it arrives at the script?

Its a string, ext_column_4 = varchar(255) ?
The dates are populated via a date popup and stored in the database column ext_column_4 as 2014-12-12

I previously had another column for the date, this is what was causing lots of issues, which was a timestamp.

So right now I see your script do this:

foreach ($topPages as $topPage){
  $articlePages = $topPage-&gt;getChildren(null,true);
  foreach ($articlePages as $articlePage){
    $overAllArray2Sort[] = array(
      'pageid' =&gt; $articlePage-&gt;page_id,
      'date'=&gt;strtotime($articlePage-&gt;ext_column_4),
      'cat'=&gt;$articlePage-&gt;ext_column_1,
      );
  }
}
$overAllArray2Sort = array_filter($overAllArray2Sort, "cat");
usort($overAllArray2Sort, 'rcmp');

$i = 0;
foreach($overAllArray2Sort as $item) {
if($i > 9) {
    break;
}
$articlePage = $pageNav-&gt;getPage($item['pageid']);
$i++;

Which in english, reads as:

  1. Find all Articles.
  2. For each article, create sub-array elements.
  3. Remove unnecessary data.
  4. Sort remaining data.
  5. Get the page data for the 9th remaining article. (Because you overwrite $articlePage every time through the loop).

Let me take a swing at it instead, and see if this makes sense to you:

<?php
 $articlePages = array_filter(topPage->getChildren(null,true),"only_this_cat");
usort($articlePages,"by_date"); //Now my data is trimmed down, and in order.
$articlePage = $pageNav->getPage($articlePages[8]->page_id);

function only_this_cat($element) {
  global $activePage;
  return $activePage->ext_column_1 == $element->ext_column_1;
}

function rcmp($a, $b)
    {
        if ($a->ext_column_4 == $b->ext_column_4) { //Really, a timestamp SHOULD be being used here. BUT. Y-M-D will allow sorting.
            return 0;
        }
        return ($a->ext_column_4 < $b->ext_column_4) ? 1 : -1;
    }
?>

I’m sure this will generate questions.

:smile: Absolutely!

I’ll need to digest this and have a crack in a more testing environment, this code is part of a site I’ve been working on for the past 2 months, suppose to go live next week ha.

For the record, each article/page is a sub/child from the parent page/category (which displays articles only for that section), and there are numerous categories. This section we’re working on, is only allowed to show related articles from that category in the footer. Likewise with the other categories where this code also runs, hence “only_this_cat”. This will put the sub-array elements into more perspective for you.

I didn’t realise.

Again, thanks for all your help with this StarLion, either way, if I use this update or not, learnt a lot here and will use these techniques for future projects and maybe updates to this project, possible localisations.

In short, I see right away you’re concentrating on performance, a good way to approach things, speed amongst other things. As things are, it’s unlikely I’ll go past 1000 articles over a 12 month period. But still adds up all those loops :smile:

Barry

Generalize your compare method. You might want to reuse it again but it is looking for specific data. Also your reserving way to much memory for the data, 255 characters for a 10 character string.

Lastly your cat function could use the variable as a reference and change it’s value.

function cat( &$element )
{
global $cat;
$element[‘cat’] = $cat;
}

Unless your trying to do a boolean comparison then just use an if statement to reduce your method call count and improve speed and memory.

the cat method (and the similar only_this_cat) is a boolean-returning function that does not modify the value of the element. It must be a boolean returning function to work with array_filter.

You could technically generalize the comparison function down more, but it would then require a further variable.

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.