Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add additional table prototype for json string array #1

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

alexander-schranz
Copy link
Owner

@alexander-schranz alexander-schranz commented Oct 16, 2021

This pull request contains a lot of hacks, but good for a prototype. It generates a dynamic class which will generate a table instead of json array.

TODO

  • Move generating of Proxy Classes to compilerpass
    • Alternative listen to onClassMetadataNotFound exception
    • Find out how to access mapping configuration in compilerpass
    • Remove custom ClassMetadataFactory with duplicated getAllmetadata call
  • Implement MEMBER OF query method which should join the additional table

Version A (move json to own to many table)

  • Convert $locales array to collection on persist / update
  • Convert $locales collection to array on load

Version B (duplicate data to additional table)

  • Keep json field
  • Add additional $localeCollection only for filter query
  • Add ore remove locales on Persist / Update events check over unit of work diff

The entity should register the array field the following way:

    /**
     * @var iterable<\Stringable|string>
     *
     * @ORM\Column(type="json", options={"string-array": true})
     */
    private $locales;

The metadata loader will convert the json into a additonal table with a stringable entity.

CREATE TABLE event (id INT AUTO_INCREMENT NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB;
CREATE TABLE page (id INT AUTO_INCREMENT NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB;

CREATE TABLE page_locales (string VARCHAR(255) NOT NULL, object_id INT NOT NULL, INDEX IDX_1FFBBF2E232D562B (object_id), INDEX idx_string (string), INDEX idx_object_string (string, object_id), PRIMARY KEY(object_id, string)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB;

CREATE TABLE event_locales (string VARCHAR(255) NOT NULL, object_id INT NOT NULL, INDEX IDX_60CCFD14232D562B (object_id), INDEX idx_string (string), INDEX idx_object_string (string, object_id), PRIMARY KEY(object_id, string)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB;

ALTER TABLE page_locales ADD CONSTRAINT FK_1FFBBF2E232D562B FOREIGN KEY (object_id) REFERENCES page (id) ON DELETE CASCADE;
ALTER TABLE event_locales ADD CONSTRAINT FK_60CCFD14232D562B FOREIGN KEY (object_id) REFERENCES event (id) ON DELETE CASCADE;

A proxy class which implements \Stringable is created which looks like the following:

The proxy class name is a sha1 hash over the related entity full qualified class name plus the related field name.

<?php

namespace ORMArrayProxy;

use Doctrine\ORM\Mapping\Builder\ClassMetadataBuilder;
use Doctrine\ORM\Mapping\ClassMetadata;

/**
 * @internal
 */
class Proxy_0607a2d5cae4c928270cdaf51534266e1871bb19 implements \Stringable
{
    /**
     * @var null|string
     */
    public static $targetEntity = 'App\Entity\Page';

    /**
     * @var null|string
     */
    public static $inversedBy = 'locales';

    /**
     * @var null|string
     */
    public static $tableName = 'page_locales';

    /**
     * @var null|string
     */
    public static $referenceColumn =  'id';
    
    /**
     * @var object
     */
    protected $object;

    /**
     * @var string
     */
    protected $string = '';

    public function __toString(): string
    {
        return $this->string;
    }

    public static function loadMetadata(ClassMetadata $metadata)
    {
        $builder = new ClassMetadataBuilder($metadata);

        $builder->setTable(static::$tableName);

        $builder->createManyToOne(
            'object',
            static::$targetEntity
        )
            ->inversedBy(static::$inversedBy)
            ->addJoinColumn(
                'object_id',
                static::$referenceColumn,
                true,
                false,
                'CASCADE'
            )
            ->makePrimaryKey()
            ->build();

        $builder->createField('string', 'string')
            ->columnName('string')
            ->makePrimaryKey()
            ->build();

        $builder->addIndex(['string'], 'idx_string');
        $builder->addIndex(['string', 'object_id'], 'idx_object_string');
    }
}

@alexander-schranz alexander-schranz force-pushed the feature/first-prototype branch 3 times, most recently from 1cd5553 to e9fbeaf Compare October 16, 2021 14:46
@alexander-schranz alexander-schranz changed the title Add additonal table prototype Add additional table prototype for json string array Oct 16, 2021
@alexander-schranz alexander-schranz force-pushed the feature/first-prototype branch 3 times, most recently from 7ed6ed4 to dddd6c6 Compare October 16, 2021 14:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant