Невозможно сгенерировать HalResource для объекта типа ArrayObject

У меня есть некоторые проблемы с возвратом объекта paginator в виде коллекции HAL json. Я использую последние версии zend-expressive и zend-expressive-hal.
Это настройка из моего ConfigProvider:

public function __invoke() : array
{
    return [
        'dependencies' => $this->getDependencies(),
        MetadataMap::class => $this->getHalConfig(),
    ];
}

public function getHalConfig() : array
{
    return [
        [
            '__class__' => RouteBasedCollectionMetadata::class,
            'collection_class' => RoleCollection::class,
            'collection_relation' => 'user_roles',
            'route' => 'api.user.roles',
        ],
    ];
}

И это мои методы обработчика:

public function get(ServerRequestInterface $request) : ResponseInterface
{
    // read some records from the database
    $select = new Select();
    $select->from(['r' => 'user_roles']);
    $select->columns(['id', 'name']);

    $paginator = new RoleCollection(new DbSelect($select, $this->dbAdapter));
    $paginator->setItemCountPerPage(25);
    $paginator->setCurrentPageNumber(1);

    return $this->createResponse($request, $paginator);
}

private function createResponse(ServerRequestInterface $request, $instance) : ResponseInterface
{
    return $this->responseFactory->createResponse(
        $request,
        $this->resourceGenerator->fromObject($instance, $request)
    );
}

Класс RoleCollection является только наследником Paginator:

class RoleCollection extends Paginator
{
}

Сообщение об ошибке, которое я получаю:

Cannot generate Zend\Expressive\Hal\HalResource for object of type ArrayObject; not in metadata map

person altralaser    schedule 04.07.2019    source источник


Ответы (1)


Я думаю, вам не хватает метаданных для самого объекта роли.

Например, это что-то похожее для моего объекта сообщений:

MetadataMap::class => [
    [
        '__class__'           => RouteBasedCollectionMetadata::class,
        'collection_class'    => Posts::class,
        'collection_relation' => 'posts',
        'route'               => 'api.posts',
    ],
    [
        '__class__'      => RouteBasedResourceMetadata::class,
        'resource_class' => Post::class,
        'route'          => 'api.posts.view',
        'extractor'      => ArraySerializable::class,
    ],
],

Вы описали только коллекцию, а класс ресурсов отсутствует для одной роли.

Я также вижу, что генератор ресурсов пытается разобрать ArrayObject. Это должно быть заключено в объект Role, который вы можете добавить в MetadataMap.

Где в вашем коде что-то идет не так, это строка:

$paginator = new RoleCollection(new DbSelect($select, $this->dbAdapter));

Это добавляет результат запроса в пагинатор, но пагинатор не знает, как с ним обращаться. Если я правильно помню, DbSelect возвращает ResultSet. Я предполагаю, что именно отсюда исходит ArrayObject. Что вам, вероятно, нужно, так это переопределить этот ResultSet и убедиться, что он возвращает массив объектов Role. Вы можете изучить адаптер dbselect и набор результатов увлажнения.

Когда у вас есть объект Role в пагинаторе, вы можете описать его в метаданных.

[
    '__class__'      => RouteBasedResourceMetadata::class,
    'resource_class' => UserRole::class,
    'route'          => 'api.roles',
    'extractor'      => ...,
],

Я сам использую доктрину с hal, поэтому zend-db выходит за рамки моей компетенции. Если вам нужна дополнительная помощь, я предлагаю посетить форумы zf.

person xtreamwayz    schedule 09.07.2019
comment
К сожалению, это не работает. Вы также определили ресурс для маршрута, отличного от коллекции. Вероятно, это означает, что вы хотите получить одну запись и один раз список. Я думаю, моя проблема в том, что метод getCurrentItems() вызывается для объекта Paginator, который, конечно же, возвращает ArrayObject. Может быть, zend-paginator и expressive-hal несовместимы, я не знаю. - person altralaser; 14.07.2019
comment
zend-paginator и холл определенно работают вместе. У меня это работает. И да, маршрут с одним ресурсом отличается от маршрута сбора. В вашем случае коллекция может быть чем-то вроде /api/users/{user_id}/roles, а маршрут ресурсов ролей может выглядеть как /api/roles/{role_id}. Что не так, так это то, что вы вводите свои роли в качестве стандартных классов в коллекцию прямо из запроса. Я обновлю свой ответ. - person xtreamwayz; 15.07.2019
comment
Что касается разных маршрутов, я не уверен, что вы можете просто пропустить маршрут для ресурса. Вся причина использования HAL заключается в добавлении маршрутов к ресурсам и коллекциям. Но я видел разные классы метаданных, так что, возможно, есть что-то вроде класса NonRouteResourceMetadata. - person xtreamwayz; 15.07.2019