3. Modularity
Our problems:
• Long development time
• Generic functionality in all projects
• Near identical operation of same features
• Hard maintainability
4. Modularity
What we need?
• Compatible components
• High reusability
• Exchangeable parts
• Configurable system
• Improved maintainability
5. High-level Modularity
We can
• Remove hard-coded class calls
• Turn Singletons into services
• Use dynamic table names for data layer
• Define keys for soft referencing
7. Soft References
Managers
• Handling references
• Lazy loading for performance and low-memory
profile
• Shared or own instances
• We can use cloning to prevent recurring
initializations
8. PHP Example
$user = new User;
!
// turns to
!
$user = clone $services->get(‘ModelUser’);
9. PHP Example
$path = Config::get(‘ViewPath’);
!
// turns to
!
$path = $services->get(‘MyConfig’)->get(‘ViewPath’);
11. A Simple Service Manager
public function get($name)
{
if (isset($this->instances[$name])
{
return $this->instances[$name];
}
if (isset($this->invokables[$name]))
{
$className = $this->invokables[$name];
if (class_exists($className))
{
$instance = new $className;
}
else
{
throw new Exception(‘Unknown class: ’ . $className);
}
}
12. A Simple Service Manager
else
if (isset($this->factories[$name])
{
$factory = $this->factories[$name];
if ($factory instanceof FactoryInterface)
{
$factory = array($factory, ‘createService’);
}
if (is_callable($factory)
{
$instance = call_user_func($factory, $this, $name);
}
else
{
throw new Exception(‘Wrong factory: ’ . $name);
}
}
13. A Simple Service Manager
else
{
throw new Exception(‘Unknown key: ’ . $name);
}
if ($instance)
{
$this->instances[$name] = $instance;
return $instance;
}
throw new Exception(‘No instance: ’ . $name);
}
15. Higher-level OOP
• Database engine independent
• Unknown “outside world”
• Focus (only) on own tasks
• An entity class holds the information and has its
related methods
21. Entity Class
abstract class Entity
{
protected $serviceLocator;
protected $storedPrimaryKey;
protected $table;
final public function getServiceLocator()
{
return $this->serviceLocator;
}
final public function getStoredPrimaryKey()
{
return $this->storedPrimaryKey;
}
final public function getTable()
{
return $this->table;
}
22. Entity Class
final public function setServiceLocator(Ser…ace $serviceLocator)
{
$this->serviceLocator = $serviceLocator;
return $this;
}
final public function setStoredPrimaryKey(array $storedPrimaryKey)
{
$this->storedPrimaryKey = $storedPrimaryKey;
return $this;
}
final public function setTable(Table $table)
{
$this->table = $table;
return $this;
}
23. Entity Class
public function delete()
{
if (!$this->storedPrimaryKey)
{
throw new Exception(‘Entity is not stored’);
}
$this->table->delete($this->storedPrimaryKey);
$this->storedPrimaryKey = array();
return $this;
}
abstract public function exchangeArray(array $data);
24. Entity Class
public function save()
{
$this->table->save($this);
$reloaded = $this->table->fetchAll($this->storedPrimaryKey)->current();
if ($reloaded)
{
$this->exchangeEntity($reloaded);
}
else
{
throw new Exception(‘Error on reload’);
}
}
}
25. Example: User Entity
class User extends Entity
{
protected $name;
protected $userID;
public function getName() {…}
public function getUserID() {…}
public function setName($name) {…}
public function setUserID($userID) {…}
.
.
.
26. Example: User Entity
public function exchangeArray(array $data)
{
$this->name = isset($data[‘name’]) ? $data[‘name’] : null;
$this->userID = isset($data[‘userID’]) ? $data[‘userID’] : null;
$this->storedPrimaryKey = array(‘userID’ => $this->userID);
return $this;
}
public function exchangeEntity(User $entity)
{
$this->name = $entity->name;
$this->userID = $entity->userID;
$this->storedPrimaryKey = $entity->storedPrimaryKey;
return $this;
}
27. Example: User Entity
public function exchangeArray(array $data)
{
$this->name = isset($data[‘name’]) ? $data[‘name’] : null;
$this->userID = isset($data[‘userID’]) ? $data[‘userID’] : null;
$this->storedPrimaryKey = array(‘userID’ => $this->userID);
return $this;
}
public function exchangeEntity(User $entity)
{
$this->name = $entity->name;
$this->userID = $entity->userID;
$this->storedPrimaryKey = $entity->storedPrimaryKey;
return $this;
}
Hydrator
28. Table Class
abstract class Table
{
protected $serviceLocator;
protected $tableGateway;
public function __construct(TableGateway $tableGateway)
{
$this->tableGateway = $tableGateway;
}
final public function getServiceLocator() {…}
final public function getTableGateway() {…}
final public function setServiceLocator(…tor) {…}
.
.
.
29. Table Class
public function delete($where)
{
$this->tableGateway->delete($where);
return $this;
}
final public function fetchAll($where = null)
{
return $this->tableGateway->select($where);
}
}
30. Example: User Table
class UserTable extends Table
{
public function save(User $entity)
{
$data = array(‘userID’ => $entity->getUserID(), ‘name’ => $entity->getName());
if ($entity->getStoredPrimaryKey())
{
$this->tableGateway->update($data, $entity->getStoredPrimaryKey());
}
else
{
$this->tableGateway->insert($data);
$data[‘userID’] = $this->tableGateway->getLastInsertValue();
}
$entity->setStoredPrimaryKey(array(‘userID’ => $data[‘userID’]));
}
31. Example: User Table
class UserTable extends Table
{
public function save(User $entity)
{
$data = array(‘userID’ => $entity->getUserID(), ‘name’ => $entity->getName());
if ($entity->getStoredPrimaryKey())
{
$this->tableGateway->update($data, $entity->getStoredPrimaryKey());
}
else
{
$this->tableGateway->insert($data);
$data[‘userID’] = $this->tableGateway->getLastInsertValue();
}
$entity->setStoredPrimaryKey(array(‘userID’ => $data[‘userID’]));
}
Hydrator
32. TableGateway Class
abstract class TableGateway extends AbstractTableGateway
{
protected $entityPrototype;
protected $serviceLocator;
public function __construct(Adapter $adapter, $table, $entityPrototype)
{
$this->adapter = $adapter;
$this->table = $table;
$this->entityPrototype = $entityPrototype;
$this->resultSetPrototype = new ResultSet;
$this->resultSetPrototype->setArrayObjectPrototype($entityPrototype);
$this->sql = new Sql($adapter, $table);
}
.
.
.
33. TableGateway Class
final public function getServiceLocator() {…}
final public function setServiceLocator(…) {…}
public function create()
{
return clone $this->entityPrototype;
}
}
35. Example: User - Group
Relation
class User extends Entity
{
.
.
.
protected $group;
public function getGroup()
{
if (!is_object($this->group) && !empty($this->group))
{
$this->group = $this->serviceLocator->get(‘ModelGroupTable’)
->fetchAll(array(‘groupID’ => $this->group))->current();
}
return $this->group;
}
36. Example: User - Group
Relation
public function getGroupID()
{
return is_object($this->group) ? $this->group->getGroupID() : $this->group;
}
public function setGroup($group) {…}
}
37. Summary
• Modules - maintainability, reusability
• Network of simpler components - complex system
• Entity-based - focus on information
• Layered Data Model - thinnest database engine related
layer, more portability