Skip to content

Commit

Permalink
Mapper TextControl
Browse files Browse the repository at this point in the history
  • Loading branch information
pepakriz committed Oct 25, 2014
1 parent b8bc644 commit 4629661
Showing 1 changed file with 116 additions and 23 deletions.
139 changes: 116 additions & 23 deletions src/System/Forms/DoctrineForms/Controls/TextControl.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,17 @@
namespace Venne\System\Forms\DoctrineForms\Controls;

use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\PersistentCollection;
use Kdyby\DoctrineForms\EntityFormMapper;
use Nette\ComponentModel\Component;
use Nette\Forms\Controls\BaseControl;
use Nette\Forms\Controls\RadioList;
use Nette\Forms\Controls\SelectBox;

/**
* @author Josef Kříž <[email protected]>
*/
class TextControl extends \Kdyby\DoctrineForms\Controls\TextControl
class TextControl extends \Nette\Object implements \Kdyby\DoctrineForms\IComponentMapper
{

/** @var \Kdyby\DoctrineForms\EntityFormMapper */
Expand All @@ -31,13 +34,8 @@ class TextControl extends \Kdyby\DoctrineForms\Controls\TextControl
/** @var \Doctrine\ORM\EntityManager */
private $entityManager;

public function __construct()
{
}

public function setEntityFormMapper(EntityFormMapper $mapper)
{
parent::__construct($mapper);
$this->mapper = $mapper;
$this->entityManager = $this->mapper->getEntityManager();
$this->accessor = $mapper->getAccessor();
Expand All @@ -46,53 +44,148 @@ public function setEntityFormMapper(EntityFormMapper $mapper)
/**
* @param \Doctrine\ORM\Mapping\ClassMetadata $meta
* @param \Nette\ComponentModel\Component $component
* @param object $entity
* @param mixed $entity
* @return boolean
*/
public function load(ClassMetadata $meta, Component $component, $entity)
{
if (parent::load($meta, $component, $entity)) {
if (!$component instanceof BaseControl) {
return false;
}

if ($meta->hasField($name = $component->getOption(self::FIELD_NAME, $component->getName()))) {
$component->setValue($this->accessor->getValue($entity, $name));

return true;
}

if (!$component instanceof BaseControl) {
if (!$meta->hasAssociation($name)) {
return false;
}

$name = $component->getOption(self::FIELD_NAME, $component->getName());

try {
$value = $this->accessor->getValue($entity, $name);
$component->setValue($value);
} catch (\Exception $e) {
/** @var SelectBox|RadioList $component */
if (($component instanceof SelectBox || $component instanceof RadioList || $component instanceof \Nette\Forms\Controls\MultiChoiceControl) && !count($component->getItems())) {
if (!$nameKey = $component->getOption(self::ITEMS_TITLE, false)) {
$path = $component->lookupPath('Nette\Application\UI\Form');
throw new \Kdyby\DoctrineForms\InvalidStateException(
'Either specify items for ' . $path . ' yourself, or set the option Kdyby\DoctrineForms\IComponentMapper::ITEMS_TITLE ' .
'to choose field that will be used as title'
);
}

$criteria = $component->getOption(self::ITEMS_FILTER, array());
$orderBy = $component->getOption(self::ITEMS_ORDER, array());

$related = $this->relatedMetadata($entity, $name);
$items = $this->findPairs($related, $criteria, $orderBy, $nameKey);
$component->setItems($items);
}

if ($meta->isCollectionValuedAssociation($name)) {
$collection = $meta->getFieldValue($entity, $name);
if ($collection instanceof PersistentCollection) {
$values = array();
foreach ($collection as $value) {
$values[] = $value->getId();
}
$component->setDefaultValue($values);
}

} elseif ($relation = $this->accessor->getValue($entity, $name)) {
$UoW = $this->entityManager->getUnitOfWork();
$component->setValue($UoW->getSingleIdentifierValue($relation));
}

return true;
}

/**
* @param string|object $entity
* @param string $relationName
* @return ClassMetadata|Kdyby\Doctrine\Mapping\ClassMetadata
*/
private function relatedMetadata($entity, $relationName)
{
$meta = $this->entityManager->getClassMetadata(is_object($entity) ? get_class($entity) : $entity);
$targetClass = $meta->getAssociationTargetClass($relationName);

return $this->entityManager->getClassMetadata($targetClass);
}

/**
* @param ClassMetadata $meta
* @param array $criteria
* @param array $orderBy
* @param string|callable $nameKey
* @return array
*/
private function findPairs(ClassMetadata $meta, $criteria, $orderBy, $nameKey)
{
$repository = $this->entityManager->getRepository($meta->getName());

if ($repository instanceof Kdyby\Doctrine\EntityDao && !is_callable($nameKey)) {
return $repository->findPairs($criteria, $nameKey, $orderBy);
}

$items = array();
$idKey = $meta->getSingleIdentifierFieldName();
foreach ($repository->findBy($criteria, $orderBy) as $entity) {
$items[$this->accessor->getValue($entity, $idKey)] = is_callable($nameKey)
? \Nette\Utils\Callback::invoke($nameKey, $entity)
: $this->accessor->getValue($entity, $nameKey);
}

return $items;
}

/**
* @param \Doctrine\ORM\Mapping\ClassMetadata $meta
* @param \Nette\ComponentModel\Component $component
* @param object $entity
* @param mixed $entity
* @return boolean
*/
public function save(ClassMetadata $meta, Component $component, $entity)
{
if (parent::save($meta, $component, $entity)) {
if (!$component instanceof BaseControl) {
return false;
}

if ($meta->hasField($name = $component->getOption(self::FIELD_NAME, $component->getName()))) {
$this->accessor->setValue($entity, $name, $component->getValue());

return true;
}

if (!$component instanceof BaseControl) {
if (!$meta->hasAssociation($name)) {
return false;
}

$name = $component->getOption(self::FIELD_NAME, $component->getName());

try {
$this->accessor->setValue($entity, $name, $component->getValue());
} catch (\Exception $e) {
$identifier = $component->getValue();
if (!$identifier && !is_array($identifier)) {
return false;
}

$entityClass = $this->relatedMetadata($entity, $name)->getName();
$repository = $this->entityManager->getRepository($entityClass);

if ($meta->isCollectionValuedAssociation($name)) {
$property = \Doctrine\Common\Util\Inflector::singularize($name);
foreach ($repository->findAll() as $associatedEntity) {
if (in_array($associatedEntity->id, $identifier)) {
$hasMethod = 'has' . ucfirst($property);
if (!$entity->$hasMethod($associatedEntity)) {
$addMethod = 'add' . ucfirst($property);
$entity->$addMethod($associatedEntity);
}

} else {
$removeMethod = 'remove' . ucfirst($property);
$entity->$removeMethod($associatedEntity);
}
}

} elseif ($relation = $repository->find($identifier)) {
$meta->setFieldValue($entity, $name, $relation);
}

return true;
Expand Down

0 comments on commit 4629661

Please sign in to comment.