D
D
dinya172020-08-11 17:44:18
PostgreSQL
dinya17, 2020-08-11 17:44:18

Why is One-To-Many Doctrine linking not working in Postgress camelCase link field?

The essence of the problem is the following.
There are 2 entities and they are related One-To-Many

class Shipping
{
    /**
     * @var int
     *
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var ShippingStatus
     *
     * @ORM\Column(type="shipping_status")
     */
    private $status;

    /**
     * @var OrderId
     *
     * @ORM\Column(name="orderId", type="order_id", unique=true)
     */
    private $orderId;

    /**
     * @var \DateTimeImmutable
     * @ORM\Column(name="createDate", type="datetimetz_immutable")
     */
    private $createDate;

    /**
     * История
     *
     * @var Collection
     * @ORM\OneToMany(targetEntity="PointHistory", mappedBy="shipping", cascade={"all"}, orphanRemoval=true)
     *
     */
    private $pointsHistory;

    public function __construct(OrderId $orderId)
    {
        $this->orderId = $orderId;
        $this->createDate = new \DateTimeImmutable();
        $this->status = new ShippingStatus(ShippingStatus::IN_PROGRESS);
        $this->pointsHistory = new ArrayCollection();
    }

    /**
     * Добавить запись в историю.
     *
     * @param int                $pointId
     * @param \DateTimeImmutable $createDate
     * @param PointStatus        $pointStatus
     *
     * @throws ValidationError
     */
    public function addPointHistory(int $pointId, \DateTimeImmutable $createDate, PointStatus $pointStatus): void
    {
        $history = new PointHistory($pointId, $createDate, $this, $pointStatus);
        $this->pointsHistory->add($history);
    }

    /**
     * @return PointHistory[]
     */
    public function getHistory(): array
    {
        return $this->pointsHistory->toArray();
    }
}



class PointHistory
{
    /**
     * @var int
     *
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var PointStatus
     *
     * @ORM\Column(type="point_status")
     */
    private $status;

    /**
     * @ORM\Column(name="pointId", type="integer")
     */
    private $pointId;

    /**
     * @var \DateTimeImmutable
     * @ORM\Column(name="createDate", type="datetimetz_immutable")
     */
    private $createDate;

    /**
     * @ORM\ManyToOne(targetEntity="driverApp\src\modules\Order\entities\shipping\Shipping", inversedBy="pointsHistory")
     * @ORM\JoinColumn(name="shippingId", nullable=false, onDelete="CASCADE")
     */
    private $shipping;

    public function __construct(int $pointId, \DateTimeImmutable $createDate, Shipping $shipping, PointStatus $status)
    {
        $this->pointId = $pointId;
        $this->shipping = $shipping;
        $this->createDate = $createDate;
        $this->status = $status;
    }

}


There was a problem with quotes, but I solved it in this magical way

class QuotedStrategy implements QuoteStrategy
{

    private function quote($token, AbstractPlatform $platform)
    {
        switch ($platform->getName()) {
            case 'postgresql':
            default:
                return $this->quoteIdentifier($token);
        }
    }

    private function quoteIdentifier($str)
    {
        if (strpos($str, '.') !== false) {
            $parts = array_map([$this, 'quoteSingleIdentifier'], explode('.', $str));

            return implode('.', $parts);
        }

        return $this->quoteSingleIdentifier($str);
    }

    private function quoteSingleIdentifier($str)
    {
        $c = '"';

        return $c . str_replace($c, $c . $c, $str) . $c;
    }

    // add quoting to appropriate methods
    public function getColumnName($fieldName, ClassMetadata $class, AbstractPlatform $platform)
    {
        return $this->quote($class->fieldMappings[$fieldName]['columnName'], $platform);
    }

    public function getTableName(ClassMetadata $class, AbstractPlatform $platform)
    {
        return $class->table['name'];
    }

    public function getSequenceName(array $definition, ClassMetadata $class, AbstractPlatform $platform)
    {
        return $definition['sequenceName'];
    }

    public function getJoinColumnName(array $joinColumn, ClassMetadata $class, AbstractPlatform $platform)
    {
        return $this->quote($joinColumn['name'], $platform);
    }

    public function getReferencedJoinColumnName(array $joinColumn, ClassMetadata $class, AbstractPlatform $platform)
    {
        return $joinColumn['referencedColumnName'];
    }

    public function getJoinTableName(array $association, ClassMetadata $class, AbstractPlatform $platform)
    {
        return $association['joinTable']['name'];
    }

    public function getIdentifierColumnNames(ClassMetadata $class, AbstractPlatform $platform)
    {
        return $class->identifier;
    }

    public function getColumnAlias($columnName, $counter, AbstractPlatform $platform, ClassMetadata $class = null)
    {
        return $platform->getSQLResultCasing($columnName . '_' . $counter);
    }
}


But the problems didn't end there. Now, when trying to get the data of the related PointHistory entity , an error occurs
An exception occurred while executing 'SELECT t0.\"id\" AS id_1, t0.\"status\" AS status_2, t0.\"pointId\" AS pointid_3, t0.\"createDate\" AS createdate_4, t0.\"shippingId\" AS shippingid_5 FROM da_point_status_history t0 WHERE t0.shippingId = ?' with params [35]:\n\nSQLSTATE[42703]: Undefined column: 7 ERROR:  column t0.shippingid does not exist\nLINE 1: ...hippingid_5 FROM da_point_status_history t0 WHERE t0.shippin...\n                                                             ^\nHINT:  Perhaps you meant to reference the column \"t0.shippingId\"


here is more details

SELECT t0.\"id\" AS id_1, t0.\"status\" AS status_2, t0.\"pointId\" AS pointid_3, t0.\"createDate\" AS createdate_4, t0.\"shippingId\" AS shippingid_5 FROM da_point_status_history t0 WHERE t0.shippingId


Those. When constructing criteria, the doctrine does not put quotes for field names, in my case, shippingId

How to make the doctrine do this? I didn't find anything similar in the documentation.
But I found the code where it's all done
BasicEntityPersister.php
$field = $sourceClass->fieldNames[$sourceKeyColumn];
            $value = $sourceClass->reflFields[$field]->getValue($sourceEntity);

            $criteria[$tableAlias . "." . $targetKeyColumn] = $value;
            $parameters[] = [
                'value' => $value,
                'field' => $field,
                'class' => $sourceClass,
            ];


I'm sure I'm not the first to encounter this, but I haven't found the answers anywhere yet. Click where to look.

Answer the question

In order to leave comments, you need to log in

1 answer(s)
D
dinya17, 2020-08-12
@dinya17

So far no one has answered. I solved it all by simply renaming the fields from camel to underscore, everything immediately took off. But why not decide otherwise?

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question