Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Fix ModelChoiceList problem with string key #6150

Closed
wants to merge 10 commits into from

3 participants

@woodspire

The ModelChoiceList code was based on EntityChoiceList for doctrine, but a critical misinterpretation happen.

I have a list where one key is : "1SER+"

This crash symfony in ChoiceList addChoice code when the index (1SER+) is not a valid form name.
This happen because the ModelChoiceList thinks that because there is only 1 column in the primary key, it will be an integer.

I modified the code to reflect the way EntityChoiceList does it.

I will also send a pull request in the propel1 project to add the isInteger() function in ColumnMap.

isNumeric() is present, but it cannot be used, because 2.34 contains a dot, and it cannot be used has a form name.

Felix Labrecque Fix problem when 1 column identifier in propel is a string.
The ModelChoiceList thinks it can be used as the index of the ChoiceList, when it can only be used if it is an integer.
972e503
@woodspire woodspire referenced this pull request in propelorm/Propel
Closed

add isInteger to help symfony form choicelist index #520

@woodspire

The pull request for the isInteger function

propelorm/Propel#520

@woodspire

It's my first pull request, so I was monitoring to see if everything was fine.

I saw that the (automated ?) build failed, and I checked why.

The query class used in the test, /Bridge/Propel1/Tests/Fixtures/ItemQuery.php is not correct.

the function getPrimaryKeys() returns an invalid array.

it should not return a string but a ColumnMap class (check in TableMap class and you will see that the primaryKeys private field never contains string, but keyed ColumnMap classes.

I am not currently fluent in how to generate test code, so I cannot help here.

@woodspire

we could add this verification but it should not be necessary:

&& current($this->identifier) instanceof ColumnMap

@woodspire

Nice. I finally found the problems with the test suite and fix them. It also helped me find a problem with my pull request, so I also fixed that at the same time. Now everything pass the automatic build.

@woodspire woodspire referenced this pull request in propelorm/Propel
Merged

Add IsInteger function to ColumnMap #526

@willdurand willdurand commented on the diff
src/Symfony/Bridge/Propel1/Tests/Fixtures/ColumnMap.php
@@ -0,0 +1,61 @@
+<?php

Why don't you use the Propel class?

Well the ColumMap class from Propel except a TableMap object, and looking at the code in Bridge/Propel1/Tests/Fixtures/ItemQuery.php, I saw that this object was implementing some function from TableMap (getPrimaryKeys) instead of using Problem TableMap class. I taught I would need to create the ColumnMap instead of using the Propel one. Trying to use the Propel class return an error saying that a TableMap was expected, but ItemQuery was given.

I simply saw that it seem that no Propel classes were used in these files, so there must have been a good reason. I continued this trend.

Could you use a ColumnMap or not?

No we cannot. ColumnMap expect to be pass a TableMap, an we do not have a table class in the test procedure.

Sorry but I am not here to fix all the test suites because it's not currently properly formatted.

Someone, in the past, decided not to mock a TableMap and use ItemQuery and ReadOnlyItemQuery instead.

I am not here to discuss if their choice was right or not, I was ok creating test cases for my PR, but fixing|rewriting other test cases because they do not match the required formatting expected right now, I do not have the man power to do that and I am not that experience in the Propel code to do so.

I found a problem with my test data, understood why it was happening and found a fix that will not break other people code. Trying to understand other test cases to be able to modify their test so that the test suite looks good, I cannot do.

An I am pretty sure it might not end there, trying to mock TableMap might ask for another class to be mocked, etc ...

@stof Collaborator
stof added a note

@woodspire If what your class is accessing is only the TableMap, you won't need to mock other stuff. The goal of using mocks is to avoid having to build the full dependency graph. You only mock the direct deps.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
...ny/Bridge/Propel1/Form/ChoiceList/ModelChoiceList.php
@@ -69,6 +76,13 @@ public function __construct($class, $labelPath = null, $choices = null, $queryOb
$choices = array();
}
+ if (1 === count($this->identifier)) {
+ // TODO this should be current($this->identifier)->isInteger() when propel ColumnMap contains the isInteger function

I think it's better to keep this behavior, because even if Propel gets this feature, it will be only available for Propel 1.6.8 and upper.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
...ny/Bridge/Propel1/Form/ChoiceList/ModelChoiceList.php
@@ -69,6 +76,13 @@ public function __construct($class, $labelPath = null, $choices = null, $queryOb
$choices = array();
}
+ if (1 === count($this->identifier)) {
+ // TODO this should be current($this->identifier)->isInteger() when propel ColumnMap contains the isInteger function
+ if ($this->isInteger(current($this->identifier))) {
+ $this->identifierAsIndex = true;
+ }
@stof Collaborator
stof added a note

Please use spaces, not tabs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
...y/Bridge/Propel1/Tests/Fixtures/PropelColumnTypes.php
((7 lines not shown))
+ *
+ * @license MIT License
+ */
+
+namespace Symfony\Bridge\Propel1\Tests\Fixtures;
+
+/**
+ * Enumeration of Propel types.
+ *
+ * THIS CLASS MUST BE KEPT UP-TO-DATE WITH THE MORE EXTENSIVE GENERATOR VERSION OF THIS CLASS.
+ *
+ * @author Hans Lellelid <hans@xmpl.org> (Propel)
+ * @version $Revision$
+ * @package propel.runtime.util
+ */
+class PropelColumnTypes
@stof Collaborator
stof added a note

why copying the file from Propel ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@woodspire

I removed the PropelColumnTypes.php copied from Propel and changed ColumnMap to use the Propel file (same way as in the Column.php file)

...ny/Bridge/Propel1/Form/ChoiceList/ModelChoiceList.php
@@ -69,6 +76,12 @@ public function __construct($class, $labelPath = null, $choices = null, $queryOb
$choices = array();
}
+ if (1 === count($this->identifier)) {
+ if ($this->isInteger(current($this->identifier))) {
+ $this->identifierAsIndex = true;
+ }
@stof Collaborator
stof added a note

Please use 4 spaces per level for the indentation, not tabs

You are right. I fixed my commit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@woodspire

Do I need to do anything else ?

...ny/Bridge/Propel1/Form/ChoiceList/ModelChoiceList.php
@@ -69,6 +76,12 @@ public function __construct($class, $labelPath = null, $choices = null, $queryOb
$choices = array();
}
+ if (1 === count($this->identifier)) {
+ if ($this->isInteger(current($this->identifier))) {
@stof Collaborator
stof added a note

you should use && instead of nesting 2 conditions here

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@stof stof commented on the diff
...ny/Bridge/Propel1/Form/ChoiceList/ModelChoiceList.php
@@ -351,4 +364,14 @@ private function getIdentifierValues($model)
return $model->getPrimaryKeys();
}
+
+ /**
+ * Whether this column in an integer
+ *
+ * @return boolean
+ */
+ private function isInteger($col)
@stof Collaborator
stof added a note

you should typehint the argument here

I cannot typehint here, because when running the code in prod, the $col will be an instance of Propel\Runtime\Map\ColumnMap

but in test, the $col will be an instance of Symfony\Bridge\Propel1\Tests\Fixtures\ColumnMap

@stof Collaborator
stof added a note

Then your test is wrong. You should not pass a totally unrelated object. Use mocks or stubs.

But look at the code in Symfony\Bridge\Propel1\TestsFixtures ItemQuery and ReadOnlyItemQuery.

Both these class are unrelated object trying to be a TableMap (check the getTableMap method) !

I am not saying your request cannot be done, I am saying that typehinting ColumnMap will break other test code that are build correct, and theses tests would also be needed to be changed, but I do not understand them, so I cannot change them !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
...y/Bridge/Propel1/Tests/Fixtures/ReadOnlyItemQuery.php
@@ -22,6 +22,8 @@ public function getTableMap()
public function getPrimaryKeys()
{
- return array('id');
+ $cm = new ColumnMap('id', $this);
+ $cm->setType('INTEGER');
+ return array('id' => $cm);
@stof Collaborator
stof added a note

missing empty line before the return statement

I did not knew you require a blank line before a return.

strange because 10 lines about, in the getTableMap method, there is no space between the return statement and the comment line.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@willdurand

#6199 now replaces this PR. Please close that one.

@woodspire woodspire closed this
@fabpot fabpot referenced this pull request from a commit
@fabpot fabpot merged branch willdurand/woodspire-master (PR #6199)
This PR was merged into the master branch.

Commits
-------

a3a832c Fix CS in the whole Propel1 bridge
86ab4b3 Add typehint to isInteger(), fix tests
a26a690 remove useless ColumnMap
ffd8759 fix some formatting issue
6fb9536 fix indentation problem
e5e3341 oups. It seems that here, we need \PDO
36d6c40 fix indentation problem
6f8cd9d Removed the PropelColumnTypes.php copy
8125163 removed the TODO mention. Will keep the Propel code here so it can work with older version of Propel
0e4419b I found the error in my latest commit. This pass the test suite.
cf8a6c0 Fix my code and also fix the test suite.
737b596 Merge remote-tracking branch 'upstream/master'
972e503 Fix problem when 1 column identifier in propel is a string.

Discussion
----------

Fix ModelChoiceList problem with string key

Replaces #6150

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

by willdurand at 2012-12-05T20:51:44Z

Note that 5f54ed1 is a "CS fix" commit. I don't want to open a PR just for that. Let me know if I should to remove it.

Also, I'm :+1: on this PR. Review has been made already, so it seems mergeable.
bf6d9be
@mmucklo mmucklo referenced this pull request from a commit
@fabpot fabpot merged branch willdurand/woodspire-master (PR #6199)
This PR was merged into the master branch.

Commits
-------

a3a832c Fix CS in the whole Propel1 bridge
86ab4b3 Add typehint to isInteger(), fix tests
a26a690 remove useless ColumnMap
ffd8759 fix some formatting issue
6fb9536 fix indentation problem
e5e3341 oups. It seems that here, we need \PDO
36d6c40 fix indentation problem
6f8cd9d Removed the PropelColumnTypes.php copy
8125163 removed the TODO mention. Will keep the Propel code here so it can work with older version of Propel
0e4419b I found the error in my latest commit. This pass the test suite.
cf8a6c0 Fix my code and also fix the test suite.
737b596 Merge remote-tracking branch 'upstream/master'
972e503 Fix problem when 1 column identifier in propel is a string.

Discussion
----------

Fix ModelChoiceList problem with string key

Replaces #6150

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

by willdurand at 2012-12-05T20:51:44Z

Note that 5f54ed1 is a "CS fix" commit. I don't want to open a PR just for that. Let me know if I should to remove it.

Also, I'm :+1: on this PR. Review has been made already, so it seems mergeable.
4136b75
@c33s c33s referenced this pull request from a commit in c33s/Propel
Felix Labrecque Used by PR symfony/symfony#6150 db4da49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Nov 29, 2012
  1. Fix problem when 1 column identifier in propel is a string.

    Felix Labrecque authored
    The ModelChoiceList thinks it can be used as the index of the ChoiceList, when it can only be used if it is an integer.
Commits on Dec 4, 2012
  1. Merge remote-tracking branch 'upstream/master'

    Felix Labrecque authored
  2. Fix my code and also fix the test suite.

    Felix Labrecque authored
  3. @woodspire

    removed the TODO mention. Will keep the Propel code here so it can wo…

    woodspire authored
    …rk with older version of Propel
  4. @woodspire

    Removed the PropelColumnTypes.php copy

    woodspire authored
    Using the Propel class instead, like in Column class
Commits on Dec 5, 2012
  1. @woodspire

    fix indentation problem

    woodspire authored
  2. @woodspire
  3. @woodspire

    fix indentation problem

    woodspire authored
  4. @woodspire
This page is out of date. Refresh to see the latest.
View
28 src/Symfony/Bridge/Propel1/Form/ChoiceList/ModelChoiceList.php
@@ -46,6 +46,13 @@ class ModelChoiceList extends ObjectChoiceList
private $loaded = false;
/**
+ * Whether to use the identifier for index generation
+ *
+ * @var Boolean
+ */
+ private $identifierAsIndex = false;
+
+ /**
* @param string $class
* @param string $labelPath
* @param array $choices
@@ -69,6 +76,11 @@ public function __construct($class, $labelPath = null, $choices = null, $queryOb
$choices = array();
}
+ if ( 1 === count($this->identifier)
+ && $this->isInteger(current($this->identifier))) {
+ $this->identifierAsIndex = true;
+ }
+
parent::__construct($choices, $labelPath, array(), $groupPath);
}
@@ -224,7 +236,7 @@ public function getIndicesForChoices(array $models)
// know that the IDs are used as indices
// Attention: This optimization does not check choices for existence
- if (1 === count($this->identifier)) {
+ if ($this->identifierAsIndex) {
$indices = array();
foreach ($models as $model) {
@@ -259,7 +271,7 @@ public function getIndicesForValues(array $values)
// know that the IDs are used as indices and values
// Attention: This optimization does not check values for existence
- if (1 === count($this->identifier)) {
+ if ($this->identifierAsIndex) {
return $this->fixIndices($values);
}
@@ -283,7 +295,7 @@ public function getIndicesForValues(array $values)
*/
protected function createIndex($model)
{
- if (1 === count($this->identifier)) {
+ if ($this->identifierAsIndex) {
return current($this->getIdentifierValues($model));
}
@@ -351,4 +363,14 @@ private function getIdentifierValues($model)
return $model->getPrimaryKeys();
}
+
+ /**
+ * Whether this column in an integer
+ *
+ * @return boolean
+ */
+ private function isInteger($col)
@stof Collaborator
stof added a note

you should typehint the argument here

I cannot typehint here, because when running the code in prod, the $col will be an instance of Propel\Runtime\Map\ColumnMap

but in test, the $col will be an instance of Symfony\Bridge\Propel1\Tests\Fixtures\ColumnMap

@stof Collaborator
stof added a note

Then your test is wrong. You should not pass a totally unrelated object. Use mocks or stubs.

But look at the code in Symfony\Bridge\Propel1\TestsFixtures ItemQuery and ReadOnlyItemQuery.

Both these class are unrelated object trying to be a TableMap (check the getTableMap method) !

I am not saying your request cannot be done, I am saying that typehinting ColumnMap will break other test code that are build correct, and theses tests would also be needed to be changed, but I do not understand them, so I cannot change them !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ {
+ return $col->getPdoType() === \PDO::PARAM_INT;
+ }
}
View
61 src/Symfony/Bridge/Propel1/Tests/Fixtures/ColumnMap.php
@@ -0,0 +1,61 @@
+<?php

Why don't you use the Propel class?

Well the ColumMap class from Propel except a TableMap object, and looking at the code in Bridge/Propel1/Tests/Fixtures/ItemQuery.php, I saw that this object was implementing some function from TableMap (getPrimaryKeys) instead of using Problem TableMap class. I taught I would need to create the ColumnMap instead of using the Propel one. Trying to use the Propel class return an error saying that a TableMap was expected, but ItemQuery was given.

I simply saw that it seem that no Propel classes were used in these files, so there must have been a good reason. I continued this trend.

Could you use a ColumnMap or not?

No we cannot. ColumnMap expect to be pass a TableMap, an we do not have a table class in the test procedure.

Sorry but I am not here to fix all the test suites because it's not currently properly formatted.

Someone, in the past, decided not to mock a TableMap and use ItemQuery and ReadOnlyItemQuery instead.

I am not here to discuss if their choice was right or not, I was ok creating test cases for my PR, but fixing|rewriting other test cases because they do not match the required formatting expected right now, I do not have the man power to do that and I am not that experience in the Propel code to do so.

I found a problem with my test data, understood why it was happening and found a fix that will not break other people code. Trying to understand other test cases to be able to modify their test so that the test suite looks good, I cannot do.

An I am pretty sure it might not end there, trying to mock TableMap might ask for another class to be mocked, etc ...

@stof Collaborator
stof added a note

@woodspire If what your class is accessing is only the TableMap, you won't need to mock other stuff. The goal of using mocks is to avoid having to build the full dependency graph. You only mock the direct deps.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+
+/*
+ * 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\Tests\Fixtures;
+
+class ColumnMap
+{
+ // Propel type of the column
+ protected $type;
+
+ // The TableMap for this column
+ protected $table;
+
+ // The name of the column
+ protected $columnName;
+
+ public function __construct($name, $containingTable)
+ {
+ $this->columnName = $name;
+ $this->table = $containingTable;
+ }
+
+ /**
+ * Set the Propel type of this column.
+ *
+ * @param string $type A string representing the Propel type (e.g. PropelColumnTypes::DATE).
+ * @return void
+ */
+ public function setType($type)
+ {
+ $this->type = $type;
+ }
+
+ /**
+ * Get the Propel type of this column.
+ *
+ * @return string A string representing the Propel type (e.g. PropelColumnTypes::DATE).
+ */
+ public function getType()
+ {
+ return $this->type;
+ }
+
+ /**
+ * Get the PDO type of this column.
+ *
+ * @return int The PDO::PARMA_* value
+ */
+ public function getPdoType()
+ {
+ return \PropelColumnTypes::getPdoType($this->type);
+ }
+}
View
5 src/Symfony/Bridge/Propel1/Tests/Fixtures/ItemQuery.php
@@ -31,7 +31,10 @@ public function getTableMap()
public function getPrimaryKeys()
{
- return array('id');
+ $cm = new ColumnMap('id', $this);
+ $cm->setType('INTEGER');
+
+ return array('id' => $cm);
}
/**
View
5 src/Symfony/Bridge/Propel1/Tests/Fixtures/ReadOnlyItemQuery.php
@@ -22,6 +22,9 @@ public function getTableMap()
public function getPrimaryKeys()
{
- return array('id');
+ $cm = new ColumnMap('id', $this);
+ $cm->setType('INTEGER');
+
+ return array('id' => $cm);
}
}
Something went wrong with that request. Please try again.