Yii Framework Forum: Convert Model With Relations To Php Array And Json - Yii Framework Forum

Jump to content

Page 1 of 1
  • You cannot start a new topic
  • You cannot reply to this topic

Convert Model With Relations To Php Array And Json A function for convert model to array. Rate Topic: ***** 2 Votes

#1 User is offline   farhad2161 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 6
  • Joined: 01-April 13

Posted 02 April 2013 - 10:41 AM

A function for convert model to array.
This function convert a model with all relations data to array.
You can use the result of this function in CJSON::encode() to get json result in client side.

    public function convertModelToArray($models) {
        if (is_array($models))
            $arrayMode = TRUE;
        else {
            $models = array($models);
            $arrayMode = FALSE;
        }

        $result = array();
        foreach ($models as $model) {
            $attributes = $model->getAttributes();
            $relations = array();
            foreach ($model->relations() as $key => $related) {
                if ($model->hasRelated($key)) {
                    $relations[$key] = convertModelToArray($model->$key);
                }
            }
            $all = array_merge($attributes, $relations);

            if ($arrayMode)
                array_push($result, $all);
            else
                $result = $all;
        }
        return $result;
    }


and use it like

public function actionComment() {
$db = Comment::model()->with('user')->findAll();
echo CJSON::encode(convertModelToArray($db));
}

2

#2 User is offline   Abhishek Shah 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 90
  • Joined: 20-July 12
  • Location:New Jersey,USA

Posted 03 April 2013 - 12:43 AM

Nice job!Appreciated.
Feel free to ask for help,
Abhishek.
Freelancer.
Yii Basic Gii With Export Pdf Excel
0

#3 User is offline   mirunho 

  • Standard Member
  • PipPip
  • Yii
  • Group: Members
  • Posts: 170
  • Joined: 19-December 12
  • Location:Gdansk, Poland

Posted 03 April 2013 - 01:17 AM

really nice, thanks!
0

#4 User is offline   dhanakumar 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 25
  • Joined: 26-December 12
  • Location:Coimbatore,Tamilnadu

Posted 02 June 2013 - 11:40 PM

Nice work .. keep up all your good work ..
-
Dhana.M
0

#5 User is offline   farhad2161 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 6
  • Joined: 01-April 13

Posted 11 July 2013 - 03:26 AM

And if you need to filter attributes in your array you can use this :

    public static function convertModelToArray($models, array $filterAttributes = null) {
        if (is_array($models))
            $arrayMode = TRUE;
        else {
            $models = array($models);
            $arrayMode = FALSE;
        }

        $result = array();
        foreach ($models as $model) {
            $attributes = $model->getAttributes();

            if (isset($filterAttributes) && is_array($filterAttributes)) {
                foreach ($filterAttributes as $key => $value) {

                    if (strtolower($key) == strtolower($model->tableName()) && strpos($value, '*') === FALSE) {
                        $value = str_replace(' ', '', $value);
                        $arrColumn = explode(",", $value);

                        foreach ($attributes as $key => $value)
                            if (!in_array($key, $arrColumn))
                                unset($attributes[$key]);
                    }
                }
            }

            $relations = array();
            foreach ($model->relations() as $key => $related) {
                if ($model->hasRelated($key)) {
                    $relations[$key] = self::convertModelToArray($model->$key, $filterAttributes);
                }
            }
            $all = array_merge($attributes, $relations);

            if ($arrayMode)
                array_push($result, $all);
            else
                $result = $all;
        }
        return $result;
    }


and use it like

public function actionComment() {
$db = Comment::model()->with('user','message')->findAll();
echo CJSON::encode(convertModelToArray($db,array('user'=>'id,firstname','message'=>'*')));
}

0

#6 User is offline   lucianocn 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 31
  • Joined: 06-October 12

Posted 21 December 2013 - 04:33 PM

View Postfarhad2161, on 11 July 2013 - 03:26 AM, said:

And if you need to filter attributes in your array you can use this :

    public static function convertModelToArray($models, array $filterAttributes = null) {
        if (is_array($models))
            $arrayMode = TRUE;
        else {
            $models = array($models);
            $arrayMode = FALSE;
        }

        $result = array();
        foreach ($models as $model) {
            $attributes = $model->getAttributes();

            if (isset($filterAttributes) && is_array($filterAttributes)) {
                foreach ($filterAttributes as $key => $value) {

                    if (strtolower($key) == strtolower($model->tableName()) && strpos($value, '*') === FALSE) {
                        $value = str_replace(' ', '', $value);
                        $arrColumn = explode(",", $value);

                        foreach ($attributes as $key => $value)
                            if (!in_array($key, $arrColumn))
                                unset($attributes[$key]);
                    }
                }
            }

            $relations = array();
            foreach ($model->relations() as $key => $related) {
                if ($model->hasRelated($key)) {
                    $relations[$key] = self::convertModelToArray($model->$key, $filterAttributes);
                }
            }
            $all = array_merge($attributes, $relations);

            if ($arrayMode)
                array_push($result, $all);
            else
                $result = $all;
        }
        return $result;
    }


and use it like

public function actionComment() {
$db = Comment::model()->with('user','message')->findAll();
echo CJSON::encode(convertModelToArray($db,array('user'=>'id,firstname','message'=>'*')));
}



Hi farhad2161,
Your code works well, but the filter is not working with HAS_MANY relation.

I had the same problem with CarJSON (http://www.yiiframew...ension-problem/).

Any idea?
0

#7 User is offline   farhad2161 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 6
  • Joined: 01-April 13

Posted 22 December 2013 - 10:25 AM

View Postlucianocn, on 21 December 2013 - 04:33 PM, said:

Hi farhad2161,
Your code works well, but the filter is not working with HAS_MANY relation.

I had the same problem with CarJSON (http://www.yiiframew...ension-problem/).

Any idea?


Hi
Please try this one:

    /**
     * Converting a Yii model with all relations to a an array.
     * @param mixed $models A single model or an array of models for converting to array.
     * @param array $filterAttributes should be like array('table name'=>'column names','user'=>'id,firstname,lastname'
     * 'comment'=>'*') to filter attributes.
     * @return array array of converted model with all related relations.
     */
    public static function convertModelToArray($models, array $filterAttributes = null) {
        if (is_array($models))
            $arrayMode = TRUE;
        else {
            $models = array($models);
            $arrayMode = FALSE;
        }

        $result = array();
        foreach ($models as $model) {
            $attributes = $model->getAttributes();

            if (isset($filterAttributes) && is_array($filterAttributes)) {
                foreach ($filterAttributes as $key => $value) {

                    if (strtolower($key) == strtolower($model->tableName())) {
                        $value = str_replace(' ', '', $value);
                        $arrColumn = explode(",", $value);

                        if (strpos($value, '*') === FALSE) {
                            $attributes = array();
                        }

                        foreach ($arrColumn as $column) {
                            if ($column != '*') {
                                $attributes[$column] = $model->$column;
                            }
                        }
                        //foreach ($attributes as $key => $value) {
                        //if (!in_array($key, $arrColumn))
                        //unset($attributes[$key]);
                        //}
                    }
                }
            }

            $relations = array();
            foreach ($model->relations() as $key => $related) {
                if ($model->hasRelated($key)) {
                    $relations[$key] = self::convertModelToArray($model->$key, $filterAttributes);
                }
            }
            $all = array_merge($attributes, $relations);

            if ($arrayMode)
                array_push($result, $all);
            else
                $result = $all;
        }
        return $result;
    }

0

#8 User is offline   lucianocn 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 31
  • Joined: 06-October 12

Posted 23 December 2013 - 04:55 PM

View Postfarhad2161, on 22 December 2013 - 10:25 AM, said:

Hi
Please try this one:

 ...




Hi farhad2161,
The filter still not working with HAS_MANY relations, only with others.
I'm working on an example to demonstrate.


Thanks!
0

#9 User is offline   Paul_G 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 1
  • Joined: 19-December 13

Posted 07 January 2014 - 12:00 AM

This code does not work with a STAT type of relation. Any solutions for this?

'lastCookDate' => array(self::STAT,
'Lunchchefs',
'user_id',
'select' => 'MAX(lunchevents.date)',
'join' => 'INNER JOIN lunchevents ON t.lunch_id = lunchevents.lunch_id'),

Thanks!
Paul
0

#10 User is offline   silentneedle 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 7
  • Joined: 06-November 13

Posted 23 January 2014 - 08:28 AM

Doesn't work if one join results with NULL.
0

#11 User is offline   cnlevy 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 3
  • Joined: 14-October 12

Posted 13 February 2014 - 07:03 PM

Try jsonize extension (www.yiiframework.com/extension/jsonize), it might handle your case

View PostPaul_G, on 07 January 2014 - 12:00 AM, said:

This code does not work with a STAT type of relation. Any solutions for this?

'lastCookDate' => array(self::STAT,
'Lunchchefs',
'user_id',
'select' => 'MAX(lunchevents.date)',
'join' => 'INNER JOIN lunchevents ON t.lunch_id = lunchevents.lunch_id'),

Thanks!
Paul

0

#12 User is offline   Chopin 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 4
  • Joined: 01-April 12

Posted 10 April 2014 - 09:13 PM

View Postsilentneedle, on 23 January 2014 - 08:28 AM, said:

Doesn't work if one join results with NULL.


I fixed this bug and also add a parameter to let you exclude some relations when convert to array.
try this one:
<?php


/**
 * Description of JSONUtil
 *
 * @author 
 */
class JSONUtil {
     /**
     * Converting a Yii model with all relations to a an array.
     * @param mixed $models A single model or an array of models for converting to array.
     * @param array $filterAttributes should be like array('table name'=>'column names','user'=>'id,firstname,lastname'
     * 'comment'=>'*') to filter attributes.
     * @param array $ignoreRelations an array contains the model names in relations that will not be converted to array
     * @return array array of converted model with all related relations.
     */
    public static function convertModelToArray($models, array $filterAttributes = null,array $ignoreRelations=array()) {
        if((!is_array($models))&&(is_null($models))) return null;

        if (is_array($models))
            $arrayMode = TRUE;
        else {
            $models = array($models);
            $arrayMode = FALSE;
        }

        $result = array();
        foreach ($models as $model) {
            $attributes = $model->getAttributes();

            if (isset($filterAttributes) && is_array($filterAttributes)) {
                foreach ($filterAttributes as $key => $value) {

                    if (strtolower($key) == strtolower($model->tableName())) {
                        $value = str_replace(' ', '', $value);
                        $arrColumn = explode(",", $value);

                        if (strpos($value, '*') === FALSE) {
                            $attributes = array();
                        }

                        foreach ($arrColumn as $column) {
                            if (($column!='')&&($column != '*')) {
                                $attributes[$column] = $model->$column;
                            }
                        }
                        //foreach ($attributes as $key => $value) {
                        //if (!in_array($key, $arrColumn))
                        //unset($attributes[$key]);
                        //}
                    }
                }
            }

            $relations = array();
            $key_ignores = array();

            if($modelClass = get_class($model)){
                if(array_key_exists($modelClass,$ignoreRelations)){
                    $key_ignores = explode(',',$ignoreRelations[$modelClass]);
                }
            }

            foreach ($model->relations() as $key => $related) {

                if ($model->hasRelated($key)) {
                    if(!in_array($key,$key_ignores))
                            $relations[$key] = self::convertModelToArray($model->$key, $filterAttributes,$ignoreRelations);
                }
            }
            $all = array_merge($attributes, $relations);

            if ($arrayMode)
                array_push($result, $all);
            else
                $result = $all;
        }
        return $result;
    }
}

0

#13 User is offline   farhad2161 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 6
  • Joined: 01-April 13

Posted 11 April 2014 - 12:14 AM

View PostChopin, on 10 April 2014 - 09:13 PM, said:

I fixed this bug and also add a parameter to let you exclude some relations when convert to array.
try this one:


Nice
0

#14 User is offline   zone66x 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 2
  • Joined: 10-September 11

Posted 08 May 2014 - 10:26 AM

Great function. I also needed the column names of the output to differ from the actual database ones so I extended the function to support aliases using the $filterAttributes argument. It works just like aliases in SQL. For example if $filterAttributes = array('user' => 'n AS name') would result in 'name' being the key in the returned array rather than 'n'.

<?php
/**
 * Description of JSONUtil
 *
 * @link http://www.yiiframework.com/forum/index.php/topic/41922-convert-model-with-relations-to-php-array-and-json/
 * @author
 */
class JSONUtil {
     /**
     * Converting a Yii model with all relations to a an array.
     * @param mixed $models A single model or an array of models for converting to array.
     * @param array $filterAttributes should be like array('table name'=>'column names','user'=>'id,firstname,lastname'
     * 'comment'=>'*') to filter attributes. Also can use alias for column names by using AS with the column name just
     * like in SQL.
     * @param array $ignoreRelations an array contains the model names in relations that will not be converted to array
     * @return array array of converted model with all related relations.
     */
    public static function convertModelToArray($models, array $filterAttributes = null,array $ignoreRelations=array())
    {
        if((!is_array($models))&&(is_null($models))) return null;

        if (is_array($models))
            $arrayMode = TRUE;
        else {
            $models = array($models);
            $arrayMode = FALSE;
        }

        $result = array();
        foreach ($models as $model) {
            $attributes = $model->getAttributes();

            if (isset($filterAttributes) && is_array($filterAttributes)) {
                foreach ($filterAttributes as $key => $value) {

                    if (strtolower($key) == strtolower($model->tableName())) {
                        $arrColumn = explode(",", $value);

                        if (strpos($value, '*') === FALSE) {
                            $attributes = array();
                        }

                        foreach ($arrColumn as $column)
                        {
                            $columnNameAlias = array_map('trim', preg_split("/[aA][sS]/", $column));

                            $columnName = '';
                            $columnAlias = '';

                            if(count($columnNameAlias) === 2)
                            {
                                $columnName = $columnNameAlias[0];
                                $columnAlias = $columnNameAlias[1];
                            }

                            else
                            {
                                $columnName = $columnNameAlias[0];
                            }

                            if(($columnName != '') && ($column != '*'))
                            {
                                if($columnAlias !== '')
                                {
                                    $attributes[$columnAlias] = $model->$columnName;
                                }

                                else
                                {
                                    $attributes[$columnName] = $model->$columnName;
                                }
                            }
                        }
                    }
                }
            }

            $relations = array();
            $key_ignores = array();

            if($modelClass = get_class($model)){
                if(array_key_exists($modelClass,$ignoreRelations)){
                    $key_ignores = explode(',',$ignoreRelations[$modelClass]);
                }
            }

            foreach ($model->relations() as $key => $related) {

                if ($model->hasRelated($key)) {
                    if(!in_array($key,$key_ignores))
                            $relations[$key] = self::convertModelToArray($model->$key, $filterAttributes,$ignoreRelations);
                }
            }
            $all = array_merge($attributes, $relations);

            if ($arrayMode)
                array_push($result, $all);
            else
                $result = $all;
        }
        return $result;
    }
}

0

#15 User is offline   DerekC 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 44
  • Joined: 09-December 09
  • Location:Europe

Posted 19 August 2014 - 01:13 AM

There is a little gotcha in the filterAttributes variable:

Make sure you use the table name of the relation - not the relation name.
So, for
HAS_ONE approver => 'User'
you need to the "{{user}}" as the key like this:


$models = Post::model()->with( array('owner','approver') )->findAll();
$ret = $this->convertModelToArray( $models, array(
	'{{user}}'=>'id,username',
);

0

#16 User is offline   pethee 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 11
  • Joined: 23-December 13

Posted 22 August 2014 - 04:20 AM

View Postcnlevy, on 13 February 2014 - 07:03 PM, said:

Try jsonize extension (www.yiiframework.com/extension/jsonize), it might handle your case


It's an ugly one, but rather than complicating it and setting up different virtual attributes, include them in a fuzzy way in the result of ->getAttributes() I chose to amend the code with a small if checking specifically for the STAT relation:

public function convertModelToArray($models) {
        if (is_array($models))
            $arrayMode = TRUE;
        else {
            $models = array($models);
            $arrayMode = FALSE;
        }

        $result = array();
        foreach ($models as $model) {
            $attributes = $model->getAttributes();
            $relations = array();     
            foreach ($model->relations() as $key => $related) {
                if ($model->hasRelated($key)) {
                    if ($related[0] == "CStatRelation")
                        $relations[$key] = $model->$key;
                    else
                        $relations[$key] = $this->convertModelToArray($model->$key);
                }
            }
            $all = array_merge(array_filter($attributes,'count'), array_filter($relations,'count'));

            if ($arrayMode)
                array_push($result, $all);
            else
                $result = $all;
        }
        return $result;
    }


Btw I also use array_filter with the callback of 'count' to check not include the fields that are "" or NULL but leave and include the '0' (zero int).
0

#17 User is offline   kapous 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 10
  • Joined: 31-March 14
  • Location:USA

Posted 31 March 2015 - 06:03 AM

Very useful ....Thank you
0

Share this topic:


Page 1 of 1
  • You cannot start a new topic
  • You cannot reply to this topic

1 User(s) are reading this topic
0 members, 1 guests, 0 anonymous users