We have moved our forum to GitHub Discussions. For questions about Phalcon v3/v4/v5 you can visit here and for Phalcon v6 here.

Getting all children, grandchildren etc from Model with hasMany relationships

Hi. I'm trying to write a json api. I want to send all the children, grandchildren and so on, along with the parent record.

If I use the following code the json output only contains the parent (Customer) record, but I want to include all the customer's orders, all the products on the order, and all the parts needed to make the product.

// Customer hasMany Order
// Order hasMany Product
// Product hasMany Part

$customer = Customer::findFirst($id);
echo json_encode($customer);

// Only outputs the parent (Customer) record

Is there an easy way to get all the children many levels deep? (without manually building arrays with foreach loops).

Thanks

Hi,

use the https://docs.phalcon.io/en/latest/api/Phalcon_Mvc_Model_ManagerInterface.html Model Manager and get all relations using the getHasOneAndHasMany() method to have all relations, than loop on this relation and use the $customer->getRelated() method to get value.

Could you please give an example on how to use the getHasOneAndHasMany() in a model or in a controller?



26.3k

I have the same problem as matt-sharp. There is another topic with link to yours here https://forum.phalcon.io/discussion/2104/related-records-automatically-including

Please write what do you think about the solution I have wrote. Or maybe you have already found the solution? TIA!



3.5k

anyone got a solution they could share for this one?

edited Nov '14

hello,

i've got a method quite heavy in code, but working ;-)

here is a list of relations attached in my model (it's a member data)


    /**
     * Merge array
     *
     * @param string $key key
     * @param array  $in  in
     * @param array  $add add
     *
     * @return array
     */
    protected function mergeArray($key, array $in, array $add)
    {
        return array_merge($in, $add);
    }
    /**
     * Add child
     *
     * @param string $key key
     * @param array  $in  in
     * @param array  $add add
     *
     * @return array
     */
    protected function addChild($key, array $in, array $add)
    {
        $in[$key] = $add;
        return $in;
    }
    /**
     * Add children
     *
     * @param string $key      key
     * @param array  $in       in
     * @param object $objects  object
     * @param array  $arrayKey arrayKey
     *
     * @return array
     */
    protected function addChildren($key, array $in, $objects, $arrayKey = null)
    {
        $in[$key] = array();
        foreach ($objects as $object) {
            if ($arrayKey) {
                $in[$key][$object->$arrayKey] = $object->toArray();
            } else {
                $in[$key][] = $object->toArray();
            }
        }
        return $in;
    }

    /**
     * Model object to json
     *
     * @param array $params params
     *
     * @return array
     */
    public function toJson(array $params = [])
    {
        $modelObject = $this->toArray();
        foreach (static::$toJsonRelations as $related => $relation) {
            $modelRelated = $this->getRelated(\Phalcon\Text::camelize($related));
            if ($modelRelated) {
                $modelObject = $this->$relation($related, $modelObject, $modelRelated->toArray());
            }
        }
        $refClass = new \ReflectionClass($this);
        return [
            strtolower($refClass->getShortName()) => $modelObject
        ];
    }

and initialize your model with this "relations data" :

    /**
     * Relation types
     *
     * @var array
    */
    public static $toJsonRelations = [
        'part' => 'addChildren',
        'product' => 'addChildren',
        'order' => 'addChildren', // can be mergeArray | addChild | addChildren depending on the relation ( 1<->1 | N->1 | 1->N)
    ];

when you'll execute

$customer = Customer::findFirst($id);
echo json_encode($customer->toJson());

you'll have all data you want attached