[DataFixtures] Fixed N-N relations
This commit is contained in:
parent
35dbf79170
commit
2e7bb13431
|
@ -11,7 +11,6 @@
|
|||
namespace Propel\PropelBundle\DataFixtures;
|
||||
|
||||
use \Propel;
|
||||
|
||||
use Symfony\Component\Finder\Finder;
|
||||
|
||||
/**
|
||||
|
@ -65,7 +64,10 @@ abstract class AbstractDataHandler
|
|||
|
||||
if (0 === count($this->dbMap->getTables())) {
|
||||
$finder = new Finder();
|
||||
$files = $finder->files()->name('*TableMap.php')->in($this->getRootDir() . '/../')->exclude('Tests');
|
||||
$files = $finder->files()->name('*TableMap.php')
|
||||
->in($this->getRootDir() . '/../')
|
||||
->exclude('PropelBundle')
|
||||
->exclude('Tests');
|
||||
|
||||
foreach ($files as $file) {
|
||||
$class = $this->guessFullClassName($file->getRelativePath(), basename($file, '.php'));
|
||||
|
|
|
@ -10,15 +10,14 @@
|
|||
|
||||
namespace Propel\PropelBundle\DataFixtures\Loader;
|
||||
|
||||
use \Propel;
|
||||
|
||||
use \BasePeer;
|
||||
use \BaseObject;
|
||||
use \ColumnMap;
|
||||
use \Propel;
|
||||
use \PropelException;
|
||||
|
||||
use Propel\PropelBundle\DataFixtures\AbstractDataHandler;
|
||||
use Propel\PropelBundle\Util\PropelInflector;
|
||||
|
||||
use Symfony\Component\Finder\Finder;
|
||||
|
||||
/**
|
||||
|
@ -156,13 +155,13 @@ abstract class AbstractDataLoader extends AbstractDataHandler implements DataLoa
|
|||
}
|
||||
|
||||
foreach ($data as $name => $value) {
|
||||
try {
|
||||
if (is_array($value) && 's' === substr($name, -1)) {
|
||||
try {
|
||||
// many to many relationship
|
||||
$this->loadManyToMany($obj, substr($name, 0, -1), $value);
|
||||
|
||||
continue;
|
||||
}
|
||||
} catch (\PropelException $e) {
|
||||
} catch (PropelException $e) {
|
||||
// Check whether this is actually an array stored in the object.
|
||||
if ('Cannot fetch TableMap for undefined table: '.substr($name, 0, -1) === $e->getMessage()) {
|
||||
if ('ARRAY' !== $tableMap->getColumn($name)->getType()) {
|
||||
|
@ -170,6 +169,7 @@ abstract class AbstractDataLoader extends AbstractDataHandler implements DataLoa
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$isARealColumn = true;
|
||||
if ($tableMap->hasColumn($name)) {
|
||||
|
@ -206,8 +206,7 @@ abstract class AbstractDataLoader extends AbstractDataHandler implements DataLoa
|
|||
|
||||
if (false !== $pos = array_search($name, $column_names)) {
|
||||
$obj->setByPosition($pos, $value);
|
||||
}
|
||||
elseif (is_callable(array($obj, $method = 'set'.ucfirst(PropelInflector::camelize($name))))) {
|
||||
} elseif (is_callable(array($obj, $method = 'set'.ucfirst(PropelInflector::camelize($name))))) {
|
||||
$obj->$method($value);
|
||||
} else {
|
||||
throw new \InvalidArgumentException(sprintf('Column "%s" does not exist for class "%s".', $name, $class));
|
||||
|
@ -234,12 +233,17 @@ abstract class AbstractDataLoader extends AbstractDataHandler implements DataLoa
|
|||
protected function loadManyToMany($obj, $middleTableName, $values)
|
||||
{
|
||||
$middleTable = $this->dbMap->getTable($middleTableName);
|
||||
$middleClass = $middleTable->getPhpName();
|
||||
$middleClass = $middleTable->getClassname();
|
||||
$tableName = constant(constant(get_class($obj).'::PEER').'::TABLE_NAME');
|
||||
|
||||
foreach ($middleTable->getColumns() as $column) {
|
||||
if ($column->isForeignKey() && constant(constant(get_class($obj).'::PEER').'::TABLE_NAME') != $column->getRelatedTableName()) {
|
||||
$relatedClass = $this->dbMap->getTable($column->getRelatedTableName())->getPhpName();
|
||||
break;
|
||||
if ($column->isForeignKey()) {
|
||||
if ($tableName !== $column->getRelatedTableName()) {
|
||||
$relatedClass = $this->dbMap->getTable($column->getRelatedTableName())->getClassname();
|
||||
$relatedSetter = 'set' . $column->getRelation()->getName();
|
||||
} else {
|
||||
$setter = 'set' . $column->getRelation()->getName();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -247,9 +251,6 @@ abstract class AbstractDataLoader extends AbstractDataHandler implements DataLoa
|
|||
throw new \InvalidArgumentException(sprintf('Unable to find the many-to-many relationship for object "%s".', get_class($obj)));
|
||||
}
|
||||
|
||||
$setter = 'set'.get_class($obj);
|
||||
$relatedSetter = 'set'.$relatedClass;
|
||||
|
||||
foreach ($values as $value) {
|
||||
if (!isset($this->object_references[$relatedClass.'_'.$value])) {
|
||||
throw new \InvalidArgumentException(
|
||||
|
|
|
@ -262,15 +262,26 @@ A valid _XML fixtures file_ is:
|
|||
A valid _YAML fixtures file_ is:
|
||||
|
||||
``` yaml
|
||||
\Awesome\Object:
|
||||
Awesome\Object:
|
||||
o1:
|
||||
Title: My title
|
||||
MyFoo: bar
|
||||
|
||||
\Awesome\Related:
|
||||
Awesome\Related:
|
||||
r1:
|
||||
ObjectId: o1
|
||||
Description: Hello world !
|
||||
|
||||
Awesome\Tag:
|
||||
t1:
|
||||
name: Foo
|
||||
t2:
|
||||
name: Baz
|
||||
|
||||
Awesome\Post:
|
||||
p1:
|
||||
title: A Post with tags (N-N relation)
|
||||
tags: [ t1, t2 ]
|
||||
```
|
||||
|
||||
You can load all fixtures files from a given _bundle_:
|
||||
|
|
|
@ -49,24 +49,24 @@ YAML;
|
|||
{
|
||||
$schema = <<<XML
|
||||
<database name="default" package="vendor.bundles.Propel.PropelBundle.Tests.Fixtures.DataFixtures.Loader" namespace="Propel\PropelBundle\Tests\Fixtures\DataFixtures\Loader" defaultIdMethod="native">
|
||||
<table name="book" phpName="YamlManyToManyBook">
|
||||
<table name="table_book" phpName="YamlManyToManyBook">
|
||||
<column name="id" type="integer" primaryKey="true" />
|
||||
<column name="name" type="varchar" size="255" />
|
||||
</table>
|
||||
|
||||
<table name="author" phpName="YamlManyToManyAuthor">
|
||||
<table name="table_author" phpName="YamlManyToManyAuthor">
|
||||
<column name="id" type="integer" primaryKey="true" />
|
||||
<column name="name" type="varchar" size="255" />
|
||||
</table>
|
||||
|
||||
<table name="book_author" phpName="YamlManyToManyBookAuthor">
|
||||
<table name="table_book_author" phpName="YamlManyToManyBookAuthor" isCrossRef="true">
|
||||
<column name="book_id" type="integer" required="true" primaryKey="true" />
|
||||
<column name="author_id" type="integer" required="true" primaryKey="true" />
|
||||
|
||||
<foreign-key foreignTable="book" phpName="Book" onDelete="CASCADE" onUpdate="CASCADE">
|
||||
<foreign-key foreignTable="table_book" phpName="Book" onDelete="CASCADE" onUpdate="CASCADE">
|
||||
<reference local="book_id" foreign="id" />
|
||||
</foreign-key>
|
||||
<foreign-key foreignTable="author" phpName="Author" onDelete="CASCADE" onUpdate="CASCADE">
|
||||
<foreign-key foreignTable="table_author" phpName="Author" onDelete="CASCADE" onUpdate="CASCADE">
|
||||
<reference local="author_id" foreign="id" />
|
||||
</foreign-key>
|
||||
</table>
|
||||
|
@ -74,17 +74,27 @@ YAML;
|
|||
XML;
|
||||
|
||||
$fixtures = <<<YAML
|
||||
Propel\PropelBundle\Tests\Fixtures\DataFixtures\Loader\YamlManyToManyAuthor:
|
||||
Author_1:
|
||||
name: 'A famous one'
|
||||
Propel\PropelBundle\Tests\Fixtures\DataFixtures\Loader\YamlManyToManyBook:
|
||||
Book_1:
|
||||
id: 1
|
||||
name: 'An important one'
|
||||
Book_2:
|
||||
id: 2
|
||||
name: 'Les misérables'
|
||||
|
||||
Propel\PropelBundle\Tests\Fixtures\DataFixtures\Loader\YamlManyToManyAuthor:
|
||||
Author_1:
|
||||
id: 1
|
||||
name: 'A famous one'
|
||||
Author_2:
|
||||
id: 2
|
||||
name: 'Victor Hugo'
|
||||
table_book_authors: [ Book_2 ]
|
||||
|
||||
Propel\PropelBundle\Tests\Fixtures\DataFixtures\Loader\YamlManyToManyBookAuthor:
|
||||
BookAuthor_1:
|
||||
book_id: Book_1
|
||||
author_id: Author_1
|
||||
|
||||
YAML;
|
||||
|
||||
$filename = $this->getTempFile($fixtures);
|
||||
|
@ -97,16 +107,23 @@ YAML;
|
|||
$loader->load(array($filename), 'default');
|
||||
|
||||
$books = \Propel\PropelBundle\Tests\Fixtures\DataFixtures\Loader\YamlManyToManyBookPeer::doSelect(new \Criteria(), $con);
|
||||
$this->assertCount(1, $books);
|
||||
$this->assertCount(2, $books);
|
||||
$this->assertInstanceOf('Propel\PropelBundle\Tests\Fixtures\DataFixtures\Loader\YamlManyToManyBook', $books[0]);
|
||||
$this->assertInstanceOf('Propel\PropelBundle\Tests\Fixtures\DataFixtures\Loader\YamlManyToManyBook', $books[1]);
|
||||
|
||||
$authors = \Propel\PropelBundle\Tests\Fixtures\DataFixtures\Loader\YamlManyToManyAuthorPeer::doSelect(new \Criteria(), $con);
|
||||
$this->assertCount(1, $authors);
|
||||
$this->assertCount(2, $authors);
|
||||
$this->assertInstanceOf('Propel\PropelBundle\Tests\Fixtures\DataFixtures\Loader\YamlManyToManyAuthor', $authors[0]);
|
||||
$this->assertInstanceOf('Propel\PropelBundle\Tests\Fixtures\DataFixtures\Loader\YamlManyToManyAuthor', $authors[1]);
|
||||
|
||||
$bookAuthors = \Propel\PropelBundle\Tests\Fixtures\DataFixtures\Loader\YamlManyToManyBookAuthorPeer::doSelect(new \Criteria(), $con);
|
||||
$this->assertCount(1, $bookAuthors);
|
||||
$this->assertCount(2, $bookAuthors);
|
||||
$this->assertInstanceOf('Propel\PropelBundle\Tests\Fixtures\DataFixtures\Loader\YamlManyToManyBookAuthor', $bookAuthors[0]);
|
||||
$this->assertInstanceOf('Propel\PropelBundle\Tests\Fixtures\DataFixtures\Loader\YamlManyToManyBookAuthor', $bookAuthors[1]);
|
||||
|
||||
$this->assertEquals('Victor Hugo', $authors[1]->getName());
|
||||
$this->assertTrue($authors[1]->getBooks()->contains($books[1]));
|
||||
$this->assertEquals('Les misérables', $authors[1]->getBooks()->get(0)->getName());
|
||||
}
|
||||
|
||||
public function testLoadSelfReferencing()
|
||||
|
|
|
@ -56,9 +56,7 @@ XML;
|
|||
|
||||
$builder = new \PropelQuickBuilder();
|
||||
$builder->setSchema($schema);
|
||||
if (!class_exists('Propel\PropelBundle\Tests\Fixtures\DataFixtures\Loader\Book')) {
|
||||
$builder->setClassTargets(array('peer', 'object', 'query', 'peerstub', 'objectstub', 'querystub'));
|
||||
} else {
|
||||
if (class_exists('Propel\PropelBundle\Tests\Fixtures\DataFixtures\Loader\Book')) {
|
||||
$builder->setClassTargets(array());
|
||||
}
|
||||
|
||||
|
|
|
@ -1,58 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Propel\PropelBundle\Tests\Fixtures\DataFixtures\Loader\map;
|
||||
|
||||
use \RelationMap;
|
||||
use \TableMap;
|
||||
|
||||
|
||||
/**
|
||||
* This class defines the structure of the 'author' table.
|
||||
*
|
||||
*
|
||||
*
|
||||
* This map class is used by Propel to do runtime db structure discovery.
|
||||
* For example, the createSelectSql() method checks the type of a given column used in an
|
||||
* ORDER BY clause to know whether it needs to apply SQL to make the ORDER BY case-insensitive
|
||||
* (i.e. if it's a text column type).
|
||||
*
|
||||
* @package propel.generator.vendor.bundles.Propel.PropelBundle.Tests.Fixtures.DataFixtures.Loader.map
|
||||
*/
|
||||
class BookAuthorTableMap extends TableMap
|
||||
{
|
||||
|
||||
/**
|
||||
* The (dot-path) name of this class
|
||||
*/
|
||||
const CLASS_NAME = 'vendor.bundles.Propel.PropelBundle.Tests.Fixtures.DataFixtures.Loader.map.BookAuthorTableMap';
|
||||
|
||||
/**
|
||||
* Initialize the table attributes, columns and validators
|
||||
* Relations are not initialized by this method since they are lazy loaded
|
||||
*
|
||||
* @return void
|
||||
* @throws PropelException
|
||||
*/
|
||||
public function initialize()
|
||||
{
|
||||
// attributes
|
||||
$this->setName('book_author');
|
||||
$this->setPhpName('BookAuthor');
|
||||
$this->setClassname('Propel\\PropelBundle\\Tests\\Fixtures\\DataFixtures\\Loader\\BookAuthor');
|
||||
$this->setPackage('vendor.bundles.Propel.PropelBundle.Tests.Fixtures.DataFixtures.Loader');
|
||||
$this->setUseIdGenerator(false);
|
||||
// columns
|
||||
$this->addPrimaryKey('ID', 'Id', 'INTEGER', true, null, null);
|
||||
$this->addColumn('NAME', 'Name', 'VARCHAR', false, 255, null);
|
||||
// validators
|
||||
} // initialize()
|
||||
|
||||
/**
|
||||
* Build the RelationMap objects for this table relationships
|
||||
*/
|
||||
public function buildRelations()
|
||||
{
|
||||
$this->addRelation('Book', 'Propel\\PropelBundle\\Tests\\Fixtures\\DataFixtures\\Loader\\Book', RelationMap::ONE_TO_MANY, array('id' => 'author_id', ), 'RESTRICT', 'CASCADE', 'Books');
|
||||
} // buildRelations()
|
||||
|
||||
} // AuthorTableMap
|
|
@ -1,59 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Propel\PropelBundle\Tests\Fixtures\DataFixtures\Loader\map;
|
||||
|
||||
use \RelationMap;
|
||||
use \TableMap;
|
||||
|
||||
|
||||
/**
|
||||
* This class defines the structure of the 'book' table.
|
||||
*
|
||||
*
|
||||
*
|
||||
* This map class is used by Propel to do runtime db structure discovery.
|
||||
* For example, the createSelectSql() method checks the type of a given column used in an
|
||||
* ORDER BY clause to know whether it needs to apply SQL to make the ORDER BY case-insensitive
|
||||
* (i.e. if it's a text column type).
|
||||
*
|
||||
* @package propel.generator.vendor.bundles.Propel.PropelBundle.Tests.Fixtures.DataFixtures.Loader.map
|
||||
*/
|
||||
class BookTableMap extends TableMap
|
||||
{
|
||||
|
||||
/**
|
||||
* The (dot-path) name of this class
|
||||
*/
|
||||
const CLASS_NAME = 'vendor.bundles.Propel.PropelBundle.Tests.Fixtures.DataFixtures.Loader.map.BookTableMap';
|
||||
|
||||
/**
|
||||
* Initialize the table attributes, columns and validators
|
||||
* Relations are not initialized by this method since they are lazy loaded
|
||||
*
|
||||
* @return void
|
||||
* @throws PropelException
|
||||
*/
|
||||
public function initialize()
|
||||
{
|
||||
// attributes
|
||||
$this->setName('book');
|
||||
$this->setPhpName('Book');
|
||||
$this->setClassname('Propel\\PropelBundle\\Tests\\Fixtures\\DataFixtures\\Loader\\Book');
|
||||
$this->setPackage('vendor.bundles.Propel.PropelBundle.Tests.Fixtures.DataFixtures.Loader');
|
||||
$this->setUseIdGenerator(false);
|
||||
// columns
|
||||
$this->addPrimaryKey('ID', 'Id', 'INTEGER', true, null, null);
|
||||
$this->addColumn('NAME', 'Name', 'VARCHAR', false, 255, null);
|
||||
$this->addForeignKey('AUTHOR_ID', 'AuthorId', 'INTEGER', 'book_author', 'ID', true, null, null);
|
||||
// validators
|
||||
} // initialize()
|
||||
|
||||
/**
|
||||
* Build the RelationMap objects for this table relationships
|
||||
*/
|
||||
public function buildRelations()
|
||||
{
|
||||
$this->addRelation('BookAuthor', 'Propel\\PropelBundle\\Tests\\Fixtures\\DataFixtures\\Loader\\BookAuthor', RelationMap::MANY_TO_ONE, array('author_id' => 'id', ), 'RESTRICT', 'CASCADE');
|
||||
} // buildRelations()
|
||||
|
||||
} // BookTableMap
|
|
@ -13,7 +13,7 @@
|
|||
"propel/propel1": "1.6.*"
|
||||
},
|
||||
"require-dev": {
|
||||
"sensio/framework-extra-bundle": "*"
|
||||
"sensio/framework-extra-bundle": "dev-master"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": { "Propel\\PropelBundle": "" }
|
||||
|
|
Loading…
Reference in a new issue