Как я могу предотвратить сохранение нежелательной доктрины в Symfony 4?

На данный момент я не уверен, проблема в доктрине или в symfony.

У меня есть объект под названием Field. У него есть свойство dataTable с обычными методами получения и установки. В одном из моих вспомогательных классов я использую метод установки, чтобы изменить dataTable на временное значение. Я никогда не вызываю persist в этом классе или контроллере, который его вызывает. Однако я обнаружил, что база данных обновляется с помощью этого временного значения.

Если нужно, я могу добавить виртуальное свойство и использовать его вместо этого, но я думаю, что код будет чище, если я смогу этого избежать. Как я могу гарантировать, что доктрина сохраняет только то, о чем я прямо говорю?

Отображение объектов:

type: entity

gedmo:
  soft_deleteable:
    field_name: deletedAt
    time_aware: false

id:
  id:
    type: integer
    generator:
      strategy: auto

fields:
  name:
    type: string
  sortorder:
    type: integer
  dataTable:
    type: string
  type:
    type: string
  columnAdded:
    type: boolean
  deletedAt:
    type: date
    nullable: true

manyToOne:
  section:
    targetEntity: Domain\Model\Section
    inversedBy: fields

oneToMany:
  fieldOptions:
    targetEntity: FieldOption
    mappedBy: field

oneToOne:
  zmrList:
    targetEntity: Domain\Model\ZmrList

Соответствующий код контроллера: (Persist никогда не вызывается ни для чего в контроллере)

 $columns = $this->queryBuilder->getListColumns($list);
 $filters = $this->queryBuilder->composeListFilters($list);
 $query = $this->queryBuilder->build($columns, $filters, $list->getForm()->getId(), $instanceId);

Соответствующий код в QueryBuilder:

 foreach ($details['columns'] as $k=>$layerColumn) {
                        $this->columns[$layerColumn]->getField()->setDataTable('table_'.$alias);
}

Функция сеттера:

 /**
     * @param string $dataTable
     */
    public function setDataTable(string $dataTable): void
    {
        $this->dataTable = $dataTable;
    }

можешь дать код карты? Контроллер и код, которые выполняют модификацию связанного объекта?

Greco Jonathan 24.04.2019 14:54

в чем я уверен, так это в том, что база данных обновляется только в том случае, если вы используете ** flush () **, поэтому отлаживайте свой код и смотрите, не сбрасываете ли вы объект где-то

A.Marwan 24.04.2019 15:23
flush записывает изменения, внесенные в Любые управляемых объектов. «временное» изменение значения управляемого объекта не чисто, это грязно. Я бы действительно использовал временное поле или переоценил бы подход.
Jakumi 24.04.2019 15:35

@Джакуми, спасибо. Если вы хотите опубликовать это как ответ, я приму это

Amy Anuszewski 24.04.2019 15:58

@AmyAnuszewski Это действительно возможно, я только что добавил ответ.

Rikudou_Sennin 29.04.2019 01:09
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Symfony Station Communiqué - 17 февраля 2023 г
Symfony Station Communiqué - 17 февраля 2023 г
Это коммюнике первоначально появилось на Symfony Station , вашем источнике передовых новостей Symfony, PHP и кибербезопасности.
Управление ответами api для исключений на Symfony с помощью KernelEvents
Управление ответами api для исключений на Symfony с помощью KernelEvents
Много раз при создании api нам нужно возвращать клиентам разные ответы в зависимости от возникшего исключения.
1
5
1 081
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

заявление об отказе от ответственности: верно следующее для политики отслеживания изменений по умолчанию (неявно)

flush по определению записывает любые изменения, внесенные в управляемые объекты, в базу данных.

Сохранение объекта делает его управляемым, и поэтому любые изменения в нем, даже если они должны быть «временными», будут сохраняться в flush (как уже указал А. Марван в комментарии).

Поскольку семантика очень ясна, я бы посоветовал не устанавливать временные значения для управляемых полей (любых сопоставленных полей). Либо добавьте для этого временное свойство, либо переоцените подход - может быть, сервис, оболочку или что-то еще, что лучше подходит для вашего варианта использования.


комментарий для изменения политики отслеживания:

Ответ Rikudou_Sennin предлагает технически правильное решение технической проблемы, когда объекты сохраняются, когда разработчик может этого не захотеть... путем изменения политики отслеживания изменений. ИМХО, это семантически зло, ... ну ладно, назовем это проблематичным.

Как разработчик, я всегда предполагал, что объекты имеют согласованное состояние, даже если оно еще не сброшено в базу данных. Если он имеет состояние, отличное от его сохраненной версии, я хочу предположить, что когда запрос выполнен и все или ничего измененных объектов записываются в базу данных, база данных находится в согласованном состоянии. «Нет» можно считать заданным. Об «всех» достаточно сложно думать.

Однако с другой политикой отслеживания изменений и неявной возможностью того, что «грязный» объект, который никогда не будет доверенным, может крутиться вокруг со значениями, на которые разработчик никоим образом не может полагаться, потому что неясно, будет ли объект сохранен. или нет, или, может быть, было упорно. Это только добавляет больше (ненужных) сомнений. Это также является дополнительным источником трудно поддающихся отладке ошибок.

Резюме вариантов:

  • добавление временного поля (или дополнительной переменной/объекта или чего-то еще): разумные усилия и никакого влияния на семантику (и предположения)*
  • изменение политики отслеживания и неправильное использование поля: низкие усилия при первом использовании, неизвестные (возможно, непостижимые) будущие усилия, потеря семантики и допущений (должны требоваться явно заявленные гарантии, и даже в этом случае!).

*) предполагает в некотором роде чистый и правильно структурированный код с неповрежденной и бескомпромиссной семантикой.

Неправда, вы можете изменить политику отслеживания.

Rikudou_Sennin 29.04.2019 01:09

@Rikudou_Sennin хорошо, я исправлен. Однако я бы сказал, что это менее интуитивно понятно и создает другие проблемы и ловушки.

Jakumi 29.04.2019 11:18

Вы имеете в виду изменение политики отслеживания или использование полей для временных значений? Изменение политики отслеживания на явное на самом деле круто, поскольку Doctrine работает намного быстрее, если вы работаете с большим количеством объектов. Я согласен с тем, что использование отслеживаемых полей для временных значений — не самое чистое решение.

Rikudou_Sennin 07.05.2019 19:19

Политика отслеживания @Rikudou_Sennin (явная) менее интуитивна, потому что вы должны явно отслеживать изменения. Не сомневаюсь, что быстрее. Однако (см. редактирование ответа) я бы предпочел неявное явному, если только нет очень веских причин не делать этого. Однако в этих случаях необработанный sql может быть даже лучше ^^

Jakumi 07.05.2019 19:50

Вы можете сделать это, изменив Change Tracking Policy с Deferred Implicit (по умолчанию) на Deferred Explicit. Изменив его на явный, в базу данных будут сохраняться только объекты, отмеченные persist(), даже обновления (в схеме implicit отслеживаются все обновления). У него есть еще одно преимущество, заключающееся в том, что он намного более удобен для памяти, потому что ему не нужно проходить каждый объект, который находится в хранилище доктрин, он проходит только те, которые вы пометили для сохранения с помощью persist().

Вот как это сделать через yaml:

type: entity
changeTrackingPolicy: DEFERRED_EXPLICIT # can be DEFERRED_IMPLICIT, DEFERRED_EXPLICIT or NOTIFY

# the rest of your config

Я думаю, что ваш ответ был тем, что я изначально искал, однако я думаю, что Джакуми был прав в том, что мне не следует делать то, что я делаю. Я создал виртуальное свойство вместо внесения временных изменений в исходное поле.

Amy Anuszewski 29.04.2019 14:53

Другие вопросы по теме