B
B
BonBon Slick2021-03-18 00:50:57
Doctrine ORM
BonBon Slick, 2021-03-18 00:50:57

One to many for super class mapping?

Docs
I know that

A mapped superclass cannot be an entity, it is not query-able and persistent relationships defined by a mapped superclass must be unidirectional (with an owning side only). This means that One-To-Many associations are not possible on a mapped superclass at all


And it is not clear how then it is correct to implement such

5 types of tokens, they all map an abstract token.
An abstract token has a field
protected ArrayCollection $apiCalls;

Every type of token must have this field. But alas, that's not possible.
<mapped-superclass name="App\Domain\TokenPack\Shared\Entity\AbstractToken">
        <embedded name="id"
                  class="App\Domain\Core\ValueObjects\EntityId"
                  use-column-prefix="false"
        />
...
        <!-- One To Many -->
        <one-to-many target-entity="App\Domain\LogPack\ApiCallLog\Entity\ApiCallLog"
                     field="apiCalls"
                     orphan-removal="true">
            <cascade>
                <cascade-persist/>
            </cascade>
            <order-by>
                <order-by-field name="createdAt" direction="DESC"/>
            </order-by>
        </one-to-many>


How would one associate a query with each type of token, because tables and entities are different for each token?

prescribe
<one-to-many target-entity="App\Domain\LogPack\ApiCallLog\Entity\ApiCallLog"

I think it will be incorrect, because the ApiCallLog table does not know about token types, therefore there is a possibility of collisions, where the same request log will be shown in different tokens.

Class inheritance will solve this problem, but will create another one, the token table will be huge. For each session, an anonymous token is created for using the API, these are hundreds of thousands of temporary records, the table is constantly under load insert / fetch.
While other tokens are used less frequently and much less often.

Answer the question

In order to leave comments, you need to log in

1 answer(s)
B
BonBon Slick, 2021-03-18
@BonBonSlick

Temporary solution , it should be reviewed and tested more thoroughly.

class ApiCallLog implements IAggregateRoot {
     public ?AuthToken                                 $authToken;
    public ?AnonToken                                 $anonToken;


    /**
     * @throws Exception
     */
    public function __construct(ApiCallLogCreateDTO $dto) {
        if (null === $dto->anonToken && null === $dto->authToken) {
            throw new Exception('One of tokens required to create entity');
        }
...


    public function token(): AbstractToken {
        return true === $this->authToken instanceof AuthToken ? $this->authToken : $this->anonToken;
    }

<entity name="App\Domain\TokenPack\Auth\Entity\AuthToken">
...
        <!-- One To Many -->
        <one-to-many target-entity="App\Domain\LogPack\ApiCallLog\Entity\ApiCallLog"
                     field="apiCalls"
                     mapped-by="authToken"
                     orphan-removal="true">
            <cascade>
                <cascade-persist/>
            </cascade>
            <order-by>
                <order-by-field name="createdAt" direction="DESC"/>
            </order-by>
        </one-to-many>

The same for the anon token only to a different field="anonToken"mapping field.
<entity name="App\Domain\LogPack\ApiCallLog\Entity\ApiCallLog"
            repository-class="App\Infrastructure\Persistence\Repository\DB\DQL\ApiCallLog\DQLRepositoryApiCallLog">
      ....
        <many-to-one target-entity="App\Domain\TokenPack\Auth\Entity\AuthToken"
                     field="authToken"
                     inversed-by="apiCalls"
        >
            <cascade>
                <cascade-persist/>
            </cascade>
            <join-column name="auth_token_uuid" referenced-column-name="uuid" nullable="true"/>
        </many-to-one>
        <many-to-one target-entity="App\Domain\TokenPack\Anon\Entity\AnonToken"
                     field="anonToken"
                     inversed-by="apiCalls"
        >
            <cascade>
                <cascade-persist/>
            </cascade>
            <join-column name="anon_token_uuid" referenced-column-name="uuid" nullable="true"/>
        </many-to-one>

This approach solves the problem of where to receive user or anon requests.
Of the shortcomings
1 - it is necessary to validate, one of the must-have tokens
2 - one of the fields is always null, I don’t remember the exact term, but when one of the fields is always null, then the table was built incorrectly. Data integrity like. This leads to a bunch of checks in the code itself and on requests of type $apiCall->token() !== nullor WHERE authToken IS NOT NULL...
3 - actually more complex mapping
4 - since the user can make requests while being both anon (incognito) and logged in, it means that when receiving information, how many requests the user completed in N time, you need to merge anon + auth tokens.
I think it can throw out the connection with the token, there is too much overhead and just slap the IP, it's just that the tokens have more information. You can monitor which routes are more often used by anons, and which are authorized users.
For what? Trite, patterns of behavior and ban bots. Although this topic is already different, about how to trap bots, parsing, etc.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question