Skip to content

Instantly share code, notes, and snippets.

@Ocramius
Created July 15, 2011 16:14
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Ocramius/1084994 to your computer and use it in GitHub Desktop.
Save Ocramius/1084994 to your computer and use it in GitHub Desktop.
A sample integration of Doctrine 2 and Zend_Form
<?php
namespace Deneb\Form;
/**
* Manages scalar fields of an entity
*/
class Entity extends ListDecorated {
const DEFAULT_DISPLAY_GROUP = 'default';
/**
* @var \Deneb\Entity
*/
protected $_entity;
/**
* @var \Doctrine\ORM\EntityManager
*/
protected $_em;
/**
* @var \Doctrine\Common\Annotations\Reader
*/
protected $_annotationReader;
/**
* @var \Zend_Acl
*/
protected $_acl;
/**
* @var \Zend_Acl_Role_Interface
*/
protected $_role;
/**
* Weather to display/manage associations or not
* @var bool
*/
protected $_manageAssociations;
/**
*
* @var \Deneb\EntityRepository\Lock
*/
protected $_locksRepository;
public function __construct(
\Deneb\Entity $entity,
\Doctrine\ORM\EntityManager $em,
\Deneb\Annotation\Reader $annotationReader,
\Zend_Acl $acl,
\Zend_Acl_Role_Interface $role,
$manageAssociations = false
) {
$this->_entity = $entity;
$this->_em = $em;
$this->_annotationReader = $annotationReader;
$this->_acl = $acl;
$this->_role = $role;
$this->_manageAssociations = $manageAssociations;
$this->_locksRepository = $em->getRepository('Deneb\\Entity\\Lock');
$metadata = $this
->_em
->getMetadataFactory()
->getMetadataFor(\get_class($this->_entity));
//$fieldsWrapper = new \Zend_Form_SubForm();
//$fieldsWrapper->setLegend($this->_entity);
//$this->setLegend($this->_entity);
$displayGroupsElements = array();
$lockable = $this->_locksRepository->isLockable($this->_entity);
foreach($metadata->getColumnNames() as $columnName) {
$fieldName = $metadata->getFieldName($columnName);
/** Allowed ACL privileges are "read" and "write" */
$resource = $metadata->name . ':property:' . $fieldName;
$read = $this->_acl->isAllowed($this->_role, $resource, 'read');
$write = $this->_acl->isAllowed($this->_role, $resource, 'write');
if($read || $write) {
$typeOfColumn = $metadata->getTypeOfColumn($columnName);
switch($typeOfColumn) {
case \Doctrine\DBAL\Types\Type::BIGINT:
case \Doctrine\DBAL\Types\Type::INTEGER:
case \Doctrine\DBAL\Types\Type::SMALLINT:
$element = new \Deneb\Form\Element\Int($fieldName);
break;
case \Doctrine\DBAL\Types\Type::BOOLEAN:
$element = new \Zend_Form_Element_Checkbox($fieldName);
$element->addFilter(new \Zend_Filter_Boolean());
break;
case \Doctrine\DBAL\Types\Type::DATE:
$element = new \Deneb\Form\Element\Date(
$fieldName,
array('format' => \Zend_Date::DATE_LONG)
);
break;
case \Doctrine\DBAL\Types\Type::DATETIME:
case \Doctrine\DBAL\Types\Type::DATETIMETZ:
$element = new \Deneb\Form\Element\Date(
$fieldName,
array('format' => \Zend_Date::DATETIME_FULL)
);
break;
case \Doctrine\DBAL\Types\Type::DECIMAL:
$details = $metadata->getFieldMapping($fieldName);
$element = new \Deneb\Form\Element\Decimal(
$fieldName/*,
array(
'precision' => $details['precision'],
'scale' => $details['scale']
)*/
);
break;
case \Doctrine\DBAL\Types\Type::OBJECT:
//Just do not display object data type in forms
continue 2;
case \Doctrine\DBAL\Types\Type::TARRAY:
throw new \Zend_Form_Exception('Unsupported data type \'' . $metadata->getTypeOfColumn($columnName) . '\'');
break;
case \Doctrine\DBAL\Types\Type::STRING:
$element = new \Zend_Form_Element_Text($fieldName);
$fieldMapping = $metadata->getFieldMapping($fieldName);
$element->addValidator(new \Zend_Validate_StringLength(array('max' => $fieldMapping['length'])));
break;
case \Doctrine\DBAL\Types\Type::TEXT:
$element = new \Zend_Form_Element_Textarea($fieldName);
break;
case \Doctrine\DBAL\Types\Type::TIME:
$element = new \Deneb\Form\Element\Date(
$fieldName,
array('format' => \Zend_Date::TIME_FULL)
);
break;
default:
$type = \Doctrine\DBAL\Types\Type::getType($typeOfColumn);
if($type instanceof \Deneb\Mapping\Type\Enum) {
$element = new \Deneb\Form\Element\Enum(
$fieldName,
array('enumType' => $type)
);
}else if($type instanceof \Deneb\Mapping\Type\Document\File) {
$element = new \Deneb\Form\Element\File($fieldName);
}else if($type instanceof \Deneb\Mapping\Type\RichText) {
$element = new \Deneb\Form\Element\RichText($fieldName);
}else{
throw new \Zend_Form_Exception('Unsupported data type \'' . $typeOfColumn . '\'');
}
break;
}
$fieldMapping = $metadata->getFieldMapping($fieldName);
if($lockable) {
$locked = !$this
->_locksRepository
->isAllowed(
$this->_role,
$this->_entity,
$fieldName,
'lock'
);
if($locked) {
$element->setAttrib('disabled', 'disabled');
$element->setIgnore(true);
}
$ownlock = $this
->_locksRepository
->findLock($this->_role, $this->_entity, $fieldName, 'lock');
if($ownlock !== null) {
/** @todo this should be encapsulated within the form element class. Will require future refactoring */
$class = $element->getAttrib('class');
$element->setAttrib('class', ($class ? $class . ' ' : '') . 'locked');
}
if($this->_acl->isAllowed($this->_role, $resource, 'lock')) {
$element->setAttrib(
'data-lock-action',
\Zend_Controller_Action_HelperBroker::getStaticHelper('url')
->url(array(
'controller' => 'lock',
'action' => 'toggle',
'entity' => $metadata->name,
'identifier' => \reset($metadata->getIdentifierValues($this->_entity)),
'field' => $fieldName,
'privilege' => 'lock'
))
);
}
}
if(!($element instanceof \Zend_Form_Element_Checkbox)) {
if($write) {
if(
(
!$read
&& ($this->_entity->$fieldName === null)
) || !$fieldMapping['nullable']
) {
$element->setRequired();
}
if($fieldMapping['unique']) {
$element->setRequired();
$element->addValidator(new \Deneb\Validate\Entity\Field\Unique($this->_em, $this->_entity, $fieldName));
}
}else{
$element->setAttrib('disabled', 'disabled');
$element->setIgnore(true);
}
}
if(!$element->isRequired()) {
if($element instanceof \Deneb\Form\Element\Enum) {
$element->setMultiOptions(array(-1 => '') + $element->getMultiOptions());
}
}else{
/** @todo this should be encapsulated within the form element class. Will require future refactoring */
$class = $element->getAttrib('class');
$element->setAttrib('class', ($class ? $class . ' ' : '') . 'required');
}
if($read) {
$element->setValue($this->_entity->$fieldName);
}
$reflectionProperty = $metadata->getReflectionProperty($fieldName);
if($filter = $this->_annotationReader->getPropertyAnnotation($reflectionProperty, 'Deneb\\Annotation\\Filter')) {
$element->addFilter($filter);
}
if($validator = $this->_annotationReader->getPropertyAnnotation($reflectionProperty, 'Deneb\\Annotation\\Validate')) {
$element->addValidator($validator);
}
$element->setLabel($resource);
if($displayGroupAnnotation = $this->_annotationReader->getPropertyAnnotation($reflectionProperty, 'Deneb\\Annotation\\DisplayGroup')) {
$displayGroupName = (string) $displayGroupAnnotation;
}else{
$displayGroupName = self::DEFAULT_DISPLAY_GROUP;
}
if(!isset($displayGroupsElements[$displayGroupName])) {
$displayGroupsElements[$displayGroupName] = array();
}
if($displayPriority = $this->_annotationReader->getPropertyAnnotation($reflectionProperty, 'Deneb\\Annotation\\DisplayPriority')) {
$element->setOrder($displayPriority->value);
}
$displayGroupsElements[$displayGroupName][] = $element;
}
}
foreach($displayGroupsElements as $name => $elements) {
$this->addDisplayGroup(
$elements,
$name,
array(
//'legend' => $metadata->name . ':displaygroup:' . $name
)
);
}
//$this->addSubForm($fieldsWrapper, 'fields');
parent::__construct();
}
/**
* Assign data to the entity. Doesn't cause \Doctrine\ORM\EntityManager#flush()
*
* @warningThis works only for valid fields!
*
* @return \Deneb\Entity the persisted entity
*/
public function persistData() {
$fieldsWrapper = $this;
$metadata = $this->_em->getMetadataFactory()->getMetadataFor(get_class($this->_entity));
foreach($metadata->getColumnNames() as $columnName) {
$fieldName = $metadata->getFieldName($columnName);
$resource = $metadata->name . ':property:' . $fieldName;
$read = $this->_acl->isAllowed($this->_role, $resource, 'read');
$write = $this->_acl->isAllowed($this->_role, $resource, 'write');
$element = $fieldsWrapper->getElement($fieldName);
if($write && $element && $element->isValid($this->getValue($fieldName))) {
if($element instanceof \Deneb\Form\Element\Date) {
$value = $element->getDateTime();
}else if($element instanceof \Deneb\Form\Element\Decimal) {
$value = $element->getDecimal();
}else if($element instanceof \Deneb\Form\Element\Int) {
$value = $element->getInt();
}else if($element instanceof \Deneb\Form\Element\Enum) {
$value = $element->getEnum();
}else{
$value = $element->getValue();
}
//Not allowing writeable only fields to be replaced by empty values
//(i.e.: operator does not set password, which means overwriting password with null!)
if($read || ($value !== null)) {
$this->_entity->$fieldName = $value;
}
}
}
foreach($metadata->getColumnNames() as $columnName) {
$fieldName = $metadata->getFieldName($columnName);
$resource = $metadata->name . ':property:' . $fieldName;
$read = $this->_acl->isAllowed($this->_role, $resource, 'read');
$element = $fieldsWrapper->getElement($fieldName);
if($read && $element) {
$element->setValue($this->_entity->$fieldName);
}
}
return $this->_entity;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment