Насколько я могу судить, проблема не в менеджере сущностей или dbal, а в использовании анти-паттерна, который я бы назвал ... запутанностью. К чему вы должны стремиться, это разделение интересов . По сути: ваша CompanyModel является недостаточной и плохой оболочкой для EntityManager и / или EntityRepository.
- Нет объекта должен знать о менеджере сущностей. Это должно касаться только хранения данных.
- Менеджер сущностей должен заботиться о постоянстве и обеспечении целостности.
- Контроллер предназначен для организации одного «действия», которое может включать добавление одной компании, редактирование одной компании, пакетный импорт / обновление многих компаний.
- Услуги могут быть реализованы, когда действия становятся тяжелыми для бизнес-логики или когда функциональность повторяется.
(Примечание: следующие примеры кода можно сделать более элегантным с использованием всех функций, которые предоставляет Symfony, таких как ParamConverters, компонент Form, компонент Validation, я обычно не пишу такой код кстати, но я полагаю, что все остальное пошло бы слишком далеко - без обид.)
обработка действий в контроллере
Действия контроллера (или сервисные действия, на самом деле) - это когда вы смотрите на свою проблему с точки зрения задачи. Как «Я хочу обновить этот объект с этими данными»). Вот когда вы получаете / создаете этот объект, а затем передаете ему данные.
use Doctrine\ORM\EntityManagerInterface;
class BaseController extends Controller {
public function __construct(EntityManagerInterface $em) {
$this->em = $em;
}
public function addAction() {
$company = new Company(['name' => '1234']); // initial setting in constructor
$this->em->persist($company);
// since you have the object, you can do any changes to it.
// just change the object
$company->update(['name' => 'abcd']); // <-- don't need id
// updates will be flushed as well!
$this->em->flush();
}
public function editAction($id, $newData) {
$company = $this->em->find(Company::class, $id);
if(!$company) {
throw $this->createNotFoundException();
}
$company->update($newData);
$this->em->flush();
}
// $companiesData should be an array of arrays, each containing
// a company with an id for update, or without an id for creation
public function batchAction(array $companiesData) {
foreach($companies as $companyData) {
if($companyData['id']) {
// has id -> update existing company
$company = $this->em->find(Company::class, $companyData['id']);
//// optional:
// if(!$company) { // id was given, but company does not exist
// continue; // skip
// // OR
// $company = new Company($companyData); // create
// // OR
// throw new \Exception('company not found: '.$companyData['id']);
// }
$company->update($companyData);
} else {
// no id -> create new company
$company = new Company($companyData);
$this->em->persist($company);
}
}
$this->em->flush(); // one flush.
}
}
базовый контроллер должен обрабатывать создание объектов и их сохранение, поэтому очень простая бизнес-логика. некоторые утверждают, что некоторые из этих операций должны выполняться в адаптированном репозитории для этого класса или инкапсулироваться в службу. И они были бы правы, как правило.
сущность обрабатывает свое внутреннее состояние
Теперь класс Company
обрабатывает свои собственные свойства и пытается оставаться согласованным. Вы просто имеете , чтобы сделать некоторые предположения здесь. Прежде всего: сам объект не должен заботиться о том, существует он в базе данных или нет. это не его цель! он должен справиться сам. Разделение проблем! Функции внутри компании должны относиться к простой бизнес-логике, которая касается ее ВНУТРЕННЕГО состояния. Он не нуждается в базе данных и не должен иметь никаких ссылок на базу данных, он заботится только о своих полях.
class Company {
/**
* all the database fields as public $fieldname;
*/
// ...
/**
* constructor for the inital state. You should never want
* an inconsistent state!
*/
public function __construct(array $data=[]) {
$this->validate($data); // set values
if(empty($this->createAt)) {
$this->createAt = new \DateTime();
}
}
/**
* update the data
*/
public function update(array $data) {
$this->validate($data); // set new values
$this->updateAt = new \DateTime();
}
public function validate(array $data) {
// this is simplified, but you can also validate
// here and throw exceptions and stuff
foreach($array as $key => $value) {
$this->$key = $value;
}
}
}
некоторые заметки
Теперь не должно быть НИКАКОГО варианта использования, когда вы получаете объект для сохранения и в то же время обновление - с идентификатором - которое ссылается на новый объект ... если только этому объекту не был заранее присвоен идентификатор! ТЕМ НЕ МЕНИЕ. Если вы сохраняете объект с идентификатором и вызываете $this->em->find(Company::class, $id)
, вы получите этот объект обратно.
Если у вас много отношений, всегда хороших способов решить эту проблему, не разрушая разделения интересов! Вы никогда не должны внедрять менеджер сущностей в сущность. сущность не должна управлять собственной настойчивостью! и при этом это не должно управлять постоянством связанных объектов. Постоянство обработки является целью менеджера сущностей или хранилища сущностей. вам никогда не понадобится обертка вокруг объекта, просто чтобы обработать этот объект. будьте осторожны, чтобы не перепутать обязанности служб, сущностей (объектов) и контролеров. В моем примере кода я объединил службы и контроллеры, потому что в простых случаях этого достаточно.