-
-
Save nebkam/81de7b5460d99049e73f12037222cae9 to your computer and use it in GitHub Desktop.
<?php | |
class ApiClient | |
{ | |
/** | |
* @return Project[] | |
*/ | |
public function getProjects(): array | |
{ | |
$projects = []; | |
$response = $this->client->get('https://some-awesome.api/projects'); | |
$projectCollection = $this->serializer->deserialize($response->getBody()->getContent(), ProjectCollection::class, 'json'); | |
if (!empty($collection->getResult())) | |
{ | |
foreach ($collection->getResult() as $project) | |
{ | |
if ($project->isOnSale()) | |
{ | |
$projects[] = $project; | |
} | |
} | |
} | |
return $projects; | |
} | |
public function addNewProject(Project $project) | |
{ | |
$this->client->post('https://some-awesome.api/projects', [ | |
'body' => $this->serializer->serialize($project, 'json') | |
]); | |
} | |
} |
<?php | |
use Symfony\Component\Serializer\Annotation\SerializedName; | |
class Project | |
{ | |
/** | |
* @SerializedName("Id") | |
* @var int | |
*/ | |
private $internalId; | |
/** | |
* @SerializedName("Name") | |
* @var string | |
*/ | |
private $title; | |
/** | |
* @SerializedName("Quality") | |
* @var float | |
*/ | |
private $quality; | |
// getters and setters | |
} |
<?php | |
use Symfony\Component\Serializer\Annotation\SerializedName; | |
class ProjectCollection | |
{ | |
/** | |
* @SerializedName("Result") | |
* @var Project[] | |
*/ | |
private $result; | |
/** | |
* @return Project[]|null | |
*/ | |
public function getResult(): ?array | |
{ | |
return $this->result; | |
} | |
/** | |
* @param Project[] $results | |
*/ | |
public function setResult(array $result) | |
{ | |
$this->result = $result; | |
} | |
} |
Just a simple getter:
/**
* @return Project[]|null
*/
public function getResult(): ?array
{
return $this->result;
}
What kind of problems are you running into?
The code works but... It returns an array of key-value pairs instead of Project (in my case Contact) objects. So somewhere I mist the part that you said:
"Have you noticed I didn’t have to tell the Serializer to map to the Project class?". I could not find out what is the key part in this.
Have you required symfony/property-info
?
After debugging a while, it seems that Serializer uses PropertyInfo component in order to "guess" from annotations which classes should be instantiated.
When I removed symfony/property-info
as a test from my project, the response wasn't typecasted, just like you've said.
That component was an indirect dependency in my project, that's why I haven't noticed it was required.
I'll update the article after you confirm it was causing it.
Thanks for catching that! 👍 :)
Hmm still not working :-(
Here's my gist with the test https://gist.github.com/parijke/05ac5d4332c1633ef23be25027a24965
I think you also made a typo using $projectCollection and $collection
I probably do not understand enough what is or should happening
Any tips what I am doing wrong?
I've been banging my head on it for an hour and finally found the culprit - another hidden dependency
composer require phpdocumentor/reflection-docblock
- Serializer uses Property Info
- Property Info uses extractors
- since the only piece of information that your
$result
is an array ofProject
s is theProject[]|null
PHP DocBlock, the corresponding extractor is needed to parse that - I've reproduced the bug with your gist (thank you) and it disappeared after requiring the package from above
I'll update my article with those hidden dependencies. Thanks again
PS I recommend that you inject the serializer in your controller/service (typecast it to SerializerInterface
) instead of constructing it, like in your gist. That way, you'll be sure the extractor is registered in the Serializer
Yes, finally I got Project objects returned now it works like I expected. Gonna try to fix the mapping. I also changed the example to use the SerializerInterface type hint as you suggested. The default serializer-pack of the website-skeleton installs all (hidden) dependencies.
array:3 [▼
0 => App\Model\Project {#699 ▼
-title: "Project A"
-sale: "1"
}
1 => App\Model\Project {#693 ▼
-title: "Project B"
-sale: "1"
}
2 => App\Model\Project {#692 ▼
-title: "Project C"
-sale: "0"
}
]
Great! I'm glad it worked! I learned a lot through your use case, thanks!
I've updated the article to suggest symfony/serializer-pack
and mentioned you in the DocBlock parsing ;)
Thx I learned a lot as well. And appreciate the mention. I am going to use this further in my project.
I ca'nt seem to get it to work.
Whats does the getResult function looks like in the ProjectCollection class?