Baru-baru ini, saya telah bekerja dengan Symfony (sedikit lebih dari setahun) dan di semua proyek yang saya punya kesempatan untuk dikerjakan - entitas selalu dibuat sedemikian rupa sehingga mereka hanya berisi bidang pribadi dan setter / getter telanjang untuk mereka.
Artikel-artikel tersebut akan membahas dan memberikan contoh mengapa pendekatan ini berbahaya, yaitu: itu melanggar enkapsulasi lama kami yang baik, memprovokasi penulisan kode dengan bug dan meningkatkan kompleksitas sistem.
Artikel ini akan menghilangkan topik setter di berbagai pembangun dan topik injeksi ketergantungan melalui setter (saya hanya akan mengatakan bahwa kami tidak menyetujui). Tidak akan ada topik rumit seperti DDD, Rich Model, tentang coupling / kohesi dan kata-kata pintar lainnya - hanya berbicara tentang enkapsulasi. Selamat datang di kucing.
Buka kode. Mari kita hilangkan sejenak petunjuk tip dan tip tipe dan pikirkan bagaimana, ketika bekerja dengan suatu objek, kode berikut berbeda dari sudut pandang utilitarian:
$userName = $user->name;
$user->name = $newUserName;
:
$userName = $user->getName();
$user->setName($newUserName);
, , .
C . โ , .
? , , . , , , .
ยซยป , :
class Order
{
private const STATUS_OPEN = 'open';
private const STATUS_DELIVERED = 'delivered';
private ProductCollection $products;
private string $deliveryStatus;
private ?DateTime $deliveryDate = null;
public function deliver()
{
if ($this->isDelivered()) {
throw new OrderDomainException('Order already delivered.');
}
$this->deliveryDate = new DateTime();
$this->deliveryStatus = self::STATUS_DELIVERED;
}
private function isDelivered(): bool
{
return $this->deliveryStatus === self::STATUS_DELIVERED;
}
//
}
ยซ ยป - ? ? โ ? . โ , , . (cohesion).
:
class Order
{
private const STATUS_OPEN = 'open';
private const STATUS_DELIVERED = 'delivered';
private ProductCollection $products;
private string $deliveryStatus;
private ?DateTime $deliveryDate = null;
public function getDeliveryStatus(): string
{
return $this->deliveryStatus;
}
public function setDeliveryStatus(string $deliveryStatus): void
{
$this->deliveryStatus = $deliveryStatus;
}
public function getDeliveryDate(): ?DateTime
{
return $this->deliveryDate;
}
public function setDeliveryDate(?DateTime $deliveryDate): void
{
$this->deliveryDate = $deliveryDate;
}
public function getProducts(): ProductCollection
{
return $this->products;
}
public function setProducts(ProductCollection $products): void
{
$this->products = $products;
}
}
? ( ). โ , , , , ? , ? . โ , โ . . . , โ ?
,
. โ , .
โ , , , , , .
. :
/**
* @ORM\Entity
*/
class Project
{
/**
* @var Id
* @ORM\GeneratedValue()
* @ORM\Id
*/
private $id;
/**
* @var string
* @ORM\Column(type="string")
*/
private $name;
/**
* @var string
* @ORM\Column(type="string", nullable=false)
*/
private $status;
/**
* @var int
* @ORM\Column(type="integer", nullable=true)
*/
private $sort;
/**
* @var User
* @ORM\Column(type="user_type", nullable=false)
*/
private $user;
/**
* @var Department
* @ORM\OneToMany(targetEntity="Department")
*/
private $department;
/**
* @var string
* @ORM\Column(type="string", nullable=true)
*/
private $membership;
public function getId(): Id
{
return $this->id;
}
public function getName(): string
{
return $this->name;
}
public function setName(string $name): Project
{
$this->name = $name;
return $this;
}
public function getStatus(): string
{
return $this->status;
}
public function setStatus(string $status): Project
{
$this->status = $status;
return $this;
}
public function getSort(): int
{
return $this->sort;
}
public function setSort(int $sort): Project
{
$this->sort = $sort;
return $this;
}
public function getUser(): User
{
return $this->user;
}
public function setUser(User $user): Project
{
$this->user = $user;
return $this;
}
public function getDepartment(): Department
{
return $this->department;
}
public function setDepartment(Department $department): Project
{
$this->department = $department;
return $this;
}
public function getMembership(): string
{
return $this->membership;
}
public function setMembership(string $membership): Project
{
$this->membership = $membership;
return $this;
}
}
not nullable โ ( false). , โ not nullable , ? :)
, โ ( ). .
, Doctrine ( ) , Reflection API. Marco Pivetta , :
ocramius.imtqy.com/blog/doctrine-orm-optimization-hydration. .
,
, ( DTO, ..)., , - ยซยป . , , .
-. ID, โ :
$order = $this->orderRepository->find($orderId);
if ($order === null) {
throw new OrderException('Order not found.');
}
if ($order->getStatus() === Order::STATUS_ACTIVE
&& $order->getDeliveryDate() <= $date
) {
$this->orderDeliveryService->handle($order);
}
โ , :
$order = $this->orderRepository->find($orderId);
$cityFreeLimit = $this->cityOrderService->getCityFreeLimit($cityName);
if ($order->getCity() === $cityName
&& $order->getTotalPrice() > $cityFreeLimit
) {
$delivery = 0;
$this->orderDeliveryService->deliveryOrder($order, $delivery);
return;
}
//
, - .
, - . , , , . , , , . ยซยป ยซยป.
/ , , , , ยซ ยป , โ , , .
โ Symfony (DAO), /. โ - ( , ).
, โ :)
. โ .