Рекурсивный as_array для отношений «один ко многим» с Kohana 3 ORM - PullRequest
1 голос
/ 11 июля 2011

Для начала я хотел бы сказать, что я знаю, как создавать некрасивые решения для моей проблемы. Я ищу хорошие решения и лучшие практики:)

Как создать глубокие иерархические массивы (позднее для json_encode) из объектов ORM Kohana 3, включая связанные объекты, где тип отношения один-ко-многим?

Проблема в том, что метод ORM-> as_array () работает рекурсивно для отношений "имеет один" и "принадлежит", но остановит и заставит вас использовать -> find_all () вручную, когда вы встретите "has" много "отношений.

Допустим, я создаю REST-сервер JSON API, используя Kohana 3 и встроенный ORM. Когда кто-то смотрит на этот URL: www.example.com/api/user?id=5 Им будет предоставлен объект JSON для пользователя, где id = 5.

Это orm-модели и отношения:

  • Пользователь принадлежит a Страна
  • Пользователь имеет много Сообщений .
  • Сообщение принадлежит a Категория

Я бы хотел, чтобы это работало:

echo json_encode(
ORM::factory('user', 5)
->with('country')
->with('messages')
->with('messages:category')
->find()
->as_array()
);

и выдайте мне вывод следующим образом:

{
    name: "John"
    age: 54,
    country_id: 5,
    country: {
        name: 'Sweden',
        code: 'SE'
    },
    messages: {
        {
            content: 'Lorem ipsum dolor...',
            category_id: 1,
            category: {...}
        },
        {
            content: 'Sit amet elit...',
            category_id: 2,
            category: {...}
        },
        {
            content: 'Consectetur ipsum dolor...',
            category_id: 3,
            category: {...}
        }
    }
}

НО ЧТО НЕ РАБОТАЕТ. Это все, что вы получите:

{
    name: "John"
    age: 54,
    country_id: 5,
    country: {
        name: 'Sweden',
        code: 'SE'
    }
}

Кто-то разветвлял или расширял ORM Kohana 3 для поддержки такого рода функций?
Кто-нибудь знает какой-нибудь хороший модуль API Kohana 3, который как-то решает эту проблему для вас?

1 Ответ

0 голосов
/ 30 декабря 2013

Насколько я знаю, нет способа сделать это, используя только ORM.Это имеет место по двум причинам:

  1. Если message имеет отношение для category, это обычно означает, что category имеет соответствующее отношение для messages вкатегория.Если вы хотите получить message «полностью» - т.е. включая его категорию - допустим, вы также хотите получить category «полностью» - т.е. включая его сообщения.Это, очевидно, очень плохая идея, так как вы можете очень легко превратить себя в бесконечный цикл.Другими словами, если бы существовала волшебная способность «рекурсировать все отношения», как бы она узнала, когда прекратить рекурсивный процесс?

  2. Все, что ORM делает за этимсцены, когда вы вызываете find(), создают запрос SQL, который возвращает строку данных из базы данных.Однако то, что вы пытаетесь сделать, слишком сложно для одного запроса, который возвращает одну строку.(Существует способ извлечь несколько строк в виде одной строки со значениями, разделенными запятыми в каждом поле, используя MySQL's GROUP_CONCAT function , но я гарантирую, что это не стоит проблем.)

По обеим этим причинам метод ORM with() работает только на belongs_to (в вашем случае user country и message * category).

Один из способов сделать этот запрос - разбить его на три этапа, например:

// Step 1: Get the user
$user = ORM::factory('user', 5)
    ->with('country')
    ->find();

// Step 2: Get the messages
$user->messages
    ->with('category')
    ->find_all();

// Step 3: Make user and the messages into arrays.
// User is easy, but messages are a little harder
// because they need to turn
//     from "an object containing an array of objects"
//     into "an array of arrays."
$user_arr = $user->as_array();
$fixer = function($obj)
{
    return $obj->as_array();
};
$user_arr['messages'] = array_map($fixer, $user->messages->as_array());

// Now you can output it
echo json_encode($user_arr);
...