Architektura aplikace nad Doctrine 2
Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.

- Pan Dobrman
 - Člen | 45
 
Po přečtení tohoto článku jsem se rozhodl, že se pokusím vytvořit web pomocí Doctrine 2. Nejsem si ale jistý, jestli jsem architekturu z článku pochopil správně, takže by jsem byl rád, pokud by mi zde někdo zkontroloval můj výtvor (jedná se o registraci uživatelů).
Entita
<?php
use \Doctrine\ORM\Mapping as ORM,
	\Nette\Object;
/**
 * @ORM\entity(repositoryClass="UsersRepository")
 * @ORM\table(name="users")
 */
class Users extends Object
{
	/**
	 * @ORM\id
	 * @ORM\column(type="integer", length=11)
	 * @ORM\generatedValue
	 */
	private $id;
	/**
	 * @ORM\column(type="string", length=32, unique=true)
	 */
	private $username;
	/**
	 * @ORM\column(type="string", columnDefinition="CHAR(128)")
	 */
	private $password;
	public function getId()
	{
		return $this->id;
	}
	public function getUsername()
	{
		return $this->username;
	}
	public function setUsername($value)
	{
		$this->username = $value;
		return $this;
	}
	public function getPassword()
	{
		return $this->password;
	}
	public function setPassword($value)
	{
		$this->password = $value;
		return $this;
	}
}
?>
Service
<?php
use \Nette\Object;
class UserService extends Object
{
	public function calculateHash($password, $salt = null)
	{
		return hash('sha512', $password . $salt);
	}
}
?>
Facade
<?php
use \Nette\Object,
    \Doctrine\ORM\EntityManager;
class RegisterFacade extends Object
{
	private $entityManager;
	private $userService;
	private $users;
	public function __construct(EntityManager $entityManager, \UserService $userService)
	{
		$this->entityManager = $entityManager;
		$this->userService = $userService;
		$this->users = new Users;
	}
	public function saveUser(array $data)
	{
		if($this->entityManager->getRepository('Users')->findOneByUsername($data['username']))
		{
			throw new \BadUsernameException;
		}
		$this->users->setUsername($data['username'])
			    ->setPassword($this->userService->calculateHash($data['password']));
		$this->entityManager->persist($this->users);
		$this->entityManager->flush();
		return $this->users;
	}
}
?>
Config.neon
	services:
		database: @doctrine.entityManagers.default
		register: RegisterFacade(@database, @userService)
		userService: UserService
Pár otázek:
- Facade má být service nebo factory?
 - Je chytré kontrolovat zda uživatel existuje tím, že vytáhnu z databáze všechny uživatele se stejným jménem, které zadal uživatel a pokud někoho naleznu, tak vyhodím výjimku (tu poté odchytávám v komponentě)?
 - Jak mohu generovat proxy třídy?
 
Omlouvám se za tak dlouhý příspěvek a všem předem děkuji za odpovědi.

- Filip Procházka
 - Moderator | 4668
 
Takže pár drobností – pokud chceš dělat OOP, musíš především co nejlépe (logicky) pojmenovávat třídy.
Users→UserUserService→PasswordGenerator(service nemusí být v názvu service)RegisterFacade::saveUser()→RegisterFacade::registerUser()
Nastuduj si autowiring
services:
        registerFacade: RegisterFacade()
        passwordGenerator: PasswordGenerator()
Je dobré používat konstruktor v entitách
class User extends Nette\Object
{
	// ...
	public function __construct($username)
	{
		$this->username = $username;
	}
        // ...
}
Je sice pravděpodobné, že budeš uživatele vytvářet max 1 za http request, ale není dobré se na to spoléhat.
class RegisterFacade extends Object
{
        private $entityManager;
        public function __construct(EntityManager $entityManager)
        {
                $this->entityManager = $entityManager;
        }
	private function isUsernameTaken()
	{
		// Téhle metodě by bylo dobré v jiné třídě
		// a ani není moc vesele implementovaná,
		// ale chvíli ti bude stačit :)
		return (bool)$this->entityManager
			->getRepository('User')
			->findOneByUsername($data['username']);
	}
        public function registerUser(array $data)
        {
                if ($this->isUsernameTaken()) {
                        throw new \BadUsernameException;
                }
		$user = new User($data['username']);
                $user->password = $this->passwordGenerator->calculateHash($data['password']);
                $this->entityManager->persist($user);
                $this->entityManager->flush();
                return $user;
        }
}