phptypo3extbase

What is the correct php type for fields with TCA type json?


I want to store some options in the DB like this:

    'question_options' => [
        'exclude' => false,
        'label' => 'xxx',
        'description' => 'xxx',
        'config' => [
            'type' => 'json',
            'default' => ''
        ],
    ],

What would the correct type for my Model.php be?

/**
 * questionOptions
 *
 * @var string ?? array ?? object ?? mixed ??
 */
protected $questionOptions;

Array shows null and string gets escaped when setting it through a setter.


Solution

  • You could make use of TYPO3's TypeInterface which will get raw data passed as constructor argument by the DataMapper. This works similar for the PropertyMapper which does this via the CoreTypeConverter.

    This allows you to use classes which implement the TypeInterface as type for domain model properties. In this particular case you can automatically convert the raw JSON string to an array-like structure like this:

    <?php
    
    declare(strict_types=1);
    
    namespace Acme\Package\Domain\Data;
    
    use TYPO3\CMS\Core\Type\TypeInterface;
    
    final class JsonData extends \ArrayObject implements TypeInterface
    {
        public function __construct(string $jsonString)
        {
            $data = json_decode(
                json: $jsonString,
                associative: true,
                flags: \JSON_THROW_ON_ERROR,
            );
    
            parent::__construct($data);
        }
    
        public function __toString(): string
        {
            return json_encode(
                value: $this,
                flags: \JSON_THROW_ON_ERROR,
            );
        }
    }
    

    Your domain model can now use this as property type:

    
    declare(strict_types=1);
    
    namespace Acme\Package\Domain\Model;
    
    use Acme\Package\Domain\Data\JsonData;
    use TYPO3\CMS\Extbase\DomainObject\AbstractEntity;
    
    final class Example extends AbstractEntity
    {
        public ?JsonData $data = null;
    }
    

    Now all instances allow you to transparently access the already decoded JSON data. Assuming an object $example1 of this Example model which has {"foo":"bar"} as data in its tx_package_domain_model_example.data column:

    $example1->data['foo'];
    
    {example1.data.foo}
    

    You can see a real-life implementation of this in the pagemachine/typo3-formlog package:

    1. Domain/Data/JsonData.php
    2. Domain/Model/FormLogEntry.php