Jump to content

is this possible?


bwakad
 Share

Recommended Posts

Suppose after a find, you would like to have a sidebar that says from these results,

on field A, we have xx items

on field B, we have xx items

etc.

to be clear: NOT the total of pages which are in DB. But from the found pages!

Link to comment
Share on other sites

This is what I am after:

Find pages with field01 value X returns results-array.

The pages in this array have fields with the same or different values.

So, I know the fields that will be returned, but not their values.

result 1 - with field02 value A, field03 with value Y

result 2 - with field02 value B, field03 with value Y

result 3 - with field02 value A, field03 with value Z

etc

from these results I would like to know:

HOW MANY have field02 with value A?

HOW MANY have field02 with value B?

HOW MANY have field03 with value Y?

HOW MANY have field03 with value Z?

etc.

For the example above, I have about 15 parents with 10 to 35 child pages as values for my page-selects.

The 15 fields (parents) are always in any single result. But the value can be different.

So as long as I get a result, those 15 fields are displayed as values.

I was looking into array functions, but it's way over the top:

to make 15 arrays with their values,

then match a value from the array with the one returned in a foreach ....

I think. So I thought, maybe PW already had such a thing in mind?

Link to comment
Share on other sites

Perhaps this will do the job (I havent tested it)

$results = $pages->find("field01=X");

$amountField02A = count($results->find("field02=A"));
$amountField02B = count($results->find("field02=B"));
$amountField03Y = count($results->find("field03=Y"));
$amountField03Z = count($results->find("field03=Z"));
  • Like 1
Link to comment
Share on other sites

Can't really explain it differently. In a way Raymond gave, except I DO NOT KNOW it's value ! Difficult to do.

But reading the API cheatsheet I see 2 functions:

$a->getValues() - which would return a php array with all values.

$a->unique()      - which would return array without duplicate values.

I am guessing I need to do the first and then count each value in this array. But using in a function I get undefined index???

Link to comment
Share on other sites

Even after reading your posts multiple times I don't understand a single thing. 

I doubt you'll find someone understanding what you want to do. Too abstract and not a comprehent case.

After all it may help to understand if you actually tell the guys here what you need to achieve, rather than I need count field01 => valueX. It could be that you go completely wrong about doing something.

  • Like 1
Link to comment
Share on other sites

Okay, because you look so mad on your avatar :) ...

let's say I do a $pages->find("items") sorted by branche. In results I have items. And I display those like this:

item 01

some title | branche: Nokia      | province: Drenthe    | network: 4

------------------------------

item 02

some title | branche: Siemens | province: Groningen | network: 6

------------------------------

item 03

some title | branche: Siemens | province: Groningen | network: 4

------------------------------

then to say FROM each field: how many of these items have the same value or single? example:

province "Drenthe" = 1

province "Groningen" = 2

network "4" = 2

network "6" = 1

branche "Nokia" = 1

branche "Siemens" = 2

Link to comment
Share on other sites

I already was playing with that function... don't mind the names I used. For now, it's just to test.

Basically I was thinking to use arrays

function create_arrays(){
    $page = wire("page");
    $pages = wire("pages");

    // this array will hold all my field names, for now just one!
    // Later, I will create the array automatic
    $fields = array('provincie'); 

    // this array will hold all field values related to $fields array value
    // Later, I will create the array automatic
    $values = array('drenthe','friesland'); 

    // here I create a new array to store values
    $new = array(); 
   
    // iterate through the $fields array
    foreach ($fields as $field) {
        
        // then after one, iterate through the $values array
        foreach($values as $value){

            // static code, but obviously I need the already used one which led me to current page
            // I use the $field and $value to get my "field=name"
            $selects = $pages->find("template=child-template, {$field}=$value");
            if(count($selects)){
                foreach($selects as $item)    {
                    // here I store the found $value in the array I created
                    $new[] = "{$value}";
                }
            }
        }
    }
    // this code is just to see output
    echo count($new)    ;
    echo "<pre>";
    print_r($new);
    echo "</pre>";

    // this part does the actual counting of what I need
    $sub_count = array_count_values($new);
    while (list ($value, $qty) = each ($sub_count)) {
           echo "$value : $qty "."  times"."<br/>";
    }
}

So, if you use this code, with minor adjustments, you will see what I am after.

Link to comment
Share on other sites

Hmm, I see. Now it's a little clearer.

But how do you know all the values those fields can have? This is a critical point. If not known, you theres one option to loop all those pages and collect field -> values, while the nested array with the same values as the key will get incremented instead of added.

I think the fields (their names) at least is something to be known.

$someFields = array("title", "headline");

$somePages = $pages->find("template=basic-page, category=phones"); // just something
$resultArray = array();

foreach($somePages as $p)
    foreach($someFields as $field)
        if(isset($resultArray[$field][$p->$field]))
            $resultArray[$field][$p->$field]++;
        else
            $resultArray[$field][$p->$field] = 1;

print_r($resultArray);

foreach($resultArray as $field => $values)
    foreach($values as $value => $count)
        echo "<p>$field - $value: $count</p>";

The amount of field values is the one of unique ones, while their values is the count found.

There's no PW distinct selector for fields unfortunately to count pages like that without knowing all the values, though there would be ways to do it with raw sql query for sure. But then you'd have to account for a couple things like is the page published and such.

This of course can be a a heavy method once you need to loop thousands of pages on every page request. So always good to be careful and try to find way to minimize the load. There's also ways to cache snippets and store things to pages to load from and update them frequently using cronjob or hooks.

Link to comment
Share on other sites

To get something as a function, just for learning purposes, the code could be like this

function getDistinctValues(PageArray $pageArray, array $fields){
    $arr = array();
    foreach($pageArray as $p)
    foreach($fields as $field)
        if(isset($resultArray[$field][$p->$field]))
            $arr[$field][$p->$field]++;
        else
            $arr[$field][$p->$field] = 1;
    return $arr;
}

$someFields     = array("title", "headline");
$somePages      = $pages->find("template=basic-page");
$resultArray    = getDistinctValues($somePages, $someFields);

foreach($resultArray as $field => $values)
    foreach($values as $value => $count)
        echo "<p>$field - $value: $count</p>";

And following is a way to add a new method to a PageArray using a method hook.

// this is right in a template code, but could also be in a autoload helper module

wire()->addHook("PageArray::getDistinctValues", null, function(HookEvent $event){
    $pageArray = $event->object; // the page array getDistinctValues($fieldsArr) is called on
    $fieldsArray = $event->arguments(0); // the first argument
    $arr = array();
    foreach($pageArray as $p)
        foreach($fieldsArray as $field)
            if(isset($arr[$field][$p->$field]))
                $arr[$field][$p->$field]++;
            else
                $arr[$field][$p->$field] = 1;
    $event->return = $arr;
});

$someFields     = array("title", "headline");

// And now you can do this on a page find result
$resultArray    = $pages->find("template=child-template")->getDistinctValues($someFields);

foreach($resultArray as $field => $values)
    foreach($values as $value => $count)
        echo "<p>$field - $value: $count</p>";

  • Like 2
Link to comment
Share on other sites

wow, you're good! I'd have to look a good number of times into these code examples you gave.

At first I thought there was a native PW function, and was trying to use:

$a->getValues() - which would return a php array with all values.

$a->unique()      - which would return array without duplicate values.

But I really did not know how to use them inside the function, so I went for the long walk. lol

Your examples are very good to study on (as I am still learning php) and I probably end up with a way of using them. My plan is not to just launch and then build further, but to build every week something, and much much later I launch. For now the learning curve is way to much fun, it's just the explaining from my part which is hard sometimes!

I probably also did not mention my field values are in fact page selects. So to get all those values into an array, I would need to use a find parent=provincie and take child page names. I know PW is one of the fastest to retrieve items of any kind. Good job from Ryan! But I am concerned because I have 8 fields (parent page) with each about 30 child pages. Would it be an overload to use that in a function?

  • Like 2
Link to comment
Share on other sites

Ah and just remembered that since PW 2.4 the simplest way to count values of certain keys/fields within a PageArray/WireArray is using the new WireAarray::explode() - combined with using PHP's array_count_values(array) you already used, it's down to this:

$someFields     = array("province", "network");
$somePages      = $pages->find("template=child-template, category=xxx");
$resultArray    = array();

foreach($someFields as $field) {
    $resultArray[$field] = array_count_values($somePages->explode($field));
}

// that's it show array result
foreach($resultArray as $field => $values) {
    foreach($values as $value => $count) {
        echo "<p>$field - $value: $count</p>";
    }
}
  • Like 5
Link to comment
Share on other sites

Warning: array_count_values(): Can only count STRING and INTEGER values!

on this line: $resultArray[$field] = array_count_values($somePages->explode($field));

It is strange because $field is in string format!

Only this code:

$someFields     = array("provincie","branche");
echo "<pre>".print_r($someFields)."</pre>";

outputs:

Array ( [0] => provincie [1] => branche )
1

below is code from Soma:

$someFields     = array("province", "network");
$somePages      = $pages->find("template=child-template, category=xxx");
$resultArray    = array();

foreach($someFields as $field) {
    $resultArray[$field] = array_count_values($somePages->explode($field));
}

// that's it show array result
foreach($resultArray as $field => $values) {
    foreach($values as $value => $count) {
        echo "<p>$field - $value: $count</p>";
    }
}
Link to comment
Share on other sites

I am not sure I follow you... "since PW 2.4 the simplest way to count values of certain keys/fields"... won't work with page fields.

Isn't the page name/title and the (page) field name a string?

Link to comment
Share on other sites

WireArray::explode() is not to count values but to create an array of PageArray, much like the php explode(), array_count_values() is the one only working with strings ans integers.

WireArray::explode() doesn't care if it's a string or integer. Page fields or file fields, any multiple value fields are objects or arrays.

Link to comment
Share on other sites

So, with your last code, I can't count the occurrence of a field VALUE, but can count the occurrence of the field NAME. Which, from my latest example is not what I am after, since all my fields are required and always occur.

Because this code will give me the pagenames that have the array's field 'provincie' present:

foreach($someFields as $field) {
    $resultArray[$field] = array_count_values($somePages->explode('name'));
}
echo "<pre>".print_r($resultArray)."</pre>";

But I will continue. You already helped a great deal and made me learn more. Thanks so far !

  • Like 1
Link to comment
Share on other sites

To get something as a function, just for learning purposes, the code could be like this

function getDistinctValues(PageArray $pageArray, array $fields){
    $arr = array();
    foreach($pageArray as $p)
    foreach($fields as $field)
        if(isset($resultArray[$field][$p->$field]))
            $arr[$field][$p->$field]++;
        else
            $arr[$field][$p->$field] = 1;
    return $arr;
}

$someFields     = array("title", "headline");
$somePages      = $pages->find("template=basic-page");
$resultArray    = getDistinctValues($somePages, $someFields);

foreach($resultArray as $field => $values)
    foreach($values as $value => $count)
        echo "<p>$field - $value: $count</p>";

ps. in this function you need to pass the [$field] and [$p->$field] as string e.g. (string) inside [], or you will get illegal offset

Link to comment
Share on other sites

So, with your last code, I can't count the occurrence of a field VALUE, but can count the occurrence of the field NAME. Which, from my latest example is not what I am after, since all my fields are required and always occur.

 

Because this code will give me the pagenames that have the array's field 'provincie' present:

All my codes count distinct VALUES of those fields specified and not the field name. But you changed something there to $somePages->explode('name') and name would be the page names values, but you set them to the [$field] array so you mess things up.

ps. in this function you need to pass the [$field] and [$p->$field] as string e.g. (string) inside [], or you will get illegal offset

I don't see the need to add (string) as if you deal with strings there's no problem, but I guess you deal with objects or array as $p->$field and that's not allowed.

After all I think you just need to adapt code to your needs and I provided various pseudo examples I think you can learn something. It's not meant to work for you as copy paste.

Link to comment
Share on other sites

Yes. I changed it to $somePages->explode('name') to see what is was returning: obviously the page withing the pageArray.

>>> function getDistinctValues(PageArray $pageArray, array $fields){

>>> Isn't a pageArray returning objects by default?

Link to comment
Share on other sites

Yes. I changed it to $somePages->explode('name') to see what is was returning: obviously the page withing the pageArray.

No it's returning array with values, not a page.

PageArray::explode() return array with the values of the requested properties of all pages in the page array.

Maybe aswell look it up what it does, if explaining and showing it here isn't enough for you. https://github.com/ryancramerdesign/ProcessWire/blob/master/wire/core/WireArray.php#L1423

>>> function getDistinctValues(PageArray $pageArray, array $fields){

>>> Isn't a pageArray returning objects by default?

Yes PageArray is an array with object, but I looks like you don't get it :)

I'm looping page array. In there I loop fields array and fill an array with

$array[$field][$p->$field] 

Translates to 

array["fieldnameA"]["value1"] -> count

array["fieldnameA"]["value2"] -> count

$p->$field is returning the value of the field.

$field is a variable of the fieldname so it's like

$p->fieldnameA 

But in your case it seems you deal with fields of type page so the field value is an object if you will so

Filling array keys with objects or array leads to illegal offsets.

Link to comment
Share on other sites

After all you can only fill an array with strings ro integers if you want to use array_count_values() later on. 

So if you deal with object or arrays for values you have to maybe (string) cast the value as you already found out. 

Then as Martijn points out the toString method comes into play and images or page arrays will end up like this as string: 

["myimage1.jpg|someother.jpg"]

or

["1203|1239|1233"]

But then I don't know what suites in your case and what you really need, but you'll find out I'm sure.

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