Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Divide and Conquer (LonghornPHP 2019)

Divide and Conquer (LonghornPHP 2019)

Andreas Hucks

May 04, 2019
Tweet

More Decks by Andreas Hucks

Other Decks in Programming

Transcript

  1. /**
 * @Route(path="/", name="list")
 */
 public function index()
 {
 $robots

    = $this
 ->getDoctrine()
 ->getRepository(Robot::class)
 ->findAll()
 ;
 
 return $this->render(
 'robot/index.html.twig',
 [
 'robots' => $robots
 ]
 );
 }
  2. /**
 * @Route(path="/{id}", name="edit")
 */
 public function edit(Request $request, Robot

    $robot)
 {
 $form = $this->createForm(RobotType::class, $robot);
 $form->handleRequest($request);
 
 if ($form->isSubmitted() && $form->isValid()) {
 $this->getDoctrine()->getManager()->flush();
 
 return $this->redirectToRoute('list');
 }
  3. /**
 * @ORM\Entity(repositoryClass="…")
 * @ORM\Table(name="robots")
 */
 class Robot
 {
 public

    static $propusionTypes = [
 'legs' => 'Can walk',
 'wheels' => 'Drives',
 'tracks' => 'Tracked Vehicle',
 'jetpack' => 'Hovers',
 'weird' => 'Why would you build that'
 ];
 
 /**
 * @ORM\Column(type=“integer")
 * @ORM\Id()
 * @ORM\GeneratedValue()
 */
 private $id;
  4. namespace App\Entity;
 
 use Doctrine\ORM\Mapping as ORM;
 use Symfony\Component\Security\Core\User\UserInterface;
 use

    Symfony\Component\Validator\Constraints as Assert;
 
 /**
 * @ORM\Entity()
 * @ORM\Table(name="mechanics")
 */
 class Mechanic implements UserInterface
 {
 // …
  5. Dependencies of your Code • to Validator • to Doctrine

    • to Security Layer • To the FrameworkBundle
  6. Clean Layers • Separate your business code from your framework

    • … or in fact, any other 3rd party libs • Separate your own layers/packages (Domain, Application, Infrastructure…)
  7. Domain\Entity\Robot:
 type: entity
 table: robots
 repositoryClass: Domain\Repository\RobotRepository
 id:
 id:
 type:

    uuid
 length: 255
 fields:
 name:
 type: string
 length: 255
 nullable: false
 […]
 embedded:
 propulsion:
 class: Domain\Entity\Data\Propulsion
 columnPrefix: false
  8. public function __construct($value)
 {
 $propulsion = (string) $value;
 
 if

    (!in_array($propulsion, array_keys(self::$propusions))) {
 throw new Exception('Invalid key');
 }
 
 $this->propulsion = $propulsion;
 }
  9. class Id
 {
 private $key;
 
 public function __construct($key)
 {


    $this->key = (string) $key;
 }
 
 public function getKey()
 {
 return $this->key;
 }
  10. 
 class Uuid extends Type
 {
 public function convertToDatabaseValue($value, AbstractPlatform

    $platform)
 {
 if (empty($value)) {
 return null;
 }
 
 if ($value instanceof Id) {
 return $value->getKey();
 }
 
 return null;
 }
 
 
 
 public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
 {
 return 'VARCHAR(255) COMMENT \'(DC2Type:uuid)\'';
 }
 
 public function getName()
 {
 return 'uuid';
 }
 }
  11. layers: - name: Application collectors: - type: className regex: ^App\\Controller\\.*|App\\Form\\.*|\\App\\Kernel

    - name: Domain collectors: - type: className regex: ^App\\Domain\\.* - name: Framework collectors: - type: className regex: ^Symfony\\|Doctrine\\.* ruleset: Application: - Domain - Framework Application: - Domain
  12. namespace App\Infrastructure\Doctrine\Repository;
 
 use Doctrine\ORM\EntityRepository;
 use Domain\Entity\Data\Id;
 use Domain\Entity\Robot;
 use

    Domain\Repository\RobotRepository as RepositoryInterface; class RobotRepository extends EntityRepository implements RepositoryInterface
 {
 public function get(Id $id)
 {
 return $this->findOneBy(['id' => $id]);
 }
 
 public function add(Robot $robot)
 {
 $this->_em->persist($robot);
 $this->_em->flush($robot);
 }
 }
  13. namespace App\Domain\Entity;
 
 use Doctrine\ORM\Mapping as ORM;
 use Symfony\Component\Security\Core\User\UserInterface;
 use

    Symfony\Component\Validator\Constraints as Assert;
 
 /**
 * @ORM\Entity()
 * @ORM\Table(name="mechanics")
 */
 class Mechanic implements UserInterface
 {
 // …
  14. 
 interface UserProviderInterface
 {
 public function loadUserByUsername($username);
 
 public function

    refreshUser(UserInterface $user);
 
 public function supportsClass($class);
 }

  15. class MechanicAccount implements UserInterface
 {
 private $mechanicId;
 private $username;
 private

    $password;
 
 public static function fromMechanic(Mechanic $mechanic)
 {
 $account = new static();
 
 $account->mechanicId = $mechanic->getId();
 $account->username = $mechanic->getEmail();
 $account->password = $mechanic->getPassword();
 
 return $account;
 }
  16. public function loadUserByUsername($username)
 {
 $mechanic = $this->repository
 ->findOneBy(['email' => new

    Email($username)]);
 
 if (null === $mechanic) {
 throw new UsernameNotFoundException( 'User does not exist.' );
 }
 
 return MechanicAccount::fromMechanic($mechanic);
 }