mirror of
https://github.com/atlanticbiomedical/portal-legacy.git
synced 2025-07-02 01:47:28 -04:00
initial commit
This commit is contained in:
385
lib/symfony/addon/propel/sfPropelData.class.php
Executable file
385
lib/symfony/addon/propel/sfPropelData.class.php
Executable 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;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user