📑
Symfony + ApiPlatformでcsvレスポンスのヘッダーをカスタマイズする
apiPlatformはnormalizeするクラスを定義すればjson, csv, xmlなど様々な形式でレスポンスを返却することができる。
denormalizeする際、対象のオブジェクトのキー(csvならばカラムヘッダー)の名前はクラスのプロパティがそのまま使われる。
jsonで返却する場合はこれで問題ないが、csvで返却する場合は、カラムヘッダーは日本語の方がいいことがある。
この記事ではそれを実現する方法を紹介する。正しくないかもしれない。
方針
- カラムヘッダーを付与するようなattributeを定義する
- カスタムカラムヘッダーを設定したいクラスに1で定義したattributeを付与する
- normalizer (denormalizer) でattributeを参照してカラムヘッダーを取得し、csvのヘッダーに設定する
全体的なイメージは以下の通り。
<?php
// カラムヘッダーを設定するattribute
#[Attribute(Attribute::TARGET_PROPERTY)]
class CsvColumnNameAttribute
{
public function __construct(
private string $columnName
) {
}
}
// csv で返却したいクラス
class OrderResource
{
#[CsvColumnNameAttribute('注文ID')]
public int $id;
#[CsvColumnNameAttribute('商品名')]
public string $name;
}
これで以下のcsvが返却されるようにしたい。
注文ID,商品名
1,商品A
実装
attributeとcsvに変換するクラスの実装は前述の通りでよい。
次にnormalizer (denormalizer) を実装する。
<?php
class CsvResponseNormalizer implements NormalizerInterface
{
private NormalizerInterface $normalizer;
public function __construct(
NormalizerInterface $normalizer,
) {
$this->normalizer = $normalizer;
}
/**
* @return mixed[]
*/
public function normalize(mixed $object, ?string $format = null, array $context = []): array
{
if ($format !== 'csv') {
return $this->normalizer->normalize($object, $format, $context);
}
$reflectionClass = new \ReflectionClass($object);
$data = [];
foreach ($reflectionClass->getProperties() as $property) {
$attributes = $property->getAttributes(CsvColumnNameAttribute::class);
$attribute = $attributes[0]->newInstance();
$property->setAccessible(true);
$data[$attribute->columnName] = $property->getValue($object);
}
return $data;
}
public function supportsNormalization(mixed $data, ?string $format = null): bool
{
return $this->normalizer->supportsNormalization($data, $format);
}
/**
* @return array<mixed>
*/
public function getSupportedTypes(?string $format): array
{
return $this->normalizer->getSupportedTypes($format);
}
}
あとはservices.yamlの登録する。
services:
App\Shared\Presentation\Serializer\CsvResponseNormalizer:
arguments: [ '@api_platform.serializer.normalizer.item' ]
tags: [ 'serializer.normalizer' ]
これで返却されるcsvのヘッダーをカスタマイズすることができる
結論
symfony + apiPlatform + doctrine構成で実装しているが、これらが全部難しい。
Discussion