16/09/2018 - SYMFONY
The whole purpose of this approach is to keep the logic in a as small classes as possible. It will allow us to maintain&refactor the code more easily because the classes will be smaller and help us to avoid creating a "God object". Technically one class will do one thing.
src/
├── Controller
│ └── CountryController.php
├── Entity
│ └── Country.php
├── Repository
│ ├── AbstractRepository.php
│ └── Country
│ └── Repository.php
└── Service
└── Country
├── Create.php
├── Delete.php
├── Read.php
└── Update.php
declare(strict_types=1);
namespace App\Controller;
use App\Service\Country\Read;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Component\HttpFoundation\JsonResponse;
/**
* @Route("/countries")
*/
class CountryController
{
private $read;
public function __construct(
Read $read
) {
$this->read = $read;
}
/**
* @Route("/{id}", methods="GET")
*/
public function getOne(int $id): JsonResponse
{
$result = $this->read->one($id);
return new JsonResponse($result);
}
/**
* @Route("", methods="GET")
*/
public function getAll(): JsonResponse
{
$result = $this->read->all();
return new JsonResponse($result);
}
// Create, Update and Delete endpoints go here
}
declare(strict_types=1);
namespace App\Service\Country;
use App\Repository\Country\Repository;
final class Create
{
private $repository;
public function __construct(Repository $repository)
{
$this->repository = $repository;
}
public function one(int $name): void
{
}
public function batch(iterable $data): void
{
}
}
declare(strict_types=1);
namespace App\Service\Country;
use App\Repository\Country\Repository;
final class Read
{
private $repository;
public function __construct(Repository $repository)
{
$this->repository = $repository;
}
public function one(int $id): iterable
{
return $this->repository->findOneById($id);
}
public function all(): iterable
{
return $this->repository->findAll();
}
}
declare(strict_types=1);
namespace App\Service\Country;
use App\Repository\Country\Repository;
final class Update
{
private $repository;
public function __construct(Repository $repository)
{
$this->repository = $repository;
}
public function one(int $name): void
{
}
public function batch(iterable $data): void
{
}
}
declare(strict_types=1);
namespace App\Service\Country;
use App\Repository\Country\Repository;
final class Delete
{
private $repository;
public function __construct(Repository $repository)
{
$this->repository = $repository;
}
public function one(int $name): void
{
}
}
declare(strict_types=1);
namespace App\Repository;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository;
abstract class AbstractRepository
{
private $entityManager;
private $entityName;
public function __construct(
EntityManagerInterface $entityManager,
string $entityName
) {
$this->entityManager = $entityManager;
$this->entityName = $entityName;
}
protected function getEntityManager(): EntityManagerInterface
{
return $this->entityManager;
}
protected function getRepository(): EntityRepository
{
return $this->entityManager->getRepository($this->entityName);
}
}
declare(strict_types=1);
namespace App\Repository\Country;
use App\Entity\Country;
use App\Repository\AbstractRepository;
use Doctrine\ORM\EntityManagerInterface;
class Repository extends AbstractRepository
{
public function __construct(EntityManagerInterface $entityManager)
{
parent::__construct($entityManager, Country::class);
}
public function findAll(): iterable
{
return $this
->getRepository()
->createQueryBuilder('c')
->getQuery()
->getArrayResult();
}
public function findOneById(int $id): iterable
{
return $this
->getRepository()
->createQueryBuilder('c')
->where('c.id = :id')
->setParameter('id', $id)
->getQuery()
->getArrayResult();
}
}