tags:

views:

172

answers:

5

I have an array of output from a database. I am wondering what the cleanest way to filter the values is

example array

Array
(
    [0] => Array
        (
            [title] => title 1
            [cat_title] => Drawings
            [sec_title] => Portfolio
        )

    [1] => Array
        (
            [title] => title 2
            [cat_title] => Paintings
            [sec_title] => Portfolio
        )

    [2] => Array
        (
            [title] => title 3
            [cat_title] => Drawings
            [sec_title] => Portfolio
        )
)

As an example what would be the cleanest way to make all of the cat_title to uppercase and all of the sec_title's to htmlspecialchars?

I was thinking if i sorted the array improperly that I could use the array map function. like this

improper array

Array
(
    [title] => Array
        (
            [0] => title 1
            [1] => title 2
            [2] => title 3
        )

    [cat_title] => Array
        (
            [0] => Drawings
            [1] => Paintings
            [2] => Drawings
        )

)

Then I could do something handy like:

array_map('strtoupper', $array['cat_title']);

and make all of the cat_titles uppercase in one go. Something like that would sure beat this, which is what I have going on now.

$count = count($array);
for($i=0; $i < $count; $i++) { 
    //filter list output
    if (isset($array[$i]['cat_title'])) {
     $array[$i]['cat_title'] = strtoupper($array[$i]['cat_title']);
    }
}

Do you guys know of anyway I could callback functions on numbered array's a little bit more elegantly then above? Hopefully without sorting the array incorrectly? something like array_map or array_walk?

+2  A: 

The Really Elegant way to do this is NOT to use associative arrays at all: make an array of objects. Turn your element into a Class which has a constructor, and title, cat_title, and sec_title as fields. Then make them private and use setters (or use a constructor) where you will check the data and perform any validation or transformation you need.

Palantir
Well this is the array that is coming out of the object and going into the templates. These values are being modified in a an object specific to the data already. I would just prefer not to have to : if (isset($array[$i]['cat_title'])) { $array[$i]['cat_title'] = strtoupper($array[$i]['cat_title']); }for every field in the array. If there is a particular design pattern that you are reffering to could you provide a link or it's name?
If you define your own class, you can set everything to a blank string in the constructor, so you don't need to use `isset`.
DisgruntledGoat
Could you provide a link to an example? If I am using pdo, would I use PDO::FETCH_OBJ? Is that what you mean? I am currently using PDO::FETCH_ASSOC. Hence ending up with an array.
Yes, you can use `FETCH_OBJ` (or `FETCH_CLASS` with a predefined class). But if you're using PDO then why do you need to use isset? If you selected those fields in your query they will always be set.
DisgruntledGoat
A: 

My solution is using array_map and anonymous functions:

<?php
$data = array_map(
    function($element) {
        $element['cat_title'] = strtoupper($element['cat_title']);
        $element['sec_title'] = htmlentities($element['sec_title']);
        return $element;
    },
    $data);
?>

If you're using PHP < 5.3 you'd have to put the function somewhere else as these anonymous functions are a 5.3 feature.

johannes
+1  A: 

You can do this with array_walk, it would be something like:

function cleanData( &$item, $key )
{
  $item['cat_title'] = strtoupper( $item['cat_title'] );
  $item['sec_title'] = htmlspecialchars( $item['sec_title'] );
}

array_walk( $arr, 'cleanData' );

However, functions like htmlspecialchars are really only intended for the very last moment when you're actually sending content to the browser. Before then, you want to work with the raw text and just have <?=htmlspecialchars($var)?> in your template/view file. Otherwise you can end up with encoding problems if you, for example, send that encoded data to a database, then retrieve it and run htmlspecialchars again.


UPDATE: Here's the code I used to test this; it works fine for me. I'm on PHP 5.2 but there isn't any difference in the function from version 4+.

$arr = array(
 array( 'title' => 'title 1', 'cat_title' => 'Drawings', 'sec_title' => 'Portfolio' ),
 array( 'title' => 'title 2', 'cat_title' => 'Paintings', 'sec_title' => 'Portfolio' ),
 array( 'title' => 'title 3', 'cat_title' => 'Drawings2', 'sec_title' => 'Portfolio' )
);


array_walk( $arr, 'cleanData' );
echo '<pre>', print_r($arr, true), '</pre>';

Outputs:

Array
(
 [0] => Array
  (
   [title] => title 1
   [cat_title] => DRAWINGS
   [sec_title] => Portfolio
  )

 [1] => Array
  (
   [title] => title 2
   [cat_title] => PAINTINGS
   [sec_title] => Portfolio
  )

 [2] => Array
  (
   [title] => title 3
   [cat_title] => DRAWINGS2
   [sec_title] => Portfolio
  )

)
DisgruntledGoat
Because the array is sorted numerically that will not work. That's why I have to have that for statement in "what i currently have going on".array_walk = PHP Warning: Wrong parameter count
This is the last step before the template. I have a lot of different utility functions like smarty, markdown, date functions etc that will only be applied when being sent to the template. output to forms gets different functions and input to database has different functions as well.I would prefer not to filter all of the functions in the tempaltes and keep it nicely in a class that can be reused and output.
It works for me...
DisgruntledGoat
Thanks for clarifying. I got it to work. I'm gonna have to play around with that function a little bit.
A: 

I suppose you could simply use array_keys, that at least would give you access to everything you want on a more basic level:

foreach( $holder as $subarr )
{
    $keys = array_keys( $subarr );
    foreach( $keys as $key )
    {
        switch( $key ):
        {
            case 'cat_title':
                $subarr[ $key ] = strtoupper( $subarr[ $key ] );
                break;
            default:                    
                $subarr[ $key ] = htmlspecialchars( $subarr[ $key ] );
        }
    }
}

Admittedly, this solution is a good deal more verbose than you need, but it will work.

Christopher W. Allen-Poole
Well it's a bit less verbose then that repetitive for and isset business. Thanks for the suggestion.
A: 

I would recommend a foreach-loop instead as it is slightly faster as you save the overhead for unnecessary function calls.

<?php
foreach ($array as &$item) {
  $item['cat_title'] = strtoupper($item['cat_title']);
  $item['sec_title'] = htmlentities($item['sec_title']);
}
?>