integrate former Symfony Propel1 bridge

This commit is contained in:
Toni Uebernickel 2016-01-23 16:52:33 +01:00
parent bde72e0ee6
commit 38b491aa46
33 changed files with 3312 additions and 54 deletions

View file

@ -0,0 +1,147 @@
<?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 Propel\PropelBundle\DataCollector;
use Propel\PropelBundle\Logger\PropelLogger;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\DataCollector\DataCollector;
/**
* The PropelDataCollector collector class collects information.
*
* @author William Durand <william.durand1@gmail.com>
*/
class PropelDataCollector extends DataCollector
{
/**
* Propel logger.
*
* @var PropelLogger
*/
private $logger;
/**
* Propel configuration.
*
* @var \PropelConfiguration
*/
protected $propelConfiguration;
/**
* Constructor.
*
* @param PropelLogger $logger A Propel logger.
* @param \PropelConfiguration $propelConfiguration The Propel configuration object.
*/
public function __construct(PropelLogger $logger, \PropelConfiguration $propelConfiguration)
{
$this->logger = $logger;
$this->propelConfiguration = $propelConfiguration;
}
/**
* {@inheritdoc}
*/
public function collect(Request $request, Response $response, \Exception $exception = null)
{
$this->data = array(
'queries' => $this->buildQueries(),
'querycount' => $this->countQueries(),
);
}
/**
* Returns the collector name.
*
* @return string
*/
public function getName()
{
return 'propel';
}
/**
* Returns the collected stats for all executed SQL queries.
*
* @return array
*/
public function getQueries()
{
return $this->data['queries'];
}
/**
* Returns the query count.
*
* @return int
*/
public function getQueryCount()
{
return $this->data['querycount'];
}
/**
* Returns the total time spent on running all queries.
*
* @return float
*/
public function getTime()
{
$time = 0;
foreach ($this->data['queries'] as $query) {
$time += (float) $query['time'];
}
return $time;
}
/**
* Computes the stats of all executed SQL queries.
*
* @return array
*/
private function buildQueries()
{
$queries = array();
$outerGlue = $this->propelConfiguration->getParameter('debugpdo.logging.outerglue', ' | ');
$innerGlue = $this->propelConfiguration->getParameter('debugpdo.logging.innerglue', ': ');
foreach ($this->logger->getQueries() as $q) {
$parts = explode($outerGlue, $q, 4);
$times = explode($innerGlue, $parts[0]);
$con = explode($innerGlue, $parts[2]);
$memories = explode($innerGlue, $parts[1]);
$sql = trim($parts[3]);
$con = trim($con[1]);
$time = trim($times[1]);
$memory = trim($memories[1]);
$queries[] = array('connection' => $con, 'sql' => $sql, 'time' => $time, 'memory' => $memory);
}
return $queries;
}
/**
* Returns the total count of SQL queries.
*
* @return int
*/
private function countQueries()
{
return count($this->logger->getQueries());
}
}

View file

@ -0,0 +1,69 @@
<?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 Propel\PropelBundle\DependencyInjection\Security\UserProvider;
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\UserProvider\UserProviderFactoryInterface;
use Symfony\Component\Config\Definition\Builder\NodeDefinition;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\DefinitionDecorator;
/**
* PropelFactory creates services for Propel user provider.
*
* @author William Durand <william.durand1@gmail.com>
*/
class PropelFactory implements UserProviderFactoryInterface
{
private $key;
private $providerId;
/**
* Constructor.
*
* @param string $key
* @param string $providerId
*/
public function __construct($key, $providerId)
{
$this->key = $key;
$this->providerId = $providerId;
}
public function create(ContainerBuilder $container, $id, $config)
{
$container
->setDefinition($id, new DefinitionDecorator($this->providerId))
->addArgument($config['class'])
->addArgument($config['property'])
;
}
public function getKey()
{
return $this->key;
}
public function addConfiguration(NodeDefinition $node)
{
$node
->children()
->scalarNode('class')
->isRequired()
->cannotBeEmpty()
->end()
->scalarNode('property')
->defaultNull()
->end()
->end()
;
}
}

View file

@ -0,0 +1,512 @@
<?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 Propel\PropelBundle\Form\ChoiceList;
use Propel\PropelBundle\Form\Type\ModelType;
use Symfony\Component\Form\Exception\StringCastException;
use Symfony\Component\Form\Extension\Core\ChoiceList\ObjectChoiceList;
use Symfony\Component\Form\Extension\Core\DataTransformer\ChoicesToValuesTransformer;
use Symfony\Component\Form\Extension\Core\DataTransformer\ChoiceToValueTransformer;
use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException;
use Symfony\Component\OptionsResolver\Exception\MissingOptionsException;
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
/**
* A choice list for object choices based on Propel model.
*
* @author William Durand <william.durand1@gmail.com>
* @author Toni Uebernickel <tuebernickel@gmail.com>
*/
class ModelChoiceList extends ObjectChoiceList
{
/**
* The fields of which the identifier of the underlying class consists.
*
* This property should only be accessed through identifier.
*
* @var array
*/
protected $identifier = array();
/**
* The query to retrieve the choices of this list.
*
* @var \ModelCriteria
*/
protected $query;
/**
* The query to retrieve the preferred choices for this list.
*
* @var \ModelCriteria
*/
protected $preferredQuery;
/**
* Whether the model objects have already been loaded.
*
* @var bool
*/
protected $loaded = false;
/**
* Whether to use the identifier for index generation.
*
* @var bool
*/
private $identifierAsIndex = false;
/**
* Constructor.
*
* @see ModelType How to use the preferred choices.
*
* @param string $class The FQCN of the model class to be loaded.
* @param string $labelPath A property path pointing to the property used for the choice labels.
* @param array $choices An optional array to use, rather than fetching the models.
* @param \ModelCriteria $queryObject The query to use retrieving model data from database.
* @param string $groupPath A property path pointing to the property used to group the choices.
* @param array|\ModelCriteria $preferred The preferred items of this choice.
* Either an array if $choices is given,
* or a \ModelCriteria to be merged with the $queryObject.
* @param PropertyAccessorInterface $propertyAccessor The reflection graph for reading property paths.
* @param string $useAsIdentifier a custom unique column (eg slug) to use instead of primary key.
*
* @throws MissingOptionsException In case the class parameter is empty.
* @throws InvalidOptionsException In case the query class is not found.
*/
public function __construct($class, $labelPath = null, $choices = null, $queryObject = null, $groupPath = null, $preferred = array(), PropertyAccessorInterface $propertyAccessor = null, $useAsIdentifier = null)
{
$this->class = $class;
$queryClass = $this->class.'Query';
if (!class_exists($queryClass)) {
if (empty($this->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();
$this->query = $queryObject ?: $query;
if ($useAsIdentifier) {
$this->identifier = array($this->query->getTableMap()->getColumn($useAsIdentifier));
} else {
$this->identifier = $this->query->getTableMap()->getPrimaryKeys();
}
$this->loaded = is_array($choices) || $choices instanceof \Traversable;
if ($preferred instanceof \ModelCriteria) {
$this->preferredQuery = $preferred->mergeWith($this->query);
}
if (!$this->loaded) {
// Make sure the constraints of the parent constructor are
// fulfilled
$choices = array();
$preferred = array();
}
if (1 === count($this->identifier) && $this->isScalar(current($this->identifier))) {
$this->identifierAsIndex = true;
}
parent::__construct($choices, $labelPath, $preferred, $groupPath, null, $propertyAccessor);
}
/**
* Returns the class name of the model.
*
* @return string
*/
public function getClass()
{
return $this->class;
}
/**
* {@inheritdoc}
*/
public function getChoices()
{
$this->load();
return parent::getChoices();
}
/**
* {@inheritdoc}
*/
public function getValues()
{
$this->load();
return parent::getValues();
}
/**
* {@inheritdoc}
*/
public function getPreferredViews()
{
$this->load();
return parent::getPreferredViews();
}
/**
* {@inheritdoc}
*/
public function getRemainingViews()
{
$this->load();
return parent::getRemainingViews();
}
/**
* {@inheritdoc}
*/
public function getChoicesForValues(array $values)
{
if (empty($values)) {
return array();
}
/*
* This performance optimization reflects a common scenario:
* * A simple select of a model entry.
* * The choice option "expanded" is set to false.
* * The current request is the submission of the selected value.
*
* @see ChoicesToValuesTransformer::reverseTransform()
* @see ChoiceToValueTransformer::reverseTransform()
*/
if (!$this->loaded) {
if (1 === count($this->identifier)) {
$filterBy = 'filterBy'.current($this->identifier)->getPhpName();
// The initial query is cloned, so all additional filters are applied correctly.
$query = clone $this->query;
$result = (array) $query
->$filterBy($values)
->find();
// Preserve the keys as provided by the values.
$models = array();
foreach ($values as $index => $value) {
foreach ($result as $eachModel) {
if ($value === $this->createValue($eachModel)) {
// Make sure to convert to the right format
$models[$index] = $this->fixChoice($eachModel);
// If all values have been assigned, skip further loops.
unset($values[$index]);
if (0 === count($values)) {
break 2;
}
}
}
}
return $models;
}
}
$this->load();
return parent::getChoicesForValues($values);
}
/**
* {@inheritdoc}
*/
public function getValuesForChoices(array $models)
{
if (empty($models)) {
return array();
}
if (!$this->loaded) {
/*
* This performance optimization assumes the validation of the respective values will be done by other means.
*
* It correlates with the performance optimization in {@link ModelChoiceList::getChoicesForValues()}
* as it won't load the actual entries from the database.
*
* @see ChoicesToValuesTransformer::transform()
* @see ChoiceToValueTransformer::transform()
*/
if (1 === count($this->identifier)) {
$values = array();
foreach ($models as $index => $model) {
if ($model instanceof $this->class) {
// Make sure to convert to the right format
$values[$index] = $this->fixValue(current($this->getIdentifierValues($model)));
}
}
return $values;
}
}
$this->load();
$values = array();
$availableValues = $this->getValues();
/*
* Overwriting default implementation.
*
* The two objects may represent the same entry in the database,
* but if they originated from different queries, there are not the same object within the code.
*
* This happens when using m:n relations with either sides model as data_class of the form.
* The choicelist will retrieve the list of available related models with a different query, resulting in different objects.
*/
$choices = $this->fixChoices($models);
foreach ($choices as $i => $givenChoice) {
if (null === $givenChoice) {
continue;
}
foreach ($this->getChoices() as $j => $choice) {
if ($this->isEqual($choice, $givenChoice)) {
$values[$i] = $availableValues[$j];
// If all choices have been assigned, skip further loops.
unset($choices[$i]);
if (0 === count($choices)) {
break 2;
}
}
}
}
return $values;
}
/**
* {@inheritdoc}
*
* @deprecated since version 2.4, to be removed in 3.0.
*/
public function getIndicesForChoices(array $models)
{
trigger_error('The '.__METHOD__.' method is deprecated since version 2.4 and will be removed in 3.0.', E_USER_DEPRECATED);
if (empty($models)) {
return array();
}
$this->load();
$indices = array();
/*
* Overwriting default implementation.
*
* The two objects may represent the same entry in the database,
* but if they originated from different queries, there are not the same object within the code.
*
* This happens when using m:n relations with either sides model as data_class of the form.
* The choice list will retrieve the list of available related models with a different query, resulting in different objects.
*/
$choices = $this->fixChoices($models);
foreach ($choices as $i => $givenChoice) {
if (null === $givenChoice) {
continue;
}
foreach ($this->getChoices() as $j => $choice) {
if ($this->isEqual($choice, $givenChoice)) {
$indices[$i] = $j;
// If all choices have been assigned, skip further loops.
unset($choices[$i]);
if (0 === count($choices)) {
break 2;
}
}
}
}
return $indices;
}
/**
* {@inheritdoc}
*
* @deprecated since version 2.4, to be removed in 3.0.
*/
public function getIndicesForValues(array $values)
{
trigger_error('The '.__METHOD__.' method is deprecated since version 2.4 and will be removed in 3.0.', E_USER_DEPRECATED);
if (empty($values)) {
return array();
}
$this->load();
return parent::getIndicesForValues($values);
}
/**
* Creates a new unique index for this model.
*
* If the model has a single-field identifier, this identifier is used.
*
* Otherwise a new integer is generated.
*
* @param mixed $model The choice to create an index for
*
* @return int|string A unique index containing only ASCII letters,
* digits and underscores.
*/
protected function createIndex($model)
{
if ($this->identifierAsIndex) {
return current($this->getIdentifierValues($model));
}
return parent::createIndex($model);
}
/**
* Creates a new unique value for this model.
*
* If the model has a single-field identifier, this identifier is used.
*
* Otherwise a new integer is generated.
*
* @param mixed $model The choice to create a value for
*
* @return int|string A unique value without character limitations.
*/
protected function createValue($model)
{
if ($this->identifierAsIndex) {
return (string) current($this->getIdentifierValues($model));
}
return parent::createValue($model);
}
/**
* Loads the complete choice list entries, once.
*
* If data has been loaded the choice list is initialized with the retrieved data.
*/
private function load()
{
if ($this->loaded) {
return;
}
$models = (array) $this->query->find();
$preferred = array();
if ($this->preferredQuery instanceof \ModelCriteria) {
$preferred = (array) $this->preferredQuery->find();
}
try {
// The second parameter $labels is ignored by ObjectChoiceList
parent::initialize($models, array(), $preferred);
$this->loaded = true;
} catch (StringCastException $e) {
throw new StringCastException(str_replace('argument $labelPath', 'option "property"', $e->getMessage()), null, $e);
}
}
/**
* Returns the values of the identifier fields of a model.
*
* Propel must know about this model, that is, the model must already
* be persisted or added to the idmodel map before. Otherwise an
* exception is thrown.
*
* @param object $model The model for which to get the identifier
*
* @return array
*/
private function getIdentifierValues($model)
{
if (!$model instanceof $this->class) {
return array();
}
if (1 === count($this->identifier) && current($this->identifier) instanceof \ColumnMap) {
$phpName = current($this->identifier)->getPhpName();
if (method_exists($model, 'get'.$phpName)) {
return array($model->{'get'.$phpName}());
}
}
if ($model instanceof \Persistent) {
return array($model->getPrimaryKey());
}
// readonly="true" models do not implement \Persistent.
if ($model instanceof \BaseObject && method_exists($model, 'getPrimaryKey')) {
return array($model->getPrimaryKey());
}
if (!method_exists($model, 'getPrimaryKeys')) {
return array();
}
return $model->getPrimaryKeys();
}
/**
* Whether this column contains scalar values (to be used as indices).
*
* @param \ColumnMap $column
*
* @return bool
*/
private function isScalar(\ColumnMap $column)
{
return in_array($column->getPdoType(), array(
\PDO::PARAM_BOOL,
\PDO::PARAM_INT,
\PDO::PARAM_STR,
));
}
/**
* Check the given choices for equality.
*
* @param mixed $choice
* @param mixed $givenChoice
*
* @return bool
*/
private function isEqual($choice, $givenChoice)
{
if ($choice === $givenChoice) {
return true;
}
if ($this->getIdentifierValues($choice) === $this->getIdentifierValues($givenChoice)) {
return true;
}
return false;
}
}

View file

@ -0,0 +1,55 @@
<?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 Propel\PropelBundle\Form\DataTransformer;
use PropelObjectCollection;
use Symfony\Component\Form\DataTransformerInterface;
use Symfony\Component\Form\Exception\TransformationFailedException;
/**
* CollectionToArrayTransformer class.
*
* @author William Durand <william.durand1@gmail.com>
* @author Pierre-Yves Lebecq <py.lebecq@gmail.com>
*/
class CollectionToArrayTransformer implements DataTransformerInterface
{
public function transform($collection)
{
if (null === $collection) {
return array();
}
if (!$collection instanceof PropelObjectCollection) {
throw new TransformationFailedException('Expected a \PropelObjectCollection.');
}
return $collection->getData();
}
public function reverseTransform($array)
{
$collection = new PropelObjectCollection();
if ('' === $array || null === $array) {
return $collection;
}
if (!is_array($array)) {
throw new TransformationFailedException('Expected an array.');
}
$collection->setData($array);
return $collection;
}
}

View file

@ -0,0 +1,102 @@
<?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 Propel\PropelBundle\Form\EventListener;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Form\Exception\UnexpectedTypeException;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
/**
* listener class for propel1_translatable_collection.
*
* @author Patrick Kaufmann
*/
class TranslationCollectionFormListener implements EventSubscriberInterface
{
private $i18nClass;
private $languages;
public function __construct($languages, $i18nClass)
{
$this->i18nClass = $i18nClass;
$this->languages = $languages;
}
public static function getSubscribedEvents()
{
return array(
FormEvents::PRE_SET_DATA => array('preSetData', 1),
);
}
public function preSetData(FormEvent $event)
{
$form = $event->getForm();
$data = $event->getData();
if (null === $data) {
return;
}
if (!is_array($data) && !($data instanceof \Traversable && $data instanceof \ArrayAccess)) {
throw new UnexpectedTypeException($data, 'array or (\Traversable and \ArrayAccess)');
}
//get the class name of the i18nClass
$temp = explode('\\', $this->i18nClass);
$dataClass = end($temp);
$rootData = $form->getRoot()->getData();
$foundData = false;
$addFunction = 'add'.$dataClass;
//add a database row for every needed language
foreach ($this->languages as $lang) {
$found = false;
foreach ($data as $i18n) {
if (!method_exists($i18n, 'getLocale')) {
throw new UnexpectedTypeException($i18n, 'Propel i18n object');
}
if ($i18n->getLocale() == $lang) {
$found = true;
break;
}
}
if (!$found) {
$currentForm = $form;
while (!$foundData) {
if (method_exists($rootData, $addFunction)) {
$foundData = true;
break;
} elseif ($currentForm->hasParent()) {
$currentForm = $currentForm->getParent();
$rootData = $currentForm->getData();
} else {
break;
}
}
if (!$foundData) {
throw new UnexpectedTypeException($rootData, 'Propel i18n object');
}
$newTranslation = new $this->i18nClass();
$newTranslation->setLocale($lang);
$rootData->$addFunction($newTranslation);
}
}
}
}

View file

@ -0,0 +1,81 @@
<?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 Propel\PropelBundle\Form\EventListener;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
/**
* Event Listener class for propel1_translation.
*
* @author Patrick Kaufmann
*/
class TranslationFormListener implements EventSubscriberInterface
{
private $columns;
private $dataClass;
public function __construct($columns, $dataClass)
{
$this->columns = $columns;
$this->dataClass = $dataClass;
}
public static function getSubscribedEvents()
{
return array(
FormEvents::PRE_SET_DATA => array('preSetData', 1),
);
}
public function preSetData(FormEvent $event)
{
$form = $event->getForm();
$data = $event->getData();
if (!$data instanceof $this->dataClass) {
return;
}
//loop over all columns and add the input
foreach ($this->columns as $column => $options) {
if (is_string($options)) {
$column = $options;
$options = array();
}
if (null === $options) {
$options = array();
}
$type = 'text';
if (array_key_exists('type', $options)) {
$type = $options['type'];
}
$label = $column;
if (array_key_exists('label', $options)) {
$label = $options['label'];
}
$customOptions = array();
if (array_key_exists('options', $options)) {
$customOptions = $options['options'];
}
$options = array(
'label' => $label.' '.strtoupper($data->getLocale()),
);
$options = array_merge($options, $customOptions);
$form->add($column, $type, $options);
}
}
}

37
Form/PropelExtension.php Normal file
View file

@ -0,0 +1,37 @@
<?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 Propel\PropelBundle\Form;
use Symfony\Component\Form\AbstractExtension;
use Symfony\Component\PropertyAccess\PropertyAccess;
/**
* Represents the Propel form extension, which loads the Propel functionality.
*
* @author Joseph Rouff <rouffj@gmail.com>
*/
class PropelExtension extends AbstractExtension
{
protected function loadTypes()
{
return array(
new Type\ModelType(PropertyAccess::createPropertyAccessor()),
new Type\TranslationCollectionType(),
new Type\TranslationType(),
);
}
protected function loadTypeGuesser()
{
return new PropelTypeGuesser();
}
}

184
Form/PropelTypeGuesser.php Normal file
View file

@ -0,0 +1,184 @@
<?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 Propel\PropelBundle\Form;
use Symfony\Component\Form\FormTypeGuesserInterface;
use Symfony\Component\Form\Guess\Guess;
use Symfony\Component\Form\Guess\TypeGuess;
use Symfony\Component\Form\Guess\ValueGuess;
/**
* Propel Type guesser.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class PropelTypeGuesser implements FormTypeGuesserInterface
{
private $cache = array();
/**
* {@inheritdoc}
*/
public function guessType($class, $property)
{
if (!$table = $this->getTable($class)) {
return new TypeGuess('text', array(), Guess::LOW_CONFIDENCE);
}
foreach ($table->getRelations() as $relation) {
if ($relation->getType() === \RelationMap::MANY_TO_ONE) {
if (strtolower($property) === strtolower($relation->getName())) {
return new TypeGuess('model', array(
'class' => $relation->getForeignTable()->getClassName(),
'multiple' => false,
), Guess::HIGH_CONFIDENCE);
}
} elseif ($relation->getType() === \RelationMap::ONE_TO_MANY) {
if (strtolower($property) === strtolower($relation->getPluralName())) {
return new TypeGuess('model', array(
'class' => $relation->getForeignTable()->getClassName(),
'multiple' => true,
), Guess::HIGH_CONFIDENCE);
}
} elseif ($relation->getType() === \RelationMap::MANY_TO_MANY) {
if (strtolower($property) == strtolower($relation->getPluralName())) {
return new TypeGuess('model', array(
'class' => $relation->getLocalTable()->getClassName(),
'multiple' => true,
), Guess::HIGH_CONFIDENCE);
}
}
}
if (!$column = $this->getColumn($class, $property)) {
return new TypeGuess('text', array(), Guess::LOW_CONFIDENCE);
}
switch ($column->getType()) {
case \PropelColumnTypes::BOOLEAN:
case \PropelColumnTypes::BOOLEAN_EMU:
return new TypeGuess('checkbox', array(), Guess::HIGH_CONFIDENCE);
case \PropelColumnTypes::TIMESTAMP:
case \PropelColumnTypes::BU_TIMESTAMP:
return new TypeGuess('datetime', array(), Guess::HIGH_CONFIDENCE);
case \PropelColumnTypes::DATE:
case \PropelColumnTypes::BU_DATE:
return new TypeGuess('date', array(), Guess::HIGH_CONFIDENCE);
case \PropelColumnTypes::TIME:
return new TypeGuess('time', array(), Guess::HIGH_CONFIDENCE);
case \PropelColumnTypes::FLOAT:
case \PropelColumnTypes::REAL:
case \PropelColumnTypes::DOUBLE:
case \PropelColumnTypes::DECIMAL:
return new TypeGuess('number', array(), Guess::MEDIUM_CONFIDENCE);
case \PropelColumnTypes::TINYINT:
case \PropelColumnTypes::SMALLINT:
case \PropelColumnTypes::INTEGER:
case \PropelColumnTypes::BIGINT:
case \PropelColumnTypes::NUMERIC:
return new TypeGuess('integer', array(), Guess::MEDIUM_CONFIDENCE);
case \PropelColumnTypes::ENUM:
case \PropelColumnTypes::CHAR:
if ($column->getValueSet()) {
//check if this is mysql enum
$choices = $column->getValueSet();
$labels = array_map('ucfirst', $choices);
return new TypeGuess('choice', array('choices' => array_combine($choices, $labels)), Guess::MEDIUM_CONFIDENCE);
}
case \PropelColumnTypes::VARCHAR:
return new TypeGuess('text', array(), Guess::MEDIUM_CONFIDENCE);
case \PropelColumnTypes::LONGVARCHAR:
case \PropelColumnTypes::BLOB:
case \PropelColumnTypes::CLOB:
case \PropelColumnTypes::CLOB_EMU:
return new TypeGuess('textarea', array(), Guess::MEDIUM_CONFIDENCE);
default:
return new TypeGuess('text', array(), Guess::LOW_CONFIDENCE);
}
}
/**
* {@inheritdoc}
*/
public function guessRequired($class, $property)
{
if ($column = $this->getColumn($class, $property)) {
return new ValueGuess($column->isNotNull(), Guess::HIGH_CONFIDENCE);
}
}
/**
* {@inheritdoc}
*/
public function guessMaxLength($class, $property)
{
if ($column = $this->getColumn($class, $property)) {
if ($column->isText()) {
return new ValueGuess($column->getSize(), Guess::HIGH_CONFIDENCE);
}
switch ($column->getType()) {
case \PropelColumnTypes::FLOAT:
case \PropelColumnTypes::REAL:
case \PropelColumnTypes::DOUBLE:
case \PropelColumnTypes::DECIMAL:
return new ValueGuess(null, Guess::MEDIUM_CONFIDENCE);
}
}
}
/**
* {@inheritdoc}
*/
public function guessPattern($class, $property)
{
if ($column = $this->getColumn($class, $property)) {
switch ($column->getType()) {
case \PropelColumnTypes::FLOAT:
case \PropelColumnTypes::REAL:
case \PropelColumnTypes::DOUBLE:
case \PropelColumnTypes::DECIMAL:
return new ValueGuess(null, Guess::MEDIUM_CONFIDENCE);
}
}
}
protected function getTable($class)
{
if (isset($this->cache[$class])) {
return $this->cache[$class];
}
if (class_exists($queryClass = $class.'Query')) {
$query = new $queryClass();
return $this->cache[$class] = $query->getTableMap();
}
}
protected function getColumn($class, $property)
{
if (isset($this->cache[$class.'::'.$property])) {
return $this->cache[$class.'::'.$property];
}
$table = $this->getTable($class);
if ($table && $table->hasColumn($property)) {
return $this->cache[$class.'::'.$property] = $table->getColumn($property);
}
if ($table && $table->hasColumnByInsensitiveCase($property)) {
return $this->cache[$class.'::'.$property] = $table->getColumnByInsensitiveCase($property);
}
}
}

128
Form/Type/ModelType.php Normal file
View file

@ -0,0 +1,128 @@
<?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 Propel\PropelBundle\Form\Type;
use Propel\PropelBundle\Form\ChoiceList\ModelChoiceList;
use Propel\PropelBundle\Form\DataTransformer\CollectionToArrayTransformer;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\Options;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\PropertyAccess\PropertyAccess;
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
/**
* ModelType class.
*
* @author William Durand <william.durand1@gmail.com>
* @author Toni Uebernickel <tuebernickel@gmail.com>
*
* Example using the preferred_choices option.
*
* <code>
* public function buildForm(FormBuilderInterface $builder, array $options)
* {
* $builder
* ->add('product', 'model', array(
* 'class' => 'Model\Product',
* 'query' => ProductQuery::create()
* ->filterIsActive(true)
* ->useI18nQuery($options['locale'])
* ->orderByName()
* ->endUse()
* ,
* 'preferred_choices' => ProductQuery::create()
* ->filterByIsTopProduct(true)
* ,
* ))
* ;
* }
* </code>
*/
class ModelType extends AbstractType
{
/**
* @var PropertyAccessorInterface
*/
private $propertyAccessor;
/**
* Constructor.
*
* @param PropertyAccessorInterface|null $propertyAccessor
*/
public function __construct(PropertyAccessorInterface $propertyAccessor = null)
{
$this->propertyAccessor = $propertyAccessor ?: PropertyAccess::createPropertyAccessor();
}
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
if ($options['multiple']) {
$builder->addViewTransformer(new CollectionToArrayTransformer(), true);
}
}
/**
* {@inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$propertyAccessor = $this->propertyAccessor;
$choiceList = function (Options $options) use ($propertyAccessor) {
return new ModelChoiceList(
$options['class'],
$options['property'],
$options['choices'],
$options['query'],
$options['group_by'],
$options['preferred_choices'],
$propertyAccessor,
$options['index_property']
);
};
$resolver->setDefaults(array(
'template' => 'choice',
'multiple' => false,
'expanded' => false,
'class' => null,
'property' => null,
'query' => null,
'choices' => null,
'choice_list' => $choiceList,
'group_by' => null,
'by_reference' => false,
'index_property' => null,
));
}
/**
* {@inheritdoc}
*/
public function getParent()
{
return 'choice';
}
/**
* {@inheritdoc}
*/
public function getName()
{
return 'model';
}
}

View file

@ -0,0 +1,78 @@
<?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 Propel\PropelBundle\Form\Type;
use Propel\PropelBundle\Form\EventListener\TranslationCollectionFormListener;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\Exception\MissingOptionsException;
use Symfony\Component\OptionsResolver\OptionsResolver;
/**
* form type for i18n-columns in propel.
*
* @author Patrick Kaufmann
*/
class TranslationCollectionType extends AbstractType
{
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
if (!isset($options['options']['data_class']) || null === $options['options']['data_class']) {
throw new MissingOptionsException('data_class must be set');
}
if (!isset($options['options']['columns']) || null === $options['options']['columns']) {
throw new MissingOptionsException('columns must be set');
}
$listener = new TranslationCollectionFormListener($options['languages'], $options['options']['data_class']);
$builder->addEventSubscriber($listener);
}
/**
* {@inheritdoc}
*/
public function getParent()
{
return 'collection';
}
/**
* {@inheritdoc}
*/
public function getName()
{
return 'propel1_translation_collection';
}
/**
* {@inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setRequired(array(
'languages',
));
$resolver->setDefaults(array(
'type' => 'propel1_translation',
'allow_add' => false,
'allow_delete' => false,
'options' => array(
'data_class' => null,
'columns' => null,
),
));
}
}

View file

@ -0,0 +1,54 @@
<?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 Propel\PropelBundle\Form\Type;
use Propel\PropelBundle\Form\EventListener\TranslationFormListener;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
/**
* Translation type class.
*
* @author Patrick Kaufmann
*/
class TranslationType extends AbstractType
{
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->addEventSubscriber(
new TranslationFormListener($options['columns'], $options['data_class'])
);
}
/**
* {@inheritdoc}
*/
public function getName()
{
return 'propel1_translation';
}
/**
* {@inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setRequired(array(
'data_class',
'columns',
));
}
}

177
Logger/PropelLogger.php Normal file
View file

@ -0,0 +1,177 @@
<?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 Propel\PropelBundle\Logger;
use Psr\Log\LoggerInterface;
use Symfony\Component\Stopwatch\Stopwatch;
/**
* PropelLogger.
*
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @author William Durand <william.durand1@gmail.com>
*/
class PropelLogger implements \BasicLogger
{
/**
* @var LoggerInterface
*/
protected $logger;
/**
* @var array
*/
protected $queries = array();
/**
* @var Stopwatch
*/
protected $stopwatch;
/**
* @var bool
*/
private $isPrepared = false;
/**
* Constructor.
*
* @param LoggerInterface $logger A LoggerInterface instance
* @param Stopwatch $stopwatch A Stopwatch instance
*/
public function __construct(LoggerInterface $logger = null, Stopwatch $stopwatch = null)
{
$this->logger = $logger;
$this->stopwatch = $stopwatch;
}
/**
* {@inheritdoc}
*/
public function alert($message)
{
$this->log($message, 'alert');
}
/**
* {@inheritdoc}
*/
public function crit($message)
{
$this->log($message, 'crit');
}
/**
* {@inheritdoc}
*/
public function err($message)
{
$this->log($message, 'err');
}
/**
* {@inheritdoc}
*/
public function warning($message)
{
$this->log($message, 'warning');
}
/**
* {@inheritdoc}
*/
public function notice($message)
{
$this->log($message, 'notice');
}
/**
* {@inheritdoc}
*/
public function info($message)
{
$this->log($message, 'info');
}
/**
* {@inheritdoc}
*/
public function debug($message)
{
$add = true;
if (null !== $this->stopwatch) {
$trace = debug_backtrace();
$method = $trace[2]['args'][2];
$watch = 'Propel Query '.(count($this->queries) + 1);
if ('PropelPDO::prepare' === $method) {
$this->isPrepared = true;
$this->stopwatch->start($watch, 'propel');
$add = false;
} elseif ($this->isPrepared) {
$this->isPrepared = false;
$this->stopwatch->stop($watch);
}
}
if ($add) {
$this->queries[] = $message;
$this->log($message, 'debug');
}
}
/**
* {@inheritdoc}
*/
public function log($message, $severity = null)
{
if (null !== $this->logger) {
$message = is_string($message) ? $message : var_export($message, true);
switch ($severity) {
case 'alert':
$this->logger->alert($message);
break;
case 'crit':
$this->logger->critical($message);
break;
case 'err':
$this->logger->error($message);
break;
case 'warning':
$this->logger->warning($message);
break;
case 'notice':
$this->logger->notice($message);
break;
case 'info':
$this->logger->info($message);
break;
case 'debug':
default:
$this->logger->debug($message);
}
}
}
/**
* Returns queries.
*
* @return array Queries
*/
public function getQueries()
{
return $this->queries;
}
}

View file

@ -7,15 +7,14 @@
*
* @license MIT License
*/
namespace Propel\PropelBundle;
use Symfony\Bridge\Propel1\DependencyInjection\Security\UserProvider\PropelFactory;
use Symfony\Component\HttpKernel\Bundle\Bundle;
use Propel\PropelBundle\DependencyInjection\Security\UserProvider\PropelFactory;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Bundle\Bundle;
/**
* PropelBundle
* PropelBundle.
*
* @author William DURAND <william.durand1@gmail.com>
*/
@ -51,7 +50,7 @@ class PropelBundle extends Bundle
), false);
$config->setParameter('debugpdo.logging.details', array(
'time' => array('enabled' => true),
'mem' => array('enabled' => true),
'mem' => array('enabled' => true),
'connection' => array('enabled' => true),
));

View file

@ -7,14 +7,14 @@
<parameters>
<parameter key="propel.dbal.default_connection">default</parameter>
<parameter key="propel.configuration.class">PropelConfiguration</parameter>
<parameter key="propel.logger.class">Symfony\Bridge\Propel1\Logger\PropelLogger</parameter>
<parameter key="propel.data_collector.class">Symfony\Bridge\Propel1\DataCollector\PropelDataCollector</parameter>
<parameter key="propel.logger.class">Propel\PropelBundle\Logger\PropelLogger</parameter>
<parameter key="propel.data_collector.class">Propel\PropelBundle\DataCollector\PropelDataCollector</parameter>
<parameter key="propel.build_properties.class">Propel\PropelBundle\DependencyInjection\Properties</parameter>
<parameter key="propel.form.type.model.class">Symfony\Bridge\Propel1\Form\Type\ModelType</parameter>
<parameter key="propel.form.type.model.class">Propel\PropelBundle\Form\Type\ModelType</parameter>
<parameter key="propel.twig.extension.syntax.class">Propel\PropelBundle\Twig\Extension\SyntaxExtension</parameter>
<parameter key="form.type_guesser.propel.class">Symfony\Bridge\Propel1\Form\PropelTypeGuesser</parameter>
<parameter key="form.type_guesser.propel.class">Propel\PropelBundle\Form\PropelTypeGuesser</parameter>
<parameter key="propel.security.acl.provider.model.class">Propel\PropelBundle\Security\Acl\AuditableAclProvider</parameter>
<parameter key="propel.security.user.provider.class">Symfony\Bridge\Propel1\Security\User\PropelUserProvider</parameter>
<parameter key="propel.security.user.provider.class">Propel\PropelBundle\Security\User\PropelUserProvider</parameter>
</parameters>
<services>

View file

@ -0,0 +1,103 @@
<?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 Propel\PropelBundle\Security\User;
use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
/**
* Provides easy to use provisioning for Propel model users.
*
* @author William DURAND <william.durand1@gmail.com>
*/
class PropelUserProvider implements UserProviderInterface
{
/**
* A Model class name.
*
* @var string
*/
protected $class;
/**
* A Query class name.
*
* @var string
*/
protected $queryClass;
/**
* A property to use to retrieve the user.
*
* @var string
*/
protected $property;
/**
* Default constructor.
*
* @param string $class The User model class.
* @param string|null $property The property to use to retrieve a user.
*/
public function __construct($class, $property = null)
{
$this->class = $class;
$this->queryClass = $class.'Query';
$this->property = $property;
}
/**
* {@inheritdoc}
*/
public function loadUserByUsername($username)
{
$queryClass = $this->queryClass;
$query = $queryClass::create();
if (null !== $this->property) {
$filter = 'filterBy'.ucfirst($this->property);
$query->$filter($username);
} else {
$query->filterByUsername($username);
}
if (null === $user = $query->findOne()) {
throw new UsernameNotFoundException(sprintf('User "%s" not found.', $username));
}
return $user;
}
/**
* {@inheritdoc}
*/
public function refreshUser(UserInterface $user)
{
if (!$user instanceof $this->class) {
throw new UnsupportedUserException(sprintf('Instances of "%s" are not supported.', get_class($user)));
}
$queryClass = $this->queryClass;
return $queryClass::create()->findPk($user->getPrimaryKey());
}
/**
* {@inheritdoc}
*/
public function supportsClass($class)
{
return $class === $this->class;
}
}

View file

@ -0,0 +1,104 @@
<?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 Propel\PropelBundle\Tests\DataCollector;
use Propel\PropelBundle\DataCollector\PropelDataCollector;
use Propel\PropelBundle\Tests\TestCase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class PropelDataCollectorTest extends TestCase
{
public function testCollectWithoutData()
{
$c = $this->createCollector(array());
$c->collect(new Request(), new Response());
$this->assertEquals(array(), $c->getQueries());
$this->assertEquals(0, $c->getQueryCount());
}
public function testCollectWithData()
{
$queries = array(
"time: 0.000 sec | mem: 1.4 MB | connection: default | SET NAMES 'utf8'",
);
$c = $this->createCollector($queries);
$c->collect(new Request(), new Response());
$this->assertEquals(array(
array(
'sql' => "SET NAMES 'utf8'",
'time' => '0.000 sec',
'connection' => 'default',
'memory' => '1.4 MB',
),
), $c->getQueries());
$this->assertEquals(1, $c->getQueryCount());
}
public function testCollectWithMultipleData()
{
$queries = array(
"time: 0.000 sec | mem: 1.4 MB | connection: default | SET NAMES 'utf8'",
'time: 0.012 sec | mem: 2.4 MB | connection: default | SELECT tags.NAME, image.FILENAME FROM tags LEFT JOIN image ON tags.IMAGEID = image.ID WHERE image.ID = 12',
"time: 0.012 sec | mem: 2.4 MB | connection: default | INSERT INTO `table` (`some_array`) VALUES ('| 1 | 2 | 3 |')",
);
$c = $this->createCollector($queries);
$c->collect(new Request(), new Response());
$this->assertEquals(array(
array(
'sql' => "SET NAMES 'utf8'",
'time' => '0.000 sec',
'connection' => 'default',
'memory' => '1.4 MB',
),
array(
'sql' => 'SELECT tags.NAME, image.FILENAME FROM tags LEFT JOIN image ON tags.IMAGEID = image.ID WHERE image.ID = 12',
'time' => '0.012 sec',
'connection' => 'default',
'memory' => '2.4 MB',
),
array(
'sql' => "INSERT INTO `table` (`some_array`) VALUES ('| 1 | 2 | 3 |')",
'time' => '0.012 sec',
'connection' => 'default',
'memory' => '2.4 MB',
),
), $c->getQueries());
$this->assertEquals(3, $c->getQueryCount());
$this->assertEquals(0.024, $c->getTime());
}
private function createCollector($queries)
{
$config = $this->getMock('\PropelConfiguration');
$config
->expects($this->any())
->method('getParameter')
->will($this->returnArgument(1))
;
$logger = $this->getMock('\Propel\PropelBundle\Logger\PropelLogger');
$logger
->expects($this->any())
->method('getQueries')
->will($this->returnValue($queries))
;
return new PropelDataCollector($logger, $config);
}
}

54
Tests/Fixtures/Column.php Normal file
View file

@ -0,0 +1,54 @@
<?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 Propel\PropelBundle\Tests\Fixtures;
class Column extends \ColumnMap
{
private $name;
protected $type;
public function __construct($name, $type)
{
$this->name = $name;
$this->type = $type;
$this->phpName = ucfirst($name);
}
public function isText()
{
if (!$this->type) {
return false;
}
switch ($this->type) {
case \PropelColumnTypes::CHAR:
case \PropelColumnTypes::VARCHAR:
case \PropelColumnTypes::LONGVARCHAR:
case \PropelColumnTypes::BLOB:
case \PropelColumnTypes::CLOB:
case \PropelColumnTypes::CLOB_EMU:
return true;
}
return false;
}
public function getSize()
{
return $this->isText() ? 255 : 0;
}
public function isNotNull()
{
return 'id' === $this->name;
}
}

111
Tests/Fixtures/Item.php Normal file
View file

@ -0,0 +1,111 @@
<?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 Propel\PropelBundle\Tests\Fixtures;
class Item implements \Persistent
{
private $id;
private $value;
private $groupName;
private $price;
private $slug;
public function __construct($id = null, $value = null, $groupName = null, $price = null, $slug = null)
{
$this->id = $id;
$this->value = $value;
$this->groupName = $groupName;
$this->price = $price;
$this->slug = $slug;
}
public function getId()
{
return $this->id;
}
public function setId($id)
{
$this->id = $id;
}
public function getValue()
{
return $this->value;
}
public function getGroupName()
{
return $this->groupName;
}
public function getPrice()
{
return $this->price;
}
public function getSlug()
{
return $this->slug;
}
public function getPrimaryKey()
{
return $this->getId();
}
public function setPrimaryKey($primaryKey)
{
$this->setId($primaryKey);
}
public function isModified()
{
return false;
}
public function isColumnModified($col)
{
return false;
}
public function isNew()
{
return false;
}
public function setNew($b)
{
}
public function resetModified()
{
}
public function isDeleted()
{
return false;
}
public function setDeleted($b)
{
}
public function delete(\PropelPDO $con = null)
{
}
public function save(\PropelPDO $con = null)
{
}
}

View file

@ -0,0 +1,130 @@
<?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 Propel\PropelBundle\Tests\Fixtures;
class ItemQuery
{
private $map = array(
'id' => \PropelColumnTypes::INTEGER,
'value' => \PropelColumnTypes::VARCHAR,
'price' => \PropelColumnTypes::FLOAT,
'is_active' => \PropelColumnTypes::BOOLEAN,
'slug' => \PropelColumnTypes::VARCHAR,
'enabled' => \PropelColumnTypes::BOOLEAN_EMU,
'updated_at' => \PropelColumnTypes::TIMESTAMP,
);
private $caseInsensitiveMap = array(
'isactive' => 'is_active',
'updatedat' => 'updated_at',
);
public static $result = array();
public function find()
{
return self::$result;
}
public function filterById($id)
{
return $this;
}
public function getTableMap()
{
// Allows to define methods in this class
// to avoid a lot of mock classes
return $this;
}
public function getPrimaryKeys()
{
$cm = new \ColumnMap('id', new \TableMap());
$cm->setType('INTEGER');
$cm->setPhpName('Id');
return array('id' => $cm);
}
/**
* Method from the TableMap API.
*/
public function hasColumn($column)
{
return in_array($column, array_keys($this->map));
}
/**
* Method from the TableMap API.
*/
public function getColumn($column)
{
if ($this->hasColumn($column)) {
return new Column($column, $this->map[$column]);
}
}
/**
* Method from the TableMap API.
*/
public function hasColumnByInsensitiveCase($column)
{
$column = strtolower($column);
return in_array($column, array_keys($this->caseInsensitiveMap));
}
/**
* Method from the TableMap API.
*/
public function getColumnByInsensitiveCase($column)
{
$column = strtolower($column);
if (isset($this->caseInsensitiveMap[$column])) {
return $this->getColumn($this->caseInsensitiveMap[$column]);
}
}
/**
* Method from the TableMap API.
*/
public function getRelations()
{
// table maps
$authorTable = new \TableMap();
$authorTable->setClassName('\Foo\Author');
$resellerTable = new \TableMap();
$resellerTable->setClassName('\Foo\Reseller');
// relations
$mainAuthorRelation = new \RelationMap('MainAuthor');
$mainAuthorRelation->setType(\RelationMap::MANY_TO_ONE);
$mainAuthorRelation->setForeignTable($authorTable);
$authorRelation = new \RelationMap('Author');
$authorRelation->setType(\RelationMap::ONE_TO_MANY);
$authorRelation->setForeignTable($authorTable);
$resellerRelation = new \RelationMap('Reseller');
$resellerRelation->setType(\RelationMap::MANY_TO_MANY);
$resellerRelation->setLocalTable($resellerTable);
return array(
$mainAuthorRelation,
$authorRelation,
$resellerRelation,
);
}
}

View file

@ -0,0 +1,25 @@
<?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 Propel\PropelBundle\Tests\Fixtures;
class ReadOnlyItem extends \BaseObject
{
public function getName()
{
return 'Marvin';
}
public function getPrimaryKey()
{
return 42;
}
}

View file

@ -0,0 +1,30 @@
<?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 Propel\PropelBundle\Tests\Fixtures;
class ReadOnlyItemQuery
{
public function getTableMap()
{
// Allows to define methods in this class
// to avoid a lot of mock classes
return $this;
}
public function getPrimaryKeys()
{
$cm = new \ColumnMap('id', new \TableMap());
$cm->setType('INTEGER');
return array('id' => $cm);
}
}

View file

@ -0,0 +1,125 @@
<?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 Propel\PropelBundle\Tests\Fixtures;
class TranslatableItem implements \Persistent
{
private $id;
private $currentTranslations;
private $groupName;
private $price;
public function __construct($id = null, $translations = array())
{
$this->id = $id;
$this->currentTranslations = $translations;
}
public function getId()
{
return $this->id;
}
public function setId($id)
{
$this->id = $id;
}
public function getGroupName()
{
return $this->groupName;
}
public function getPrice()
{
return $this->price;
}
public function getPrimaryKey()
{
return $this->getId();
}
public function setPrimaryKey($primaryKey)
{
$this->setId($primaryKey);
}
public function isModified()
{
return false;
}
public function isColumnModified($col)
{
return false;
}
public function isNew()
{
return false;
}
public function setNew($b)
{
}
public function resetModified()
{
}
public function isDeleted()
{
return false;
}
public function setDeleted($b)
{
}
public function delete(\PropelPDO $con = null)
{
}
public function save(\PropelPDO $con = null)
{
}
public function getTranslation($locale = 'de', \PropelPDO $con = null)
{
if (!isset($this->currentTranslations[$locale])) {
$translation = new TranslatableItemI18n();
$translation->setLocale($locale);
$this->currentTranslations[$locale] = $translation;
}
return $this->currentTranslations[$locale];
}
public function addTranslatableItemI18n(TranslatableItemI18n $i)
{
if (!in_array($i, $this->currentTranslations)) {
$this->currentTranslations[$i->getLocale()] = $i;
$i->setItem($this);
}
}
public function removeTranslatableItemI18n(TranslatableItemI18n $i)
{
unset($this->currentTranslations[$i->getLocale()]);
}
public function getTranslatableItemI18ns()
{
return $this->currentTranslations;
}
}

View file

@ -0,0 +1,128 @@
<?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 Propel\PropelBundle\Tests\Fixtures;
class TranslatableItemI18n implements \Persistent
{
private $id;
private $locale;
private $value;
private $value2;
private $item;
public function __construct($id = null, $locale = null, $value = null)
{
$this->id = $id;
$this->locale = $locale;
$this->value = $value;
}
public function getId()
{
return $this->id;
}
public function setId($id)
{
$this->id = $id;
}
public function getPrimaryKey()
{
return $this->getId();
}
public function setPrimaryKey($primaryKey)
{
$this->setId($primaryKey);
}
public function isModified()
{
return false;
}
public function isColumnModified($col)
{
return false;
}
public function isNew()
{
return false;
}
public function setNew($b)
{
}
public function resetModified()
{
}
public function isDeleted()
{
return false;
}
public function setDeleted($b)
{
}
public function delete(\PropelPDO $con = null)
{
}
public function save(\PropelPDO $con = null)
{
}
public function setLocale($locale)
{
$this->locale = $locale;
}
public function getLocale()
{
return $this->locale;
}
public function getItem()
{
return $this->item;
}
public function setItem($item)
{
$this->item = $item;
}
public function setValue($value)
{
$this->value = $value;
}
public function getValue()
{
return $this->value;
}
public function setValue2($value2)
{
$this->value2 = $value2;
}
public function getValue2()
{
return $this->value2;
}
}

View file

@ -0,0 +1,118 @@
<?php
namespace Propel\PropelBundle\Tests\Form\ChoiceList;
use Propel\PropelBundle\Form\ChoiceList\ModelChoiceList;
use Propel\PropelBundle\Tests\Fixtures\Item;
use Propel\PropelBundle\Tests\Fixtures\ItemQuery;
use Symfony\Component\Form\Tests\Extension\Core\ChoiceList\AbstractChoiceListTest;
class CompatModelChoiceListTest extends AbstractChoiceListTest
{
const ITEM_CLASS = '\Propel\PropelBundle\Tests\Fixtures\Item';
/**
* @var \PHPUnit_Framework_MockObject_MockObject|\Propel\PropelBundle\Tests\Fixtures\ItemQuery
*/
protected $query;
protected $item1;
protected $item2;
protected $item3;
protected $item4;
public function testGetChoicesForValues()
{
$this->query
->expects($this->once())
->method('filterById')
->with(array(1, 2))
->will($this->returnSelf())
;
ItemQuery::$result = array(
$this->item2,
$this->item1,
);
parent::testGetChoicesForValues();
}
protected function setUp()
{
$this->query = $this->getMock('Propel\PropelBundle\Tests\Fixtures\ItemQuery', array(
'filterById',
), array(), '', true, true, true, false, true);
$this->query
->expects($this->any())
->method('filterById')
->with($this->anything())
->will($this->returnSelf())
;
$this->createItems();
ItemQuery::$result = array(
$this->item1,
$this->item2,
$this->item3,
$this->item4,
);
parent::setUp();
}
protected function createItems()
{
$this->item1 = new Item(1, 'Foo');
$this->item2 = new Item(2, 'Bar');
$this->item3 = new Item(3, 'Baz');
$this->item4 = new Item(4, 'Cuz');
}
protected function createChoiceList()
{
return new ModelChoiceList(self::ITEM_CLASS, 'value', null, $this->query);
}
protected function getChoices()
{
return array(
1 => $this->item1,
2 => $this->item2,
3 => $this->item3,
4 => $this->item4,
);
}
protected function getLabels()
{
return array(
1 => 'Foo',
2 => 'Bar',
3 => 'Baz',
4 => 'Cuz',
);
}
protected function getValues()
{
return array(
1 => '1',
2 => '2',
3 => '3',
4 => '4',
);
}
protected function getIndices()
{
return array(
1,
2,
3,
4,
);
}
}

View file

@ -0,0 +1,316 @@
<?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 Propel\PropelBundle\Tests\Form\ChoiceList;
use Propel\PropelBundle\Form\ChoiceList\ModelChoiceList;
use Propel\PropelBundle\Tests\Fixtures\Item;
use Propel\PropelBundle\Tests\Fixtures\ItemQuery;
use Propel\PropelBundle\Tests\Fixtures\ReadOnlyItem;
use Propel\PropelBundle\Tests\TestCase;
use Symfony\Component\Form\Extension\Core\View\ChoiceView;
class ModelChoiceListTest extends TestCase
{
const ITEM_CLASS = '\Propel\PropelBundle\Tests\Fixtures\Item';
protected function setUp()
{
ItemQuery::$result = array();
}
public function testEmptyChoicesReturnsEmpty()
{
$choiceList = new ModelChoiceList(
self::ITEM_CLASS,
'value',
array()
);
$this->assertSame(array(), $choiceList->getChoices());
}
public function testReadOnlyIsValidChoice()
{
$item = new ReadOnlyItem();
$choiceList = new ModelChoiceList(
'\Propel\PropelBundle\Tests\Fixtures\ReadOnlyItem',
'name',
array(
$item,
)
);
$this->assertSame(array(42 => $item), $choiceList->getChoices());
}
public function testFlattenedChoices()
{
$item1 = new Item(1, 'Foo');
$item2 = new Item(2, 'Bar');
$choiceList = new ModelChoiceList(
self::ITEM_CLASS,
'value',
array(
$item1,
$item2,
)
);
$this->assertSame(array(1 => $item1, 2 => $item2), $choiceList->getChoices());
}
public function testFlattenedPreferredChoices()
{
$item1 = new Item(1, 'Foo');
$item2 = new Item(2, 'Bar');
$choiceList = new ModelChoiceList(
self::ITEM_CLASS,
'value',
array(
$item1,
$item2,
),
null,
null,
array(
$item1,
)
);
$this->assertSame(array(1 => $item1, 2 => $item2), $choiceList->getChoices());
$this->assertEquals(array(1 => new ChoiceView($item1, '1', 'Foo')), $choiceList->getPreferredViews());
}
public function testNestedChoices()
{
$item1 = new Item(1, 'Foo');
$item2 = new Item(2, 'Bar');
$choiceList = new ModelChoiceList(
self::ITEM_CLASS,
'value',
array(
'group1' => array($item1),
'group2' => array($item2),
)
);
$this->assertSame(array(1 => $item1, 2 => $item2), $choiceList->getChoices());
$this->assertEquals(array(
'group1' => array(1 => new ChoiceView($item1, '1', 'Foo')),
'group2' => array(2 => new ChoiceView($item2, '2', 'Bar')),
), $choiceList->getRemainingViews());
}
public function testGroupBySupportsString()
{
$item1 = new Item(1, 'Foo', 'Group1');
$item2 = new Item(2, 'Bar', 'Group1');
$item3 = new Item(3, 'Baz', 'Group2');
$item4 = new Item(4, 'Boo!', null);
$choiceList = new ModelChoiceList(
self::ITEM_CLASS,
'value',
array(
$item1,
$item2,
$item3,
$item4,
),
null,
'groupName'
);
$this->assertEquals(array(1 => $item1, 2 => $item2, 3 => $item3, 4 => $item4), $choiceList->getChoices());
$this->assertEquals(array(
'Group1' => array(1 => new ChoiceView($item1, '1', 'Foo'), 2 => new ChoiceView($item2, '2', 'Bar')),
'Group2' => array(3 => new ChoiceView($item3, '3', 'Baz')),
4 => new ChoiceView($item4, '4', 'Boo!'),
), $choiceList->getRemainingViews());
}
public function testGroupByInvalidPropertyPathReturnsFlatChoices()
{
$item1 = new Item(1, 'Foo', 'Group1');
$item2 = new Item(2, 'Bar', 'Group1');
$choiceList = new ModelChoiceList(
self::ITEM_CLASS,
'value',
array(
$item1,
$item2,
),
null,
'child.that.does.not.exist'
);
$this->assertEquals(array(
1 => $item1,
2 => $item2,
), $choiceList->getChoices());
}
public function testGetValuesForChoices()
{
$item1 = new Item(1, 'Foo');
$item2 = new Item(2, 'Bar');
ItemQuery::$result = array(
$item1,
$item2,
);
$choiceList = new ModelChoiceList(
self::ITEM_CLASS,
'value',
null,
null,
null,
null
);
$this->assertEquals(array(1, 2), $choiceList->getValuesForChoices(array($item1, $item2)));
}
public function testDifferentEqualObjectsAreChoosen()
{
$item = new Item(1, 'Foo');
ItemQuery::$result = array(
$item,
);
$choiceList = new ModelChoiceList(
self::ITEM_CLASS,
'value',
array($item)
);
$choosenItem = new Item(1, 'Foo');
$this->assertEquals(array('1'), $choiceList->getValuesForChoices(array($choosenItem)));
}
public function testLegacygetIndicesForChoices()
{
$this->iniSet('error_reporting', -1 & ~E_USER_DEPRECATED);
$item1 = new Item(1, 'Foo');
$item2 = new Item(2, 'Bar');
ItemQuery::$result = array(
$item1,
$item2,
);
$choiceList = new ModelChoiceList(
self::ITEM_CLASS,
'value',
null,
null,
null,
null
);
$this->assertEquals(array(1, 2), $choiceList->getIndicesForChoices(array($item1, $item2)));
}
public function testLegacyDifferentEqualObjectsAreChoosen()
{
$this->iniSet('error_reporting', -1 & ~E_USER_DEPRECATED);
$item = new Item(1, 'Foo');
ItemQuery::$result = array(
$item,
);
$choiceList = new ModelChoiceList(
self::ITEM_CLASS,
'value',
array($item)
);
$choosenItem = new Item(1, 'Foo');
$this->assertEquals(array(1), $choiceList->getIndicesForChoices(array($choosenItem)));
}
public function testLegacyGetIndicesForNullChoices()
{
$this->iniSet('error_reporting', -1 & ~E_USER_DEPRECATED);
$item = new Item(1, 'Foo');
$choiceList = new ModelChoiceList(
self::ITEM_CLASS,
'value',
array($item)
);
$this->assertEquals(array(), $choiceList->getIndicesForChoices(array(null)));
}
public function testDontAllowInvalidChoiceValues()
{
$item = new Item(1, 'Foo');
$choiceList = new ModelChoiceList(
self::ITEM_CLASS,
'value',
array($item)
);
$this->assertEquals(array(), $choiceList->getValuesForChoices(array(new Item(2, 'Bar'))));
$this->assertEquals(array(), $choiceList->getChoicesForValues(array(2)));
}
/**
* @expectedException \Symfony\Component\OptionsResolver\Exception\MissingOptionsException
*/
public function testEmptyClass()
{
new ModelChoiceList('');
}
/**
* @expectedException \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException
*/
public function testInvalidClass()
{
new ModelChoiceList('Foo\Bar\DoesNotExistClass');
}
public function testCustomIdentifier()
{
$item1 = new Item(1, 'Foo', null, null, 'slug');
$item2 = new Item(2, 'Bar', null, null, 'slug2');
$choiceList = new ModelChoiceList(
self::ITEM_CLASS,
'value',
array(
$item1,
$item2,
),
null,
null,
array(),
null,
'slug'
);
$this->assertSame(array('slug' => $item1, 'slug2' => $item2), $choiceList->getChoices());
}
}

View file

@ -0,0 +1,106 @@
<?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 Propel\PropelBundle\Tests\Form\DataTransformer;
use Propel\PropelBundle\Form\DataTransformer\CollectionToArrayTransformer;
use Propel\PropelBundle\Tests\TestCase;
class CollectionToArrayTransformerTest extends TestCase
{
private $transformer;
protected function setUp()
{
$this->transformer = new CollectionToArrayTransformer();
}
public function testTransform()
{
$result = $this->transformer->transform(new \PropelObjectCollection());
$this->assertTrue(is_array($result));
$this->assertCount(0, $result);
}
public function testTransformWithNull()
{
$result = $this->transformer->transform(null);
$this->assertTrue(is_array($result));
$this->assertCount(0, $result);
}
/**
* @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
*/
public function testTransformThrowsExceptionIfNotPropelObjectCollection()
{
$this->transformer->transform(new DummyObject());
}
public function testTransformWithData()
{
$coll = new \PropelObjectCollection();
$coll->setData(array('foo', 'bar'));
$result = $this->transformer->transform($coll);
$this->assertTrue(is_array($result));
$this->assertCount(2, $result);
$this->assertEquals('foo', $result[0]);
$this->assertEquals('bar', $result[1]);
}
public function testReverseTransformWithNull()
{
$result = $this->transformer->reverseTransform(null);
$this->assertInstanceOf('\PropelObjectCollection', $result);
$this->assertCount(0, $result->getData());
}
public function testReverseTransformWithEmptyString()
{
$result = $this->transformer->reverseTransform('');
$this->assertInstanceOf('\PropelObjectCollection', $result);
$this->assertCount(0, $result->getData());
}
/**
* @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
*/
public function testReverseTransformThrowsExceptionIfNotArray()
{
$this->transformer->reverseTransform(new DummyObject());
}
public function testReverseTransformWithData()
{
$inputData = array('foo', 'bar');
$result = $this->transformer->reverseTransform($inputData);
$data = $result->getData();
$this->assertInstanceOf('\PropelObjectCollection', $result);
$this->assertTrue(is_array($data));
$this->assertCount(2, $data);
$this->assertEquals('foo', $data[0]);
$this->assertEquals('bar', $data[1]);
$this->assertsame($inputData, $data);
}
}
class DummyObject
{
}

View file

@ -0,0 +1,136 @@
<?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 Propel\PropelBundle\Tests\Form;
use Propel\PropelBundle\Form\PropelTypeGuesser;
use Propel\PropelBundle\Tests\TestCase;
use Symfony\Component\Form\Guess\Guess;
class PropelTypeGuesserTest extends TestCase
{
const CLASS_NAME = 'Propel\PropelBundle\Tests\Fixtures\Item';
const UNKNOWN_CLASS_NAME = 'Propel\PropelBundle\Tests\Fixtures\UnknownItem';
private $guesser;
protected function setUp()
{
$this->guesser = new PropelTypeGuesser();
}
protected function tearDown()
{
$this->guesser = null;
}
public function testGuessMaxLengthWithText()
{
$value = $this->guesser->guessMaxLength(self::CLASS_NAME, 'value');
$this->assertNotNull($value);
$this->assertEquals(255, $value->getValue());
}
public function testGuessMaxLengthWithFloat()
{
$value = $this->guesser->guessMaxLength(self::CLASS_NAME, 'price');
$this->assertNotNull($value);
$this->assertNull($value->getValue());
}
public function testGuessMinLengthWithText()
{
$value = $this->guesser->guessPattern(self::CLASS_NAME, 'value');
$this->assertNull($value);
}
public function testGuessMinLengthWithFloat()
{
$value = $this->guesser->guessPattern(self::CLASS_NAME, 'price');
$this->assertNotNull($value);
$this->assertNull($value->getValue());
}
public function testGuessRequired()
{
$value = $this->guesser->guessRequired(self::CLASS_NAME, 'id');
$this->assertNotNull($value);
$this->assertTrue($value->getValue());
}
public function testGuessRequiredWithNullableColumn()
{
$value = $this->guesser->guessRequired(self::CLASS_NAME, 'value');
$this->assertNotNull($value);
$this->assertFalse($value->getValue());
}
public function testGuessTypeWithoutTable()
{
$value = $this->guesser->guessType(self::UNKNOWN_CLASS_NAME, 'property');
$this->assertNotNull($value);
$this->assertEquals('text', $value->getType());
$this->assertEquals(Guess::LOW_CONFIDENCE, $value->getConfidence());
}
public function testGuessTypeWithoutColumn()
{
$value = $this->guesser->guessType(self::CLASS_NAME, 'property');
$this->assertNotNull($value);
$this->assertEquals('text', $value->getType());
$this->assertEquals(Guess::LOW_CONFIDENCE, $value->getConfidence());
}
/**
* @dataProvider dataProviderForGuessType
*/
public function testGuessType($property, $type, $confidence, $multiple = null)
{
$value = $this->guesser->guessType(self::CLASS_NAME, $property);
$this->assertNotNull($value);
$this->assertEquals($type, $value->getType());
$this->assertEquals($confidence, $value->getConfidence());
if ($type === 'model') {
$options = $value->getOptions();
$this->assertSame($multiple, $options['multiple']);
}
}
public static function dataProviderForGuessType()
{
return array(
array('is_active', 'checkbox', Guess::HIGH_CONFIDENCE),
array('enabled', 'checkbox', Guess::HIGH_CONFIDENCE),
array('id', 'integer', Guess::MEDIUM_CONFIDENCE),
array('value', 'text', Guess::MEDIUM_CONFIDENCE),
array('price', 'number', Guess::MEDIUM_CONFIDENCE),
array('updated_at', 'datetime', Guess::HIGH_CONFIDENCE),
array('isActive', 'checkbox', Guess::HIGH_CONFIDENCE),
array('updatedAt', 'datetime', Guess::HIGH_CONFIDENCE),
array('Authors', 'model', Guess::HIGH_CONFIDENCE, true),
array('Resellers', 'model', Guess::HIGH_CONFIDENCE, true),
array('MainAuthor', 'model', Guess::HIGH_CONFIDENCE, false),
);
}
}

View file

@ -0,0 +1,151 @@
<?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 Propel\PropelBundle\Tests\Form\Type;
use Propel\PropelBundle\Form\PropelExtension;
use Propel\PropelBundle\Tests\Fixtures\Item;
use Propel\PropelBundle\Tests\Fixtures\TranslatableItem;
use Propel\PropelBundle\Tests\Fixtures\TranslatableItemI18n;
use Symfony\Component\Form\Test\TypeTestCase;
class TranslationCollectionTypeTest extends TypeTestCase
{
const TRANSLATION_CLASS = 'Propel\PropelBundle\Tests\Fixtures\TranslatableItem';
const TRANSLATABLE_I18N_CLASS = 'Propel\PropelBundle\Tests\Fixtures\TranslatableItemI18n';
const NON_TRANSLATION_CLASS = 'Propel\PropelBundle\Tests\Fixtures\Item';
protected function getExtensions()
{
return array(new PropelExtension());
}
public function testTranslationsAdded()
{
$item = new TranslatableItem();
$item->addTranslatableItemI18n(new TranslatableItemI18n(1, 'fr', 'val1'));
$item->addTranslatableItemI18n(new TranslatableItemI18n(2, 'en', 'val2'));
$builder = $this->factory->createBuilder('form', null, array(
'data_class' => self::TRANSLATION_CLASS,
));
$builder->add('translatableItemI18ns', 'propel1_translation_collection', array(
'languages' => array('en', 'fr'),
'options' => array(
'data_class' => self::TRANSLATABLE_I18N_CLASS,
'columns' => array('value', 'value2' => array('label' => 'Label', 'type' => 'textarea')),
),
));
$form = $builder->getForm();
$form->setData($item);
$translations = $form->get('translatableItemI18ns');
$this->assertCount(2, $translations);
$this->assertInstanceOf('Symfony\Component\Form\Form', $translations['en']);
$this->assertInstanceOf('Symfony\Component\Form\Form', $translations['fr']);
$this->assertInstanceOf(self::TRANSLATABLE_I18N_CLASS, $translations['en']->getData());
$this->assertInstanceOf(self::TRANSLATABLE_I18N_CLASS, $translations['fr']->getData());
$this->assertEquals($item->getTranslation('en'), $translations['en']->getData());
$this->assertEquals($item->getTranslation('fr'), $translations['fr']->getData());
$columnOptions = $translations['fr']->getConfig()->getOption('columns');
$this->assertEquals('value', $columnOptions[0]);
$this->assertEquals('textarea', $columnOptions['value2']['type']);
$this->assertEquals('Label', $columnOptions['value2']['label']);
}
public function testNotPresentTranslationsAdded()
{
$item = new TranslatableItem();
$this->assertCount(0, $item->getTranslatableItemI18ns());
$builder = $this->factory->createBuilder('form', null, array(
'data_class' => self::TRANSLATION_CLASS,
));
$builder->add('translatableItemI18ns', 'propel1_translation_collection', array(
'languages' => array('en', 'fr'),
'options' => array(
'data_class' => self::TRANSLATABLE_I18N_CLASS,
'columns' => array('value', 'value2' => array('label' => 'Label', 'type' => 'textarea')),
),
));
$form = $builder->getForm();
$form->setData($item);
$this->assertCount(2, $item->getTranslatableItemI18ns());
}
/**
* @expectedException \Symfony\Component\Form\Exception\UnexpectedTypeException
*/
public function testNoArrayGiven()
{
$item = new Item(null, 'val');
$builder = $this->factory->createBuilder('form', null, array(
'data_class' => self::NON_TRANSLATION_CLASS,
));
$builder->add('value', 'propel1_translation_collection', array(
'languages' => array('en', 'fr'),
'options' => array(
'data_class' => self::TRANSLATABLE_I18N_CLASS,
'columns' => array('value', 'value2' => array('label' => 'Label', 'type' => 'textarea')),
),
));
$form = $builder->getForm();
$form->setData($item);
}
/**
* @expectedException \Symfony\Component\OptionsResolver\Exception\MissingOptionsException
*/
public function testNoDataClassAdded()
{
$this->factory->createNamed('itemI18ns', 'propel1_translation_collection', null, array(
'languages' => array('en', 'fr'),
'options' => array(
'columns' => array('value', 'value2'),
),
));
}
/**
* @expectedException \Symfony\Component\OptionsResolver\Exception\MissingOptionsException
*/
public function testNoLanguagesAdded()
{
$this->factory->createNamed('itemI18ns', 'propel1_translation_collection', null, array(
'options' => array(
'data_class' => self::TRANSLATABLE_I18N_CLASS,
'columns' => array('value', 'value2'),
),
));
}
/**
* @expectedException \Symfony\Component\OptionsResolver\Exception\MissingOptionsException
*/
public function testNoColumnsAdded()
{
$this->factory->createNamed('itemI18ns', 'propel1_translation_collection', null, array(
'languages' => array('en', 'fr'),
'options' => array(
'data_class' => self::TRANSLATABLE_I18N_CLASS,
),
));
}
}

View file

@ -7,12 +7,11 @@
*
* @license MIT License
*/
namespace Propel\PropelBundle\Tests\Security\User;
use Propel\PropelBundle\Security\User\PropelUserProvider;
use Propel\PropelBundle\Tests\Fixtures\Model\User;
use Propel\PropelBundle\Tests\TestCase;
use Symfony\Bridge\Propel1\Security\User\PropelUserProvider;
/**
* @author William Durand <william.durand1@gmail.com>

View file

@ -1,5 +0,0 @@
<?php
require_once __DIR__ . '/../vendor/autoload.php';
set_include_path(get_include_path() . PATH_SEPARATOR . __DIR__ . '/../vendor/phing/phing/classes');

View file

@ -1,7 +0,0 @@
<?php
if (file_exists($file = __DIR__.'/autoload.php')) {
require_once $file;
} elseif (file_exists($file = __DIR__.'/autoload.php.dist')) {
require_once $file;
}

View file

@ -15,9 +15,8 @@
},
"require": {
"symfony/framework-bundle": "^2.8.2",
"symfony/propel1-bridge": "2.7.x-dev",
"propel/propel1": "^1.6.8"
"propel/propel1": "^1.6.8",
"symfony/framework-bundle": "^2.8.2"
},
"require-dev": {
"phpunit/phpunit": "^4.8.21|^5.0.10",
@ -26,6 +25,14 @@
"fzaninotto/faker": "^1.5"
},
"conflict": {
"symfony/propel1-bridge": ">=2.8.0"
},
"replace": {
"symfony/propel1-bridge": "<=2.8.0"
},
"suggest": {
"symfony/security-acl": "For using the Propel ACL implementation"
}

View file

@ -1,30 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
backupStaticAttributes="false"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
syntaxCheck="false"
bootstrap="./Tests/bootstrap.php">
<php>
<!-- <server name="SYMFONY" value="/path/to/symfony" /> -->
</php>
<testsuites>
<testsuite name="PropelBundle Test Suite">
<directory suffix="Test.php">./Tests</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory>./</directory>
<exclude>
<directory>./Tests</directory>
<directory>./vendor</directory>
<directory>./Resources</directory>
</exclude>
</whitelist>
</filter>
backupStaticAttributes="false"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
syntaxCheck="false"
bootstrap="vendor/autoload.php">
<php>
<ini name="error_reporting" value="E_ALL ^ E_DEPRECATED"/>
<includePath>vendor/phing/phing/classes</includePath>
</php>
<testsuites>
<testsuite name="PropelBundle Test Suite">
<directory suffix="Test.php">./Tests</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory>./</directory>
<exclude>
<directory>./Tests</directory>
<directory>./vendor</directory>
<directory>./Resources</directory>
</exclude>
</whitelist>
</filter>
</phpunit>