Доктрина не сохранит измененные данные - PullRequest
0 голосов
/ 04 сентября 2018

Итак, я пытаюсь сохранить сущность в Доктрине. Объект, который я хочу сохранить, выглядит так, как он извлекается из функции Symfony dump ():

Time {#7751 ▼
  -id: 3
  -timeIn: DateTime {#7749 ▶}
  -timeOut: null
  -rateId: Rate {#7761 ▼
    -id: 1
    -amount: "30.00"
    -name: "Technical"
    -projectId: Project {#7756 ▶}
    -groupId: 1
  }
  -description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."
  -userId: 1
  -status: "Unpaid"
  -total: null
  -cost: "60.00"
  -projectId: Project {#7756 ▼
    -id: 1
    -name: "Acme Corp"
    -description: "Metals Company"
    -contactId: 1
    -organizationId: 1
    -groupId: 1
  }
  -groupId: 1
  }

Теперь я, очевидно, не могу сохранить это, потому что у меня есть соответствующие объекты в их идентификаторах. Например: rateId, projectId и т. Д. Поэтому, чтобы компенсировать это, в моей функции clockOut я запускаю проверку, чтобы заменить объекты с их идентификаторами для хранения. См. Функцию clockOut ниже:

public function clockOut($time, $group = null){
    dump($time);
    if(gettype($time) == "object"){
        if(gettype($time->getProjectId())=='object'){
            $time->setProjectId($time->getProjectId()->getId());
        }
        if(gettype($time->getRateId())=='object'){
            $time->setRateId($time->getRateId()->getId());
        }
        $this->persistClockout($time);
    }
    elseif(gettype($time) == "string"){
        if($group == null){
            return false;
        }else {
            $time = $this->findData($group, $time);
            $this->persistClockout($time);
        }
    }else {
        return false;
    }
}

Существует также соответствующая функция persistClockout, которая обрабатывает фактическое тактирование и вычисление часов. Хотя я не думаю, что это действительно имеет какое-либо отношение к проблеме, которая у меня есть, я все равно включу ее, потому что она связана.

/**
 * Persist time
 */
private function persistClockout($time, $group = null){
    if($time->getTimeOut() == null){
        $time->setTimeOut(new DateTime("Now"));
    }
    $this->hours = $this->hoursCalculate($time->getTimeIn(), $time->getTimeOut());
    $time->setTotal($this->hours);
    dump($time);
    die();
    $this->persist($time);
}

/**
 * Get the amount of hours spent in decimal format.
 */
private function hoursCalculate($past, $present){
    $diff = $present->diff($past);
    $hours = round($diff->s / 3600 + $diff->i / 60 + $diff->h + $diff->days * 24, 2);
    return $hours;
}

Теперь, как вы можете видеть, я запускаю функцию dump () непосредственно перед завершением команды, прежде чем она сохранится, потому что я сам пытался диагностировать эту проблему. Согласно функции dump () данные выглядят так:

Time {#7751 ▼
  -id: 3
  -timeIn: DateTime {#7749 ▶}
  -timeOut: DateTime {#11571 ▶}
  -rateId: 1
  -description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."
  -userId: 1
  -status: "Unpaid"
  -total: 187.83
  -cost: "60.00"
  -projectId: 1
  -groupId: 1
}

Отлично! Это ожидаемый результат. Но проблема возникает, когда я начинаю пытаться сделать фактическое сохранение в базе данных.

An exception occurred while executing 'UPDATE rate SET project_id = ? WHERE id = ? AND group_id = ?' with params [{}, 1, 1]:

Notice: Object of class ProjectBundle\Entity\Project could not be converted to int

Хотя я проверил данные непосредственно перед запуском функции persist, мне все еще кажется, что projectId по-прежнему является объектом, хотя я и установил для него фактический Id, а не объект, он игнорирует меня.

Я пошел дальше и заглянул в профилировщик Symfony и нашел ту часть, которую доктрина использует для обновления, и просмотрел детали, и вот, projectId - это объект? Даже если это не то, что я передал?

Symfony Profiler SQL update with params listed.

Кто-нибудь знает, что происходит? Извините за многословный пост, я просто хотел дать вам, ребята, немного информации о том, с чем вы работаете. Пожалуйста, игнорируйте функции dump () и die () в коде, я использовал их, чтобы попытаться диагностировать это, но я озадачен. Стоит отметить, что я попробовал запустить такие обычные вещи, как кэш php bin / console: очистить и перезапустить сервер.

Благодарим вас за переполнение стека!

РЕДАКТИРОВАТЬ:

Ниже приведен код для -> persist ()

    public function persist($entity, bool $flush = true)
{
    $this->manager->persist($entity);

    if ($flush) {
        $this->flush();
    }

    return $this;
}

UPDATE

Я попытался запустить persist, а затем выполнить сброс отдельно, но это не сработало. Получил то же исключение. Я, честно говоря, в растерянности, ребята.

Ответы [ 2 ]

0 голосов
/ 07 сентября 2018

Я понял это. Оказывается, это была проблема с тем, как доктрина идентифицирует различные фрагменты данных и что она считает одинаковыми. Я бы предположил, что это связано с эффективностью, кэшированием или чем-то в этом роде.

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

Первый совет, который я получил, заключался в том, что, хотя rateId изначально был объектом, а затем был преобразован в соответствующий ему идентификатор, он не выдавал ошибку, как это делал ProjectId.

Во-вторых, я изучил функцию dump () гораздо ближе и кое-что заметил. (Я буду использовать пример из моего исходного поста)

Time {#7751 ▼
  -id: 3
  -timeIn: DateTime {#7749 ▶}
  -timeOut: null
  -rateId: Rate {#7761 ▼
    -id: 1
    -amount: "30.00"
    -name: "Technical"
    -projectId: Project {#7756 ▶}  <---- Right Here
    -groupId: 1
  }
  -description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."
  -userId: 1
  -status: "Unpaid"
  -total: null
  -cost: "60.00"
  -projectId: Project {#7756 ▼  <---- Right Here
    -id: 1
    -name: "Acme Corp"
    -description: "Metals Company"
    -contactId: 1
    -organizationId: 1
    -groupId: 1
  }
  -groupId: 1
  }

Числа после объектов Project были одинаковыми. Поэтому я пришел к теории, что доктрина хранит исходную ссылку на projectId (объект) и использует ее вместо значения, которое я позже установил в качестве соответствующего идентификатора (Int).

Итак, чтобы проверить эту теорию, я написал две функции для «выравнивания» моего объекта, начиная с конца дерева объектов (поскольку оно действительно должно идти только до 3 вложенных объектов) до начала. Таким образом, все ссылки совпали, хотя в конечном итоге они были «удалены».

 /**
 * Undo all object associations and convert them back into their original IDs. 
 * @param object $data
 * @param array $callable
 */
public function flattenObject($data, $callable){
    $sorter = new SortingHelper;
    foreach($callable as $call){
        $getMethod = 'get'.ucfirst($call).'Id';
        $setMethod = 'set'.ucfirst($call).'Id';
        if(method_exists($data, $getMethod)){
            $found = $data->$getMethod();
            if(gettype($found) == 'object'){
                $result = $this->flatten($found, $callable);
                $data->$setMethod($result);
            }
        }
    }
    return $data;
}

/**
 * @param object $data 
 * @param array $callable
 */
private function flatten($data, $callable){
    for($i = 0; $i != count($callable); $i++){
        $getMethod = 'get'.ucfirst($callable[$i]).'Id';
        $setMethod = 'set'.ucfirst($callable[$i]).'Id';
        if(method_exists($data, $getMethod)){
            $result = $data->$getMethod();
            if(gettype($result) == 'object'){
                $data->$setMethod($result->getId());
            }
        }
    }
    return $data->getId();
}

Запуск функции flattenObject () позволил мне сохранить объект в базе данных, поскольку ссылки на идентификаторы больше не были объектами.

Bam. Супер раздражающая проблема решена.

Надеюсь, это как-то поможет кому-то в будущем. Спасибо всем, кто внес свой вклад! :)

0 голосов
/ 04 сентября 2018

Я думаю, вам нужно было использовать этот код:

$this->flush($time); 

вместо $this->persist($time);

...