Permalink
Browse files

merged branch willdurand/propel-bridge (PR #2191)

Commits
-------

5e4b7cb Renamed Propel Bridge: Propel => Propel1
cdad7ab Introducing the Propel Bridge

Discussion
----------

Introducing the Propel Bridge

Basic bridge with stable components for Propel.

This should not affect anything except the need to maintain this code (even if the most part is safe thanks to `@api` tag). As Propel future is linked to Symfony2, to maintain this bridge should not be a problem.
Don't flame me for this proposal, I do that "knowingly".

Regards,
William.

---------------------------------------------------------------------------

by stof at 2011/09/15 12:22:12 -0700

IMO, it would be better to put this code in a repo owned by the Propel organization than in the core.

---------------------------------------------------------------------------

by Richtermeister at 2011/09/15 15:33:02 -0700

Yay, great to see this, very much looking forward to using Propel again.

---------------------------------------------------------------------------

by GromNaN at 2011/09/16 01:37:53 -0700

+1 for @stof proposition.The Silex Core should stay lightweight.

Silex definitely need a site or at least a page in the doc to list all the community extensions.

---------------------------------------------------------------------------

by odino at 2011/09/16 01:39:40 -0700

Silex? :)

---------------------------------------------------------------------------

by GromNaN at 2011/09/16 01:43:20 -0700

Oups, I was looking at Silex PR and got this PR.

---------------------------------------------------------------------------

by lsmith77 at 2011/10/08 01:01:56 -0700

@willdurand we should maybe make this a topic for the next IRC meeting.

---------------------------------------------------------------------------

by willdurand at 2011/10/09 10:26:22 -0700

Agreed :)

---------------------------------------------------------------------------

by willdurand at 2011/11/03 14:18:02 -0700

Good to go ?

---------------------------------------------------------------------------

by willdurand at 2011/11/04 03:34:37 -0700

Just removed the `Query` class. /cc @Stof

Anything else?

---------------------------------------------------------------------------

by willdurand at 2011/11/05 08:45:34 -0700

@fabpot : good to merge ?

The PropelBundle has a `bridge` branch. I'm ready, I'm just waiting you merge this PR to tag the PropelBundle for Symfony 2.0, and after that I'll merge the `bridge` branch into the `master`.

---------------------------------------------------------------------------

by fabpot at 2011/11/16 22:32:42 -0800

What about renaming the directory from `Propel` to `Propel1`? That way, we will be able to have a `Propel` bridge for Propel 2.0.

---------------------------------------------------------------------------

by willdurand at 2011/11/16 23:18:56 -0800

It won't be consistent with the PropelBundle but I guess we don't have any other choice.. So I'm +1 for that.

If it's ok, I'll update this PR, just tell me.

---------------------------------------------------------------------------

by fabpot at 2011/11/17 07:09:58 -0800

yes, +1 for renaming

---------------------------------------------------------------------------

by lsmith77 at 2011/11/17 07:11:45 -0800

Why rename it to ``Propel1``? I think its enough to eventually add a ``Propel2``.

---------------------------------------------------------------------------

by willdurand at 2011/11/17 07:14:05 -0800

`Propel1` is for BC.
`Propel` will be the Propel's future :)

---------------------------------------------------------------------------

by lsmith77 at 2011/11/17 07:17:02 -0800

sounds like a bad idea .. and what happens when you come out with ``Propel3`` ?

---------------------------------------------------------------------------

by stof at 2011/11/17 07:17:31 -0800

@willdurand Maybe the bundle should renamed the same way, for consistency and to let ``PropelBundle`` for the Propel 2 one ? (but this should probably be discussed in another issue tracker)

---------------------------------------------------------------------------

by willdurand at 2011/11/17 07:30:21 -0800

That way we'll be able to handle both Propel 1 & 2 without BC break. You may want to upgrade Symfony2 but not Propel nor PropelBundle. Propel1 bridge has a limited lifetime.

@stof : the PropelBundle will be tagged and a branch will probably appear for Propel1 compatibility.

---------------------------------------------------------------------------

by stof at 2011/11/17 07:34:10 -0800

@willdurand if Symfony provides a Propel bridge using the same namespace for Propel2 and then Propel3, this means that the Sf2 update changing the bridge to use the Propel3 code will make Sf2 incompatible with Propel2 even if you have a tag for Propel2 in the PropelBundle (as you will need to downgrade Symfony to the older tag too). As long as bridges are in the main Symfony repo, they are upgraded the same time Symfony is upgraded and they can bump the requirements.

---------------------------------------------------------------------------

by willdurand at 2011/11/17 07:37:13 -0800

Yes but Propel 1 is frozen, almost dead as we won't add any new features.
Propel2 is the future and there is no plan for a Propel3 which will break BC.

---------------------------------------------------------------------------

by willdurand at 2011/11/17 07:57:05 -0800

Updated!
  • Loading branch information...
2 parents cddb706 + 5e4b7cb commit d59bde758541f64ca2df555eb996eee1f85d49eb @fabpot fabpot committed Nov 19, 2011
@@ -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 Symfony\Bridge\Propel1\DataCollector;
+
+use Symfony\Bridge\Propel1\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 \Symfony\Bridge\Propel1\Logger\PropelLogger
+ */
+ private $logger;
+
+ /**
+ * Propel configuration
+ * @var \PropelConfiguration
+ */
+ protected $propelConfiguration;
+
+ /**
+ * Constructor
+ *
+ * @param \Symfony\Bridge\Propel1\Logger\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 The collector name.
+ */
+ public function getName()
+ {
+ return 'propel';
+ }
+
+ /**
+ * Returns queries.
+ *
+ * @return array Queries
+ */
+ public function getQueries()
+ {
+ return $this->data['queries'];
+ }
+
+ /**
+ * Returns the query count.
+ *
+ * @return int The query count
+ */
+ public function getQueryCount()
+ {
+ return $this->data['querycount'];
+ }
+
+ /**
+ * Creates an array of Build objects.
+ *
+ * @return array An array of Build objects
+ */
+ 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);
+
+ $times = explode($innerGlue, $parts[0]);
+ $memories = explode($innerGlue, $parts[1]);
+
+ $sql = trim($parts[2]);
+ $time = trim($times[1]);
+ $memory = trim($memories[1]);
+
+ $queries[] = array('sql' => $sql, 'time' => $time, 'memory' => $memory);
+ }
+
+ return $queries;
+ }
+
+ /**
+ * Count queries.
+ *
+ * @return int The number of queries.
+ */
+ private function countQueries()
+ {
+ return count($this->logger->getQueries());
+ }
+}
@@ -0,0 +1,230 @@
+<?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 Symfony\Bridge\Propel1\Form\ChoiceList;
+
+use Symfony\Component\Form\Util\PropertyPath;
+use Symfony\Component\Form\Exception\FormException;
+use Symfony\Component\Form\Exception\UnexpectedTypeException;
+use Symfony\Component\Form\Extension\Core\ChoiceList\ArrayChoiceList;
+
+/**
+ * Widely inspirated by the EntityChoiceList (Symfony2).
+ *
+ * @author William Durand <william.durand1@gmail.com>
+ */
+class ModelChoiceList extends ArrayChoiceList
+{
+ /**
+ * The models from which the user can choose
+ *
+ * This array is either indexed by ID (if the ID is a single field)
+ * or by key in the choices array (if the ID consists of multiple fields)
+ *
+ * This property is initialized by initializeChoices(). It should only
+ * be accessed through getModel() and getModels().
+ *
+ * @var array
+ */
+ private $models = array();
+
+ /**
+ * The fields of which the identifier of the underlying class consists
+ *
+ * This property should only be accessed through identifier.
+ *
+ * @var array
+ */
+ private $identifier = array();
+
+ /**
+ * TableMap
+ *
+ * @var \TableMap
+ */
+ private $table = null;
+
+ /**
+ * Property path
+ *
+ * @var \Symfony\Component\Form\Util\PropertyPath
+ */
+ private $propertyPath = null;
+
+ /**
+ * Query
+ */
+ private $query = null;
+
+ /**
+ * @param string $class
+ * @param string $property
+ * @param array $choices
+ * @param \ModelCriteria $queryObject
+ */
+ public function __construct($class, $property = null, $choices = array(), $queryObject = null)
+ {
+ $this->class = $class;
+
+ $queryClass = $this->class . 'Query';
+ $query = new $queryClass();
+
+ $this->table = $query->getTableMap();
+ $this->identifier = $this->table->getPrimaryKeys();
+ $this->query = $queryObject ?: $query;
+
+ // The property option defines, which property (path) is used for
+ // displaying models as strings
+ if ($property) {
+ $this->propertyPath = new PropertyPath($property);
+ }
+
+ parent::__construct($choices);
+ }
+
+ /**
+ * Initializes the choices and returns them
+ *
+ * The choices are generated from the models. If the models have a
+ * composite identifier, the choices are indexed using ascending integers.
+ * Otherwise the identifiers are used as indices.
+ *
+ * If the models were passed in the "choices" option, this method
+ * does not have any significant overhead. Otherwise, if a query object
+ * was passed in the "query" option, this query is now used and executed.
+ * In the last case, all models for the underlying class are fetched.
+ *
+ * If the option "property" was passed, the property path in that option
+ * is used as option values. Otherwise this method tries to convert
+ * objects to strings using __toString().
+ *
+ * @return array An array of choices
+ */
+ protected function load()
+ {
+ parent::load();
+
+ if ($this->choices) {
+ $models = $this->choices;
+ } else {
+ $models = $this->query->find();
+ }
+
+ $this->choices = array();
+ $this->models = array();
+
+ foreach ($models as $key => $model) {
+ if ($this->propertyPath) {
+ // If the property option was given, use it
+ $value = $this->propertyPath->getValue($model);
+ } else {
+ // Otherwise expect a __toString() method in the model
+ $value = (string)$model;
+ }
+
+ if (count($this->identifier) > 1) {
+ // When the identifier consists of multiple field, use
+ // naturally ordered keys to refer to the choices
+ $this->choices[$key] = $value;
+ $this->models[$key] = $model;
+ } else {
+ // When the identifier is a single field, index choices by
+ // model ID for performance reasons
+ $id = current($this->getIdentifierValues($model));
+ $this->choices[$id] = $value;
+ $this->models[$id] = $model;
+ }
+ }
+ }
+
+ public function getIdentifier()
+ {
+ return $this->identifier;
+ }
+
+ /**
+ * Returns the according models for the choices
+ *
+ * If the choices were not initialized, they are initialized now. This
+ * is an expensive operation, except if the models were passed in the
+ * "choices" option.
+ *
+ * @return array An array of models
+ */
+ public function getModels()
+ {
+ if (!$this->loaded) {
+ $this->load();
+ }
+
+ return $this->models;
+ }
+
+ /**
+ * Returns the model for the given key
+ *
+ * If the underlying models have composite identifiers, the choices
+ * are intialized. The key is expected to be the index in the choices
+ * array in this case.
+ *
+ * If they have single identifiers, they are either fetched from the
+ * internal model cache (if filled) or loaded from the database.
+ *
+ * @param string $key The choice key (for models with composite
+ * identifiers) or model ID (for models with single
+ * identifiers)
+ * @return object The matching model
+ */
+ public function getModel($key)
+ {
+ if (!$this->loaded) {
+ $this->load();
+ }
+
+ try {
+ if (count($this->identifier) > 1) {
+ // $key is a collection index
+ $models = $this->getModels();
+
+ return isset($models[$key]) ? $models[$key] : null;
+ }
+
+ if ($this->models) {
+ return isset($this->models[$key]) ? $this->models[$key] : null;
+ }
+
+ $queryClass = $this->class . 'Query';
+
+ return $queryClass::create()->findPk($key);
+ } catch (NoResultException $e) {
+ return null;
+ }
+ }
+
+ /**
+ * Returns the values of the identifier fields of an 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
+ * @throws FormException If the model does not exist
+ */
+ public function getIdentifierValues($model)
+ {
+ if ($model instanceof \BaseObject) {
+ return array($model->getPrimaryKey());
+ }
+
+ return $model->getPrimaryKeys();
+ }
+}
Oops, something went wrong.

0 comments on commit d59bde7

Please sign in to comment.