Trying to extract a collection of objects where one contains a NULL value, works fine for JSON, but when trying to output XML generates:
Encountered non-primitive type "NULL" when serializing Zend\Expressive\Hal\HalResource instance; unable to serialize
Code to reproduce the issue
ConfigProvider.php
namespace App;
class ConfigProvider
{
/**
* Get configuration
*
* @return array
*/
public function __invoke(): array
{
return [
'dependencies' => [
'factories' => [
TestPageHandler::class => TestPageHandlerFactory::class,
],
],
MetadataMap::class => [
[
'__class__' => RouteBasedResourceMetadata::class,
'resource_class' => TestEntity::class,
'route' => 'test',
'extractor' => Reflection::class,
],
[
'__class__' => RouteBasedCollectionMetadata::class,
'collection_class' => TestCollection::class,
'collection_relation' => 'test',
'route' => 'tests',
],
],
'routes' => [
'tests' => [
'path' => '/test',
'middleware' => TestPageHandler::class,
'allowed_methods' => ['GET'],
],
'test' => [
'path' => '/test/:id',
'middleware' => TestPageHandler::class,
'allowed_methods' => ['GET'],
],
],
];
}
}
TestEntity.php
namespace App;
class TestEntity
{
/**
* @var int
*/
protected $id;
/**
* @var string
*/
protected $name;
/**
* @var string|null
*/
protected $description;
/**
* Get id
*
* @return int
*/
public function getId(): int
{
return $this->id;
}
/**
* Set id
*
* @param int $id
*
* @return void
*/
public function setId(int $id): void
{
$this->id = $id;
}
/**
* Get name
*
* @return string
*/
public function getName(): string
{
return $this->name;
}
/**
* Set name
*
* @param string $name
*
* @return void
*/
public function setName(string $name): void
{
$this->name = $name;
}
/**
* Get description
*
* @return null|string
*/
public function getDescription(): ?string
{
return $this->description;
}
/**
* Set description
*
* @param null|string $description
*
* @return void
*/
public function setDescription(?string $description): void
{
$this->description = $description;
}
}
TestPageCollection.php
namespace App;
use Zend\Paginator\Paginator;
class TestCollection extends Paginator
{
}
TestPageHandler.php
namespace App;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Zend\Expressive\Hal\HalResponseFactory;
use Zend\Expressive\Hal\ResourceGenerator;
use Zend\Paginator\Adapter\ArrayAdapter;
class TestPageHandler implements RequestHandlerInterface
{
/**
* @var ResourceGenerator
*/
protected $resourceGenerator;
/**
* @var HalResponseFactory
*/
protected $responseFactory;
/**
* @var TestEntity[]
*/
protected $testEntities;
/**
* Constructor
*
* @param ResourceGenerator $resourceGenerator
* @param HalResponseFactory $responseFactory
*/
public function __construct(ResourceGenerator $resourceGenerator, HalResponseFactory $responseFactory)
{
$this->resourceGenerator = $resourceGenerator;
$this->responseFactory = $responseFactory;
}
/**
* @inheritdoc
*/
public function handle(ServerRequestInterface $request): ResponseInterface
{
$this->generateTestEntities();
$id = $request->getAttribute('id', false);
if ($id) {
$resource = $this->getTestEntity($id);
} else {
$resource = $this->getAllTestEntities();
}
return $this->responseFactory->createResponse($request,
$this->resourceGenerator->fromObject($resource, $request));
}
/**
* Get test entity
*
* @param $id
*
* @return TestEntity
*/
public function getTestEntity(int $id): TestEntity
{
return $this->testEntities[$id];
}
/**
* Get all test entities
*
* @return TestCollection
*/
public function getAllTestEntities(): TestCollection
{
return new TestCollection(new ArrayAdapter($this->testEntities));
}
/**
* Generate test entities
*
* @return void
*/
public function generateTestEntities(): void
{
$this->testEntities = [];
foreach (range(1, 10) as $id) {
$entity = new TestEntity;
$entity->setId($id);
$entity->setName('test' . $id);
$this->testEntities[$id] = $entity;
}
}
}
TestPageHandlerFactory.php
namespace App;
use Interop\Container\ContainerInterface;
use Zend\Expressive\Hal\HalResponseFactory;
use Zend\Expressive\Hal\ResourceGenerator;
use Zend\ServiceManager\Factory\FactoryInterface;
class TestPageHandlerFactory implements FactoryInterface
{
/**
* @inheritdoc
*/
public function __invoke(ContainerInterface $container, $requestedName, array $options = null): TestPageHandler
{
return new $requestedName(
$container->get(ResourceGenerator::class),
$container->get(HalResponseFactory::class)
);
}
}
Expected results
Valid JSON representing the collection when doing a GET on /test using JSON content negotiation.
Valid XML representing the collection when doing a GET on /test using XML content negotiation.
Actual results
Valid JSON representing the collection when doing a GET on /test using JSON content negotiation.
{
"_total_items": 10,
"_page": 1,
"_page_count": 1,
"_links": {
"self": {
"href": "http://localhost/test?page=1"
}
},
"_embedded": {
"test": [
{
"id": 1,
"name": "test1",
"description": null,
"_links": {
"self": {
"href": "http://localhost/test/1"
}
}
},
{
"id": 2,
"name": "test2",
"description": null,
"_links": {
"self": {
"href": "http://localhost/test/2"
}
}
},
{
"id": 3,
"name": "test3",
"description": null,
"_links": {
"self": {
"href": "http://localhost/test/3"
}
}
},
{
"id": 4,
"name": "test4",
"description": null,
"_links": {
"self": {
"href": "http://localhost/test/4"
}
}
},
{
"id": 5,
"name": "test5",
"description": null,
"_links": {
"self": {
"href": "http://localhost/test/5"
}
}
},
{
"id": 6,
"name": "test6",
"description": null,
"_links": {
"self": {
"href": "http://localhost/test/6"
}
}
},
{
"id": 7,
"name": "test7",
"description": null,
"_links": {
"self": {
"href": "http://localhost/test/7"
}
}
},
{
"id": 8,
"name": "test8",
"description": null,
"_links": {
"self": {
"href": "http://localhost/test/8"
}
}
},
{
"id": 9,
"name": "test9",
"description": null,
"_links": {
"self": {
"href": "http://localhost/test/9"
}
}
},
{
"id": 10,
"name": "test10",
"description": null,
"_links": {
"self": {
"href": "http://localhost/test/10"
}
}
}
]
}
}
When doing a GET on /test using XML content negotiation, the following error is thrown:
Zend\Expressive\Hal\Exception\InvalidResourceValueException thrown with message "Encountered non-primitive type "NULL" when serializing Zend\Expressive\Hal\HalResource instance; unable to serialize"
Stacktrace:
#42 Zend\Expressive\Hal\Exception\InvalidResourceValueException in /var/www/vendor/zendframework/zend-expressive-hal/src/Exception/InvalidResourceValueException.php:22
#41 Zend\Expressive\Hal\Exception\InvalidResourceValueException:fromValue in /var/www/vendor/zendframework/zend-expressive-hal/src/Renderer/XmlRenderer.php:129
#40 Zend\Expressive\Hal\Renderer\XmlRenderer:createResourceElement in /var/www/vendor/zendframework/zend-expressive-hal/src/Renderer/XmlRenderer.php:146
#39 Zend\Expressive\Hal\Renderer\XmlRenderer:createNodeTree in /var/www/vendor/zendframework/zend-expressive-hal/src/Renderer/XmlRenderer.php:78
#38 Zend\Expressive\Hal\Renderer\XmlRenderer:createResourceNode in /var/www/vendor/zendframework/zend-expressive-hal/src/Renderer/XmlRenderer.php:73
#37 Zend\Expressive\Hal\Renderer\XmlRenderer:createResourceNode in /var/www/vendor/zendframework/zend-expressive-hal/src/Renderer/XmlRenderer.php:29
#36 Zend\Expressive\Hal\Renderer\XmlRenderer:render in /var/www/vendor/zendframework/zend-expressive-hal/src/HalResponseFactory.php:78
#35 Zend\Expressive\Hal\HalResponseFactory:createResponse in /var/www/src/App/src/Handler/TestPageHandler.php:46
#34 App\Handler\TestPageHandler:handle in /var/www/vendor/zendframework/zend-stratigility/src/Middleware/RequestHandlerMiddleware.php:53
#33 Zend\Stratigility\Middleware\RequestHandlerMiddleware:process in /var/www/vendor/zendframework/zend-expressive/src/Middleware/LazyLoadingMiddleware.php:46
#32 Zend\Expressive\Middleware\LazyLoadingMiddleware:process in /var/www/vendor/zendframework/zend-expressive-router/src/Route.php:100
#31 Zend\Expressive\Router\Route:process in /var/www/vendor/zendframework/zend-expressive-router/src/RouteResult.php:110
#30 Zend\Expressive\Router\RouteResult:process in /var/www/vendor/zendframework/zend-expressive-router/src/Middleware/DispatchMiddleware.php:35
#29 Zend\Expressive\Router\Middleware\DispatchMiddleware:process in /var/www/vendor/zendframework/zend-expressive/src/Middleware/LazyLoadingMiddleware.php:46
#28 Zend\Expressive\Middleware\LazyLoadingMiddleware:process in /var/www/vendor/zendframework/zend-stratigility/src/MiddlewarePipe.php:78
#27 Zend\Stratigility\MiddlewarePipe:handle in /var/www/src/CcApi/src/RouterOptionsToAttributesMiddleware.php:32
#26 Cc\Api\RouterOptionsToAttributesMiddleware:process in /var/www/vendor/zendframework/zend-expressive/src/Middleware/LazyLoadingMiddleware.php:46
#25 Zend\Expressive\Middleware\LazyLoadingMiddleware:process in /var/www/vendor/zendframework/zend-stratigility/src/MiddlewarePipe.php:78
#24 Zend\Stratigility\MiddlewarePipe:handle in /var/www/vendor/zendframework/zend-expressive-helpers/src/UrlHelperMiddleware.php:45
#23 Zend\Expressive\Helper\UrlHelperMiddleware:process in /var/www/vendor/zendframework/zend-expressive/src/Middleware/LazyLoadingMiddleware.php:46
#22 Zend\Expressive\Middleware\LazyLoadingMiddleware:process in /var/www/vendor/zendframework/zend-stratigility/src/MiddlewarePipe.php:78
#21 Zend\Stratigility\MiddlewarePipe:handle in /var/www/vendor/zendframework/zend-expressive-router/src/Middleware/MethodNotAllowedMiddleware.php:51
#20 Zend\Expressive\Router\Middleware\MethodNotAllowedMiddleware:process in /var/www/vendor/zendframework/zend-expressive/src/Middleware/LazyLoadingMiddleware.php:46
#19 Zend\Expressive\Middleware\LazyLoadingMiddleware:process in /var/www/vendor/zendframework/zend-stratigility/src/MiddlewarePipe.php:78
#18 Zend\Stratigility\MiddlewarePipe:handle in /var/www/vendor/zendframework/zend-expressive-router/src/Middleware/ImplicitOptionsMiddleware.php:70
#17 Zend\Expressive\Router\Middleware\ImplicitOptionsMiddleware:process in /var/www/vendor/zendframework/zend-expressive/src/Middleware/LazyLoadingMiddleware.php:46
#16 Zend\Expressive\Middleware\LazyLoadingMiddleware:process in /var/www/vendor/zendframework/zend-stratigility/src/MiddlewarePipe.php:78
#15 Zend\Stratigility\MiddlewarePipe:handle in /var/www/vendor/zendframework/zend-expressive-router/src/Middleware/ImplicitHeadMiddleware.php:84
#14 Zend\Expressive\Router\Middleware\ImplicitHeadMiddleware:process in /var/www/vendor/zendframework/zend-expressive/src/Middleware/LazyLoadingMiddleware.php:46
#13 Zend\Expressive\Middleware\LazyLoadingMiddleware:process in /var/www/vendor/zendframework/zend-stratigility/src/MiddlewarePipe.php:78
#12 Zend\Stratigility\MiddlewarePipe:handle in /var/www/vendor/zendframework/zend-expressive-router/src/Middleware/RouteMiddleware.php:54
#11 Zend\Expressive\Router\Middleware\RouteMiddleware:process in /var/www/vendor/zendframework/zend-expressive/src/Middleware/LazyLoadingMiddleware.php:46
#10 Zend\Expressive\Middleware\LazyLoadingMiddleware:process in /var/www/vendor/zendframework/zend-stratigility/src/MiddlewarePipe.php:78
#9 Zend\Stratigility\MiddlewarePipe:handle in /var/www/vendor/zendframework/zend-expressive-helpers/src/ServerUrlMiddleware.php:37
#8 Zend\Expressive\Helper\ServerUrlMiddleware:process in /var/www/vendor/zendframework/zend-expressive/src/Middleware/LazyLoadingMiddleware.php:46
#7 Zend\Expressive\Middleware\LazyLoadingMiddleware:process in /var/www/vendor/zendframework/zend-stratigility/src/MiddlewarePipe.php:78
#6 Zend\Stratigility\MiddlewarePipe:handle in /var/www/vendor/zendframework/zend-stratigility/src/Middleware/ErrorHandler.php:143
#5 Zend\Stratigility\Middleware\ErrorHandler:process in /var/www/vendor/zendframework/zend-expressive/src/Middleware/LazyLoadingMiddleware.php:46
#4 Zend\Expressive\Middleware\LazyLoadingMiddleware:process in /var/www/vendor/zendframework/zend-stratigility/src/MiddlewarePipe.php:78
#3 Zend\Stratigility\MiddlewarePipe:handle in /var/www/vendor/zendframework/zend-httphandlerrunner/src/RequestHandlerRunner.php:95
#2 Zend\HttpHandlerRunner\RequestHandlerRunner:run in /var/www/vendor/zendframework/zend-expressive/src/Application.php:81
#1 Zend\Expressive\Application:run in /var/www/public/index.php:21
#0 {closure} in /var/www/public/index.php:22