In his publication describing CUPID principles, Dan North begins with the question, "If I do not think the SOLID principles are useful these days, then what would I replace them with?". This got me thinking about what I think of SOLID and how I look at it. In my presentation, I would like to break down this acronym into its components, test its usefulness with examples (based on a Symfony-based app), and consider what we can take from it. I will also try to answer the question posed in the title of the presentation.
23. @lukaszchrusciel
public function __invoke(string $orderNumber, int $unitId, int $amount,
RefundTypeInterface $refundType): void
{
/** @var OrderInterface|null $order */
$order = $this->orderRepository->findOneByNumber($orderNumber);
Assert::notNull($order);
$remainingTotal = $this->remainingTotalProvider->getTotalLeftToRefund($unitId,
$refundType);
if ($remainingTotal === 0) {
throw UnitAlreadyRefunded::withIdAndOrderNumber($unitId, $orderNumber);
}
$refund = $this->refundFactory->createWithData($order, $unitId, $amount,
$refundType);
$this->refundManager->persist($refund);
$this->refundManager->flush();
}
24. @lukaszchrusciel
Communication outside of the local scope
Communication outside of the local scope
public function __invoke(string $orderNumber, int $unitId, int $amount, RefundTypeInterface
$refundType): void
{
$order = $this->orderRepository->findOneByNumber($orderNumber);
$remainingTotal = $this->remainingTotalProvider->getTotalLeftToRefund($unitId, $refundType);
if ($remainingTotal === 0) {
throw UnitAlreadyRefunded::withIdAndOrderNumber($unitId, $orderNumber);
}
$refund = $this->refundFactory->createWithData(
$order,
$unitId,
$amount,
$refundType
);
$this->refundManager->persist($refund);
$this->refundManager->flush();
}
25. @lukaszchrusciel
Communication outside of the local scope
Communication outside of the local scope
public function __invoke(string $orderNumber, int $unitId, int $amount, RefundTypeInterface
$refundType): void
{
$order = $this->orderRepository->findOneByNumber($orderNumber);
$remainingTotal = $this->remainingTotalProvider->getTotalLeftToRefund($unitId, $refundType);
if ($remainingTotal === 0) {
throw UnitAlreadyRefunded::withIdAndOrderNumber($unitId, $orderNumber);
}
$refund = $this->refundFactory->createWithData(
$order,
$unitId,
$amount,
$refundType
);
return $refund;
}
38. @lukaszchrusciel
Covariance
Covariance
abstract class Animal
{
}
class Cat extends Animal
{
}
interface AnimalShelter
{
public function adopt(): Animal;
}
class CatShelter implements AnimalShelter
{
public function adopt(): Cat // instead of returning class type Animal, it can return class type Cat
{
return new Cat();
}
}
39. @lukaszchrusciel
abstract class Animal
{
}
class Cat extends Animal
{
}
interface CatShelter
{
public function adopt(Cat $cat);
}
class AnimalShelter implements CatShelter
{
public function adopt(Animal $animal) // instead of accepting class type Cat, it can
accept any Animal
{
return new Cat();
}
}
40. @lukaszchrusciel
abstract class Animal
{
}
class Cat extends Animal
{
}
interface CatShelter
{
public function adopt(Animal $cat);
}
class AnimalShelter implements CatShelter
{
public function adopt(Cat $animal) // instead of accepting class type Cat, it can accept any Animal
{
return new Cat();
}
}
Fatal error: Declaration of AnimalShelter::adopt(Cat $animal) must be compatible with
CatShelter::adopt(Animal $cat) in /tmp/preview on line 19
42. @lukaszchrusciel
final class PerUnitRateCalculator implements CalculatorInterface
{
public function calculate(ShipmentInterface $subject, array
$configuration): int
{
return (int) ($configuration['amount'] * $subject-
>getShippingUnitCount());
}
public function getType(): string
{
return 'per_unit_rate';
}
}
43. @lukaszchrusciel
{
/**
* @param array{'amount': int}
$configuration
*/
public function calculate(ShipmentInterface
$subject, array $configuration): int;
public function getType(): string;
}
49. @lukaszchrusciel
interface OrderRepositoryInterface extends BaseOrderRepositoryInterface
{
public function createListQueryBuilder(): QueryBuilder;
public function createSearchListQueryBuilder(): QueryBuilder;
public function createByCustomerIdQueryBuilder($customerId): QueryBuilder;
public function createByCustomerAndChannelIdQueryBuilder($customerId, $channelId): QueryBuilder;
public function countByCustomerAndCoupon(CustomerInterface $customer, PromotionCouponInterface $coupon): int;
public function countByCustomer(CustomerInterface $customer): int;
public function findOrderById($id): ?OrderInterface;
public function findByCustomer(CustomerInterface $customer): array;
public function findForCustomerStatistics(CustomerInterface $customer): array;
public function findOneForPayment($id): ?OrderInterface;
public function findOneByNumberAndCustomer(string $number, CustomerInterface $customer): ?OrderInterface;
public function findCartByChannel($id, ChannelInterface $channel): ?OrderInterface;
public function findLatestCartByChannelAndCustomer(ChannelInterface $channel, CustomerInterface $customer): ?OrderInterface;
public function findLatestNotEmptyCartByChannelAndCustomer(ChannelInterface $channel, CustomerInterface $customer): ?OrderInterface;
public function getTotalSalesForChannel(ChannelInterface $channel): int;
public function getTotalPaidSalesForChannel(ChannelInterface $channel): int;
public function getTotalPaidSalesForChannelInPeriod(ChannelInterface $channel, DateTimeInterface $startDate, DateTimeInterface $endDate): int;
public function countFulfilledByChannel(ChannelInterface $channel): int;
public function countPaidByChannel(ChannelInterface $channel): int;
public function countPaidForChannelInPeriod(ChannelInterface $channel, DateTimeInterface $startDate, DateTimeInterface $endDate): int;
public function findLatestInChannel(int $count, ChannelInterface $channel): array;
public function findOrdersUnpaidSince(DateTimeInterface $terminalDate, ?int $limit = null): array;
public function findCartForSummary($id): ?OrderInterface;
public function findCartForAddressing($id): ?OrderInterface;
public function findCartForSelectingShipping($id): ?OrderInterface;
public function findCartForSelectingPayment($id): ?OrderInterface;
public function findCartByTokenValue(string $tokenValue): ?BaseOrderInterface;
public function findCartByTokenValueAndChannel(string $tokenValue, ChannelInterface $channel): ?BaseOrderInterface;
}
72. @lukaszchrusciel
Takeaways
Takeaways If you see clickbait title with
If you see clickbait title with
question in it
question in it
Then the answer is always no
no
Functional programming may
Functional programming may
help us
help us
Deliver better ObjectOriented code
SOLID is a solid fundament for
SOLID is a solid fundament for
packages that will be reused by
packages that will be reused by
other devs
other devs
But end applications may benefit from it as well
Doing eCommerce? Give a
Doing eCommerce? Give a
Sylius try ;)
Sylius try ;)
Don't be discouraged by this presentation