Doctrine ODM (MongoDB) - получить полный массив объекта? - PullRequest
5 голосов
/ 27 мая 2011

У меня возникла проблема с получением полного массива всеми данными встроенных дочерних коллекций и объектов) моего документа. Мой документ выглядит именно так:

use Doctrine\Common\Collections\ArrayCollection;

/** @Document(collection="user") */
class User {

/** @Id */
protected $id;

/** @String */
protected $firstname;

/** @String */
protected $lastname;

/** @EmbedMany(targetDocument="Email") */
protected $email;

/** @EmbedMany(targetDocument="Address") */
protected $address;

/** @EmbedMany(targetDocument="Subscription") */
protected $subscription;


/**
* Construct the user
*
* @param   array $properties
* @throws  User_Exception
*/
public function __construct(array $properties = array()) {

    $this->email = new ArrayCollection();
    $this->address = new ArrayCollection();
    $this->subscription = new ArrayCollection();

    foreach($properties as $name => $value){
        $this->{$name} = $value;
    }

}


...

Мне нужен полный массив встроенной коллекции для вывода всех данных и их рендеринга с помощью json . Мой запрос выглядит так:

$query = $this->_dbContainer->getDocumentManager()->createQueryBuilder('User')->field('deletedAt')->exists(false);                          
$result = $query->field('id')->equals($id)->getQuery()->getSingleResult();

Например, если я вызываю функцию toArray() следующим образом:

$array = $result->getSubscription()->toArray();
print_r($array);

Тогда вывод - это просто массив верхнего уровня:

[0] => Object Subscription...
[1] => Object Subscription...
...

Как я могу легко получить такой массив?

[0] => array('subscriptionLabel' => 'value1', 'field' => 'value1', ...)
[1] => array('subscriptionLabel' => 'value2', 'field' => 'value2', ...)
...

Существуют ли передовые практики или, возможно, отсутствуют некоторые вспомогательные сценарии для предотвращения чего-то уродливого, подобного этому коду (как обрабатывать child -> child -> child szenarios? Ugly -> ugly ugly -> ugly ugly ugly -> ...) :

$example = array();
foreach($result->getSubscription() as $key => $subscription) {
    $example[$key]['subscriptionLabel'] = $subscription->getSubscriptionLabel();
    $example[$key]['field'] = $subscription->getField();
    ...
}

Большое спасибо, Stephan

Ответы [ 4 ]

12 голосов
/ 28 мая 2011

Блин, простой ответ! Просто используйте -> гидрат (false) и все готово.

Для запросов поиска результаты по по умолчанию гидратированы, и вы получите объекты документа назад вместо массивы. Вы можете отключить это и получить необработанные результаты прямо из Монго с использованием гидрата (ложь) Метод:

<?php

$users = $dm->createQueryBuilder('User')
    ->hydrate(false)
    ->getQuery()
    ->execute();

print_r($users);
1 голос
/ 27 марта 2015

Недавно я столкнулся с этой же потребностью и решил ее, создав базовый класс для всех моих сущностей с помощью функции toArray () и JsonSerializable. Он также конвертирует все вложенные ссылки.

/**
 * @ODM\MappedSuperclass
 */
abstract class BaseDocument implements \JsonSerializable 
{
    public function jsonSerialize() {
        return $this->toArray();
    }

    public function toArray() {
        $getter_names = get_class_methods(get_class($this));
        $gettable_attributes = array();
        foreach ($getter_names as $key => $funcName) {
            if(substr($funcName, 0, 3) === 'get') {
                $propName = strtolower(substr($funcName, 3, 1));
                $propName .= substr($funcName, 4);
                $value = $this->$funcName();
                if (is_object($value) && get_class($value) == 'Doctrine\ODM\MongoDB\PersistentCollection') {
                    $values = array();
                    $collection = $value;
                    foreach ($collection as $obj) {
                        $values[] = $obj->toArray();
                    }
                    $gettable_attributes[$propName] = $values;
                }
                else {
                    $gettable_attributes[$propName] = $value;
                }
            }
        }
        return $gettable_attributes;
    }
}

Теперь я могу сериализовать сущность как массив или строку json с помощью json_encode ($ doc). Bam.

0 голосов
/ 03 января 2016

Только что сделал это немного более общим, отлично работает.Просто не забудьте расширить его своими документами и встраиваниями.

<?php
namespace App\Documents;

use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM;
use Doctrine\ODM\MongoDB\PersistentCollection;

/**
 * @ODM\MappedSuperclass
 */
abstract class BaseDocument implements \JsonSerializable
{
    /**
     * @return array
     */
    public function jsonSerialize()
    {
        return $this->toArray();
    }

    /**
     * @return array
     */
    public function toArray()
    {
        $getterNames = get_class_methods(get_class($this));
        $gettableAttributes = [];
        foreach ($getterNames as $funcName) {
            if (substr($funcName, 0, 3) !== 'get') {
                continue;
            }

            $propName = strtolower(substr($funcName, 3, 1));
            $propName .= substr($funcName, 4);
            $value = $this->$funcName();

            $gettableAttributes[$propName] = $value;


            if (is_object($value)) {
                if ($value instanceof PersistentCollection) {
                    $values = [];
                    $collection = $value;
                    foreach ($collection as $obj) {
                        /** @var BaseDocument $obj */
                        if ($obj instanceof \JsonSerializable) {
                            $values[] = $obj->toArray();
                        } else {
                            $values[] = $obj;
                        }
                    }
                    $gettableAttributes[$propName] = $values;
                } elseif ($value instanceof \JsonSerializable) {
                    /** @var BaseDocument $value */
                    $gettableAttributes[$propName] = $value->toArray();
                }
            }
        }

        return $gettableAttributes;
    }
}
0 голосов
/ 19 июля 2015

Танки к Rooster242, вы даже можете рекурсивно применять к массиву для встроенных документов, который сам расширяет BaseDocument, используя функцию php is_subclass_of :

/**
 * @ODM\MappedSuperclass
 */
abstract class BaseDocument implements \JsonSerializable 
{
    public function jsonSerialize() {
        return $this->toArray();
    }

    public function toArray() {
        $getter_names = get_class_methods(get_class($this));
        $gettable_attributes = array();
        foreach ($getter_names as $key => $funcName) {
            if(substr($funcName, 0, 3) === 'get') {
                $propName = strtolower(substr($funcName, 3, 1));
                $propName .= substr($funcName, 4);
                $value = $this->$funcName();
                if (is_object($value) && is_subclass_of($value,"BaseDocument")) {
                    $gettable_attributes[$propName] = $value->toArray();
                } elseif (is_object($value) && get_class($value) == 'Doctrine\ODM\MongoDB\PersistentCollection') {
                    $values = array();
                    $collection = $value;
                    foreach ($collection as $obj) {
                        if (is_subclass_of($obj,"BaseDocument")) {
                            $values[] = $obj->toArray();
                        } else {
                            $values[] = $obj;
                        }
                    }
                    $gettable_attributes[$propName] = $values;
                }
                else {
                    $gettable_attributes[$propName] = $value;
                }
            }
        }
        return $gettable_attributes;
    }
}
...