More recently, I have been working with Symfony (a little over a year) and in all the projects that I had a chance to work on, entities were always created in such a way that they contained only private fields and bare setters / getters for them.
There will be arguments and examples in the articles why such an approach is dangerous, namely: it violates our good old encapsulation, provokes writing code with bugs and increasing the complexity of the system.
The article will omit the topic of setters in various builders and the topic of dependency injection through setters (Iโll just say that we do not approve). There will be nothing about complex topics like DDD, Rich Model, about coupling / cohesion and other smart words - just talk about encapsulation. Welcome to cat.
Go to the code. Let's omit for a second the typehint and the type return indication and think about how, when working with an object, this code differs from a utilitarian point of view:
$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.github.io/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), /. โ - ( , ).
, โ :)
. โ .