initial commit

This commit is contained in:
Chris Sewell
2012-11-28 03:55:08 -05:00
parent 7adb399b2e
commit cf140a2e97
3247 changed files with 492437 additions and 0 deletions

View File

@ -0,0 +1,385 @@
<?php
/*
* This file is part of the symfony package.
* (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* This class is the Propel implementation of sfData. It interacts with the data source
* and loads data.
*
* @package symfony
* @subpackage addon
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
* @version SVN: $Id: sfPropelData.class.php 5339 2007-10-01 07:35:33Z fabien $
*/
class sfPropelData extends sfData
{
protected
$maps = array(),
$deletedClasses = array(),
$con = null;
// symfony load-data (file|dir)
/**
* Loads data from a file or directory into a Propel data source
*
* @param mixed A file or directory path
* @param string The Propel connection name, default 'propel'
*
* @throws Exception If the database throws an error, rollback transaction and rethrows exception
*/
public function loadData($directory_or_file = null, $connectionName = 'propel')
{
$fixture_files = $this->getFiles($directory_or_file);
// wrap all database operations in a single transaction
$this->con = Propel::getConnection($connectionName);
try
{
$this->con->begin();
$this->doDeleteCurrentData($fixture_files);
$this->doLoadData($fixture_files);
$this->con->commit();
}
catch (Exception $e)
{
$this->con->rollback();
throw $e;
}
}
/**
* Implements the abstract loadDataFromArray method and loads the data using the generated data model.
*
* @param array The data to be loaded into the data source
*
* @throws Exception If data is unnamed.
* @throws sfException If an object defined in the model does not exist in the data
* @throws sfException If a column that does not exist is referenced
*/
public function loadDataFromArray($data)
{
if ($data === null)
{
// no data
return;
}
foreach ($data as $class => $datas)
{
$class = trim($class);
$peer_class = $class.'Peer';
// load map class
$this->loadMapBuilder($class);
$tableMap = $this->maps[$class]->getDatabaseMap()->getTable(constant($peer_class.'::TABLE_NAME'));
$column_names = call_user_func_array(array($peer_class, 'getFieldNames'), array(BasePeer::TYPE_FIELDNAME));
// iterate through datas for this class
// might have been empty just for force a table to be emptied on import
if (!is_array($datas))
{
continue;
}
foreach ($datas as $key => $data)
{
// create a new entry in the database
$obj = new $class();
if (!is_array($data))
{
throw new Exception(sprintf('You must give a name for each fixture data entry (class %s)'), $class);
}
foreach ($data as $name => $value)
{
// foreign key?
try
{
$column = $tableMap->getColumn($name);
if ($column->isForeignKey() && !is_null($value))
{
$relatedTable = $this->maps[$class]->getDatabaseMap()->getTable($column->getRelatedTableName());
if (!isset($this->object_references[$relatedTable->getPhpName().'_'.$value]))
{
$error = 'The object "%s" from class "%s" is not defined in your data file.';
$error = sprintf($error, $value, $relatedTable->getPhpName());
throw new sfException($error);
}
$value = $this->object_references[$relatedTable->getPhpName().'_'.$value];
}
}
catch (PropelException $e)
{
}
$pos = array_search($name, $column_names);
$method = 'set'.sfInflector::camelize($name);
if ($pos)
{
$obj->setByPosition($pos, $value);
}
else if (is_callable(array($obj, $method)))
{
$obj->$method($value);
}
else
{
$error = 'Column "%s" does not exist for class "%s"';
$error = sprintf($error, $name, $class);
throw new sfException($error);
}
}
$obj->save($this->con);
// save the id for future reference
if (method_exists($obj, 'getPrimaryKey'))
{
$this->object_references[$class.'_'.$key] = $obj->getPrimaryKey();
}
}
}
}
/**
* Clears existing data from the data source by reading the fixture files
* and deleting the existing data for only those classes that are mentioned
* in the fixtures.
*
* @param array The list of YAML files.
*
* @throws sfException If a class mentioned in a fixture can not be found
*/
protected function doDeleteCurrentData($fixture_files)
{
// delete all current datas in database
if (!$this->deleteCurrentData)
{
return;
}
rsort($fixture_files);
foreach ($fixture_files as $fixture_file)
{
$data = sfYaml::load($fixture_file);
if ($data === null)
{
// no data
continue;
}
$classes = array_keys($data);
krsort($classes);
foreach ($classes as $class)
{
$class = trim($class);
if (in_array($class, $this->deletedClasses))
{
continue;
}
$peer_class = $class.'Peer';
if (!$classPath = sfCore::getClassPath($peer_class))
{
throw new sfException(sprintf('Unable to find path for class "%s".', $peer_class));
}
require_once($classPath);
call_user_func(array($peer_class, 'doDeleteAll'), $this->con);
$this->deletedClasses[] = $class;
}
}
}
/**
* Loads the mappings for the classes
*
* @param string The model class name
*
* @throws sfException If the class cannot be found
*/
protected function loadMapBuilder($class)
{
$mapBuilderClass = $class.'MapBuilder';
if (!isset($this->maps[$class]))
{
if (!$classPath = sfCore::getClassPath($mapBuilderClass))
{
throw new sfException(sprintf('Unable to find path for class "%s".', $mapBuilderClass));
}
require_once($classPath);
$this->maps[$class] = new $mapBuilderClass();
$this->maps[$class]->doBuild();
}
}
/**
* Dumps data to fixture from one or more tables.
*
* @param string directory or file to dump to
* @param mixed name or names of tables to dump (or all to dump all tables)
* @param string connection name
*/
public function dumpData($directory_or_file = null, $tables = 'all', $connectionName = 'propel')
{
$sameFile = true;
if (is_dir($directory_or_file))
{
// multi files
$sameFile = false;
}
else
{
// same file
// delete file
}
$this->con = Propel::getConnection($connectionName);
// get tables
if ('all' === $tables || is_null($tables))
{
// load all map builder classes
$files = sfFinder::type('file')->name('*MapBuilder.php')->in(sfLoader::getModelDirs());
foreach ($files as $file)
{
$mapBuilderClass = basename($file, '.php');
$map = new $mapBuilderClass();
$map->doBuild();
}
$dbMap = Propel::getDatabaseMap($connectionName);
$tables = array();
foreach ($dbMap->getTables() as $table)
{
$tables[] = $table->getPhpName();
}
}
else if (!is_array($tables))
{
$tables = array($tables);
}
$dumpData = array();
// load map classes
array_walk($tables, array($this, 'loadMapBuilder'));
$tables = $this->fixOrderingOfForeignKeyData($tables);
foreach ($tables as $tableName)
{
$tableMap = $this->maps[$tableName]->getDatabaseMap()->getTable(constant($tableName.'Peer::TABLE_NAME'));
// get db info
$rs = $this->con->executeQuery('SELECT * FROM '.constant($tableName.'Peer::TABLE_NAME'));
while ($rs->next())
{
$pk = $tableName;
$values = array();
foreach ($tableMap->getColumns() as $column)
{
$col = strtolower($column->getColumnName());
if ($column->isPrimaryKey())
{
$pk .= '_'.$rs->get($col);
}
else if ($column->isForeignKey())
{
$relatedTable = $this->maps[$tableName]->getDatabaseMap()->getTable($column->getRelatedTableName());
$values[$col] = $relatedTable->getPhpName().'_'.$rs->get($col);
}
else
{
$values[$col] = $rs->get($col);
}
}
if (!isset($dumpData[$tableName]))
{
$dumpData[$tableName] = array();
}
$dumpData[$tableName][$pk] = $values;
}
}
// save to file(s)
if ($sameFile)
{
file_put_contents($directory_or_file, Spyc::YAMLDump($dumpData));
}
else
{
$i = 0;
foreach ($tables as $tableName)
{
if (!isset($dumpData[$tableName]))
{
continue;
}
file_put_contents(sprintf("%s/%03d-%s.yml", $directory_or_file, ++$i, $tableName), Spyc::YAMLDump(array($tableName => $dumpData[$tableName])));
}
}
}
/**
* Fixes the ordering of foreign key data, by outputting data a foreign key depends on before the table with the foreign key.
*
* @param array The array with the class names.
*/
public function fixOrderingOfForeignKeyData($classes)
{
// reordering classes to take foreign keys into account
for ($i = 0, $count = count($classes); $i < $count; $i++)
{
$class = $classes[$i];
$tableMap = $this->maps[$class]->getDatabaseMap()->getTable(constant($class.'Peer::TABLE_NAME'));
foreach ($tableMap->getColumns() as $column)
{
if ($column->isForeignKey())
{
$relatedTable = $this->maps[$class]->getDatabaseMap()->getTable($column->getRelatedTableName());
$relatedTablePos = array_search($relatedTable->getPhpName(), $classes);
// check if relatedTable is after the current table
if ($relatedTablePos > $i)
{
// move related table 1 position before current table
$classes = array_merge(
array_slice($classes, 0, $i),
array($classes[$relatedTablePos]),
array_slice($classes, $i, $relatedTablePos - $i),
array_slice($classes, $relatedTablePos + 1)
);
// we have moved a table, so let's see if we are done
return $this->fixOrderingOfForeignKeyData($classes);
}
}
}
}
return $classes;
}
}