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
→User
UserService
→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;
}
}