|
<?php |
|
|
|
/* |
|
* This file is part of the Symfony package. |
|
* |
|
* (c) Fabien Potencier <fabien@symfony.com> |
|
* |
|
* For the full copyright and license information, please view the LICENSE |
|
* file that was distributed with this source code. |
|
*/ |
|
|
|
namespace WouterJ\EloquentBundle\Form\Type; |
|
|
|
use WouterJ\EloquentBundle\Form\DataTransformer\EloquentTransformer; |
|
use WouterJ\EloquentBundle\Form\ChoiceList\EloquentChoiceLoader; |
|
use Illuminate\Database\Eloquent\Relations\BelongsTo; |
|
use Symfony\Component\Form\AbstractType; |
|
use Symfony\Component\Form\ChoiceList\Factory\ChoiceListFactoryInterface; |
|
use Symfony\Component\Form\ChoiceList\Factory\DefaultChoiceListFactory; |
|
use Symfony\Component\Form\ChoiceList\Factory\PropertyAccessDecorator; |
|
use Symfony\Component\Form\FormBuilderInterface; |
|
use Symfony\Component\OptionsResolver\Options; |
|
use Symfony\Component\OptionsResolver\OptionsResolver; |
|
use Symfony\Component\PropertyAccess\PropertyAccessorInterface; |
|
use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException; |
|
use Symfony\Component\OptionsResolver\Exception\MissingOptionsException; |
|
|
|
/** |
|
* ModelType class. |
|
* |
|
* @author William Durand <william.durand1@gmail.com> |
|
* @author Toni Uebernickel <tuebernickel@gmail.com> |
|
* @author Eduardo Ayres <eduardo@eduardoayres.com> |
|
* |
|
* Example using the preferred_choices option. |
|
* |
|
* <code> |
|
* public function buildForm(FormBuilderInterface $builder, array $options) |
|
* { |
|
* $builder |
|
* ->add('product', 'model', array( |
|
* 'class' => 'Model\Product', |
|
* 'query' => {{notImpl... internally using default all() query}}, |
|
* 'preferred_choices' => DB::table('product') |
|
* ->where('active', false)->get(); |
|
* , |
|
* )) |
|
* ; |
|
* } |
|
* </code> |
|
*/ |
|
class EloquentType extends AbstractType |
|
{ |
|
/** |
|
* @var ChoiceListFactoryInterface |
|
*/ |
|
private $choiceListFactory; |
|
|
|
/** |
|
* ModelType constructor. |
|
* |
|
* @param PropertyAccessorInterface|null $propertyAccessor |
|
* @param ChoiceListFactoryInterface|null $choiceListFactory |
|
*/ |
|
public function __construct(PropertyAccessorInterface $propertyAccessor = null, ChoiceListFactoryInterface $choiceListFactory = null) |
|
{ |
|
$this->choiceListFactory = $choiceListFactory ?: new PropertyAccessDecorator( |
|
new DefaultChoiceListFactory(), |
|
$propertyAccessor |
|
); |
|
} |
|
|
|
/** |
|
* Creates the label for a choice. |
|
* |
|
* For backwards compatibility, objects are cast to strings by default. |
|
* |
|
* @param object $choice The object. |
|
* |
|
* @return string The string representation of the object. |
|
* |
|
* @internal This method is public to be usable as callback. It should not |
|
* be used in user code. |
|
*/ |
|
public static function createChoiceLabel($choice) |
|
{ |
|
return (string) $choice; |
|
} |
|
|
|
/** |
|
* Creates the field name for a choice. |
|
* |
|
* This method is used to generate field names if the underlying object has |
|
* a single-column integer ID. In that case, the value of the field is |
|
* the ID of the object. That ID is also used as field name. |
|
* |
|
* @param object $choice The object. |
|
* @param int|string $key The choice key. |
|
* @param string $value The choice value. Corresponds to the object's |
|
* ID here. |
|
* |
|
* @return string The field name. |
|
* |
|
* @internal This method is public to be usable as callback. It should not |
|
* be used in user code. |
|
*/ |
|
public static function createChoiceName($choice, $key, $value) |
|
{ |
|
return str_replace('-', '_', (string) $value); |
|
} |
|
|
|
/** |
|
* {@inheritDoc} |
|
*/ |
|
public function buildForm(FormBuilderInterface $builder, array $options) |
|
{ |
|
if ($options['multiple']) { |
|
$builder |
|
->addViewTransformer(new EloquentTransformer(), true) |
|
; |
|
} |
|
} |
|
|
|
/** |
|
* {@inheritDoc} |
|
*/ |
|
public function configureOptions(OptionsResolver $resolver) |
|
{ |
|
$choiceLoader = function (Options $options) { |
|
// Unless the choices are given explicitly, load them on demand |
|
/*if (null === $options['choices']) { |
|
|
|
$propelChoiceLoader = new EloquentChoiceLoader( |
|
$this->choiceListFactory, |
|
$options['class'], |
|
$options['query'], |
|
$options['index_property'] |
|
); |
|
|
|
return $propelChoiceLoader; |
|
}*/ |
|
return new EloquentChoiceLoader( |
|
$this->choiceListFactory, |
|
$options['class'], |
|
$options['query'], |
|
$options['index_property'] |
|
); |
|
return null; |
|
}; |
|
|
|
$choiceName = function (Options $options) { |
|
|
|
/** @var Query\Builder $query */ |
|
/*$query = $options['query']; |
|
if ($options['index_property']) { |
|
$identifier = array($query->getTableMap()->getColumn($options['index_property'])); |
|
} else { |
|
$identifier = $query->getTableMap()->getPrimaryKeys(); |
|
}*/ |
|
/** @var ColumnMap $firstIdentifier */ |
|
/*$firstIdentifier = current($identifier); |
|
if (count($identifier) === 1 && $firstIdentifier->getPdoType() === \PDO::PARAM_INT) { |
|
return array(__CLASS__, 'createChoiceName'); |
|
}*/ |
|
return null; |
|
}; |
|
|
|
$choiceValue = function (Options $options) { |
|
|
|
/** @var Query\Builder $query */ |
|
$query = $options['query']; |
|
if ($options['index_property']) { |
|
//$identifier = array($query->getTableMap()->getColumn($options['index_property'])); |
|
$identifier = $query->getKeyName(); |
|
} else { |
|
$identifier = $query->getKeyName(); |
|
} |
|
|
|
return function($object) use ($identifier,$query) { |
|
|
|
if ($object && !$object instanceof BelongsTo) { |
|
//@TODO get by phpname (camelCased) |
|
//return call_user_func([$object, 'get' . ucfirst(camel_case($identifier))]); |
|
return call_user_func([$object, camel_case('getKey')]); |
|
} |
|
return null; |
|
}; |
|
// the commented parts from this code are from the original propel ModelType.php that i'm based on... |
|
//..maybe it will be helpfull in future |
|
/** @var ColumnMap $firstIdentifier *//* |
|
$firstIdentifier = current($identifier); |
|
if (count($identifier) === 1 && in_array($firstIdentifier->getPdoType(), [\PDO::PARAM_BOOL, \PDO::PARAM_INT, \PDO::PARAM_STR])) { |
|
return function($object) use ($firstIdentifier) { |
|
if ($object) { |
|
return call_user_func([$object, 'get' . ucfirst($firstIdentifier->getPhpName())]); |
|
} |
|
return null; |
|
}; |
|
}*/ |
|
|
|
/*if ($options['index_property']) { |
|
return "nome";//$options['class']:: |
|
} else { |
|
|
|
} |
|
return null;*/ |
|
}; |
|
|
|
$queryNormalizer = function (Options $options, $query) { |
|
if ($query === null) { |
|
$queryClass = $options['class'];// . 'Query'; |
|
if (!class_exists($queryClass)) { |
|
if (empty($options['class'])) { |
|
throw new MissingOptionsException('The "class" parameter is empty, you should provide the model class'); |
|
} |
|
throw new InvalidOptionsException( |
|
sprintf( |
|
'The query class "%s" is not found, you should provide the FQCN of the model class', |
|
$queryClass |
|
) |
|
); |
|
} |
|
$query = new $queryClass(); |
|
} |
|
return $query; |
|
}; |
|
|
|
$choiceLabelNormalizer = function (Options $options, $choiceLabel) { |
|
if ($choiceLabel === null) { |
|
if ($options['property'] == null) { |
|
$choiceLabel = array(__CLASS__, 'createChoiceLabel'); |
|
} else { |
|
$valueProperty = $options['property']; |
|
/** @var Query\Builder $query */ |
|
$query = $options['query']; |
|
|
|
$choiceLabel = function($choice) use ($valueProperty) { |
|
$getter = 'get'.ucfirst(camel_case($valueProperty)); |
|
if (!method_exists($choice, $getter)) { |
|
//@TODO |
|
$getter = 'get' . ucfirst(camel_case($query->getAttribute($valueProperty))); |
|
} |
|
|
|
return call_user_func([$choice, $getter]); |
|
}; |
|
} |
|
} |
|
|
|
return $choiceLabel; |
|
|
|
/*$query = $options['query']; |
|
|
|
return $query->{$choiceLabel};*/ |
|
}; |
|
|
|
$resolver->setDefaults([ |
|
'query' => null, |
|
'index_property' => null, |
|
'property' => null, |
|
'choices' => null, |
|
'choice_loader' => $choiceLoader, |
|
'choice_label' => null, |
|
'choice_name' => $choiceName, |
|
'choice_value' => $choiceValue, |
|
'choice_translation_domain' => false, |
|
'by_reference' => false, |
|
]); |
|
|
|
$resolver->setRequired(array('class')); |
|
$resolver->setNormalizer('query', $queryNormalizer); |
|
$resolver->setNormalizer('choice_label', $choiceLabelNormalizer); |
|
//$resolver->setAllowedTypes('query', ['null', 'Propel\Runtime\ActiveQuery\Query\Builder']); |
|
} |
|
|
|
/** |
|
* {@inheritdoc} |
|
*/ |
|
public function getBlockPrefix() |
|
{ |
|
return 'model'; |
|
} |
|
|
|
public function getParent() |
|
{ |
|
return 'Symfony\Component\Form\Extension\Core\Type\ChoiceType'; |
|
} |
|
} |