362 lines
8.9 KiB
PHP
362 lines
8.9 KiB
PHP
|
<?php
|
||
|
/*
|
||
|
* This file is part of the sfDoctrine package.
|
||
|
* (c) 2006 Olivier Verdier <Olivier.Verdier@gmail.com>
|
||
|
*
|
||
|
* For the full copyright and license information, please view the LICENSE
|
||
|
* file that was distributed with this source code.
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* @package sfDoctrinePlugin
|
||
|
* @subpackage sfDoctrineData
|
||
|
* @author Olivier Verdier <Olivier.Verdier@gmail.com>
|
||
|
* @version SVN: $Id: sfDoctrineData.class.php 4493 2007-06-30 00:47:02Z Jonathan.Wage $
|
||
|
*/
|
||
|
class sfDoctrineData extends sfData
|
||
|
{
|
||
|
/**
|
||
|
* connectionName
|
||
|
*
|
||
|
* @var mixed
|
||
|
* @access protected
|
||
|
*/
|
||
|
protected $connectionName = null;
|
||
|
|
||
|
/**
|
||
|
* loadData
|
||
|
*
|
||
|
* @param mixed $directory_or_file
|
||
|
* @param mixed $connectionName
|
||
|
* @access public
|
||
|
* @return void
|
||
|
*/
|
||
|
public function loadData($directory_or_file = null, $connectionName = null)
|
||
|
{
|
||
|
$this->connectionName = $connectionName;
|
||
|
|
||
|
$fixture_files = $this->getFiles($directory_or_file);
|
||
|
|
||
|
// wrap all database operations in a single transaction
|
||
|
$con = sfDoctrine::connection($connectionName);
|
||
|
try
|
||
|
{
|
||
|
$con->beginTransaction();
|
||
|
|
||
|
$this->doLoadData($fixture_files);
|
||
|
|
||
|
$con->commit();
|
||
|
}
|
||
|
catch (Exception $e)
|
||
|
{
|
||
|
$con->rollback();
|
||
|
throw $e;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* loadDataFromArray
|
||
|
*
|
||
|
* @param mixed $data
|
||
|
* @access public
|
||
|
* @return void
|
||
|
*/
|
||
|
public function loadDataFromArray($data)
|
||
|
{
|
||
|
$pendingRelations = array();
|
||
|
|
||
|
if ($data === null)
|
||
|
{
|
||
|
// no data
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// only for pake_echo_action
|
||
|
require_once(sfConfig::get('sf_symfony_lib_dir').'/vendor/pake/pakeFunction.php');
|
||
|
|
||
|
foreach ($data as $class => $entries)
|
||
|
{
|
||
|
pake_echo_action('Filling', sprintf('class "%s"', $class)."\t");
|
||
|
// fetch a table object
|
||
|
$table = sfDoctrine::getTable($class, $this->connectionName);
|
||
|
|
||
|
$colNames = array_keys($table->getColumns());
|
||
|
|
||
|
$tableName = $table->getTableName();
|
||
|
|
||
|
// relation fields
|
||
|
$relations = $table->getRelations();
|
||
|
|
||
|
//echo "Class $class: ".implode(', ', array_keys($relations))."\n";
|
||
|
|
||
|
if ($this->deleteCurrentData)
|
||
|
{
|
||
|
$q = new Doctrine_Query();
|
||
|
$q->delete()->from($class);
|
||
|
$q->execute();
|
||
|
}
|
||
|
|
||
|
// iterate through entries for this class
|
||
|
// might have been empty just for force a table to be emptied on import
|
||
|
if (is_array($entries))
|
||
|
{
|
||
|
foreach ($entries as $key => $columnAssignments)
|
||
|
{
|
||
|
// create a new entry in the database
|
||
|
$obj = $table->create();
|
||
|
$now = date("Y-m-d H:i:s", time());
|
||
|
if($obj->getTable()->hasColumn('created_at'))
|
||
|
{
|
||
|
$obj->set('created_at', $now);
|
||
|
}
|
||
|
|
||
|
if (!is_array($columnAssignments))
|
||
|
{
|
||
|
throw new Exception('You must give a name for each fixture data entry');
|
||
|
}
|
||
|
|
||
|
foreach ($columnAssignments as $name => $value)
|
||
|
{
|
||
|
$isRelation = isset($relations[$name]);
|
||
|
// foreign key?
|
||
|
if ($isRelation)
|
||
|
{
|
||
|
$rel = $relations[$name];
|
||
|
// $relatedTable = $rel->getTable()->getTableName();
|
||
|
$localKey = $rel->getLocal();
|
||
|
$foreignKey = $rel->getForeign();
|
||
|
|
||
|
$pendingRelations[] = array($obj, $localKey, $foreignKey, $value);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// first check that the column exists
|
||
|
if (!in_array($name, $colNames))
|
||
|
{
|
||
|
$error = 'Column "%s" does not exist for class "%s"';
|
||
|
$error = sprintf($error, $name, $class);
|
||
|
throw new sfException($error);
|
||
|
}
|
||
|
|
||
|
$obj->rawSet($name, $value);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
$obj->save();
|
||
|
|
||
|
// For progress meter
|
||
|
echo '.';
|
||
|
|
||
|
// save the id for future reference
|
||
|
$pk = $obj->obtainIdentifier();
|
||
|
if (isset($this->object_references[$key]))
|
||
|
{
|
||
|
throw new sfException(sprintf('The key "%s" is not unique', $key));
|
||
|
}
|
||
|
|
||
|
$this->object_references[$key] = $pk;
|
||
|
}
|
||
|
}
|
||
|
echo "\n";
|
||
|
}
|
||
|
|
||
|
// now we take care of the pending relations
|
||
|
foreach ($pendingRelations as $pending)
|
||
|
{
|
||
|
list($obj, $localKey, $foreignKey, $key) = $pending;
|
||
|
|
||
|
if (!isset($this->object_references[$key]))
|
||
|
{
|
||
|
$error = 'No object with key "%s" is defined in your data file';
|
||
|
$error = sprintf($error, $key);
|
||
|
throw new sfException($error);
|
||
|
}
|
||
|
|
||
|
$foreignId = $this->object_references[$key][$foreignKey];
|
||
|
|
||
|
$obj->rawSet($localKey, $foreignId);
|
||
|
$obj->save();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* loadMapBuilder
|
||
|
*
|
||
|
* @param mixed $class
|
||
|
* @access protected
|
||
|
* @return void
|
||
|
*/
|
||
|
protected function loadMapBuilder($class)
|
||
|
{
|
||
|
$class_map_builder = $class.'MapBuilder';
|
||
|
if (!isset($this->maps[$class]))
|
||
|
{
|
||
|
if (!$classPath = sfCore::getClassPath($class_map_builder))
|
||
|
{
|
||
|
throw new sfException(sprintf('Unable to find path for class "%s".', $class_map_builder));
|
||
|
}
|
||
|
|
||
|
require_once($classPath);
|
||
|
$this->maps[$class] = new $class_map_builder();
|
||
|
$this->maps[$class]->doBuild();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* dumpData
|
||
|
*
|
||
|
* @param mixed $directory_or_file
|
||
|
* @param string $tables
|
||
|
* @param string $connectionName
|
||
|
* @access public
|
||
|
* @return void
|
||
|
*/
|
||
|
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
|
||
|
}
|
||
|
|
||
|
$manager = Doctrine_Manager::getInstance();
|
||
|
$con = $manager->getCurrentConnection();
|
||
|
|
||
|
// get tables
|
||
|
if ('all' === $tables || null === $tables)
|
||
|
{
|
||
|
$modelDirectories = array();
|
||
|
$modelDirectories[] = sfConfig::get('sf_model_lib_dir').'/doctrine';
|
||
|
|
||
|
$directories = sfFinder::type('dir')->maxdepth(0)->in(sfConfig::get('sf_model_lib_dir').'/doctrine');
|
||
|
|
||
|
foreach($directories AS $directory)
|
||
|
{
|
||
|
if( strstr($directory, 'generated') )
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
$modelDirectories[] = $directory;
|
||
|
}
|
||
|
|
||
|
$tables = array();
|
||
|
foreach($modelDirectories AS $directory)
|
||
|
{
|
||
|
$dirTables = sfFinder::type('file')->name('/(?<!Table)\.class.php$/')->maxdepth(0)->in($directory);
|
||
|
|
||
|
foreach ($dirTables AS $key => $table)
|
||
|
{
|
||
|
$table = basename($table, '.class.php');
|
||
|
$tables[] = $table;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else if (!is_array($tables))
|
||
|
{
|
||
|
$tables = array($tables);
|
||
|
}
|
||
|
|
||
|
$dumpData = array();
|
||
|
|
||
|
foreach ($tables as $modelName)
|
||
|
{
|
||
|
$table = sfDoctrine::getTable($modelName, $this->connectionName);
|
||
|
|
||
|
// get table name
|
||
|
$tableName = $table->getTableName();
|
||
|
|
||
|
$relations = $table->getRelations();
|
||
|
|
||
|
// get columns
|
||
|
$columns = $con->fetchAll('DESCRIBE '.$tableName);
|
||
|
|
||
|
// get records
|
||
|
//$records = $con->fetchAll('SELECT * FROM '.$tableName);
|
||
|
$query = new Doctrine_Query();
|
||
|
$query->from($modelName);
|
||
|
$records = $query->execute();
|
||
|
|
||
|
$dumpData[$modelName] = array();
|
||
|
|
||
|
foreach($records AS $record)
|
||
|
{
|
||
|
$pk = $modelName;
|
||
|
|
||
|
$values = array();
|
||
|
foreach($columns AS $column)
|
||
|
{
|
||
|
$col = strtolower($column['Field']);
|
||
|
|
||
|
try {
|
||
|
$initialValue = $record[$col];
|
||
|
} catch(Exception $e) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if( !$initialValue )
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if ($column['Key'] == 'PRI')
|
||
|
{
|
||
|
$pk .= '_'.$initialValue;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
$isForeignKey = false;
|
||
|
foreach($relations AS $relation)
|
||
|
{
|
||
|
if( $relation->getLocal() == $col )
|
||
|
{
|
||
|
$isForeignKey = true;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if( $isForeignKey )
|
||
|
{
|
||
|
$array = $relation->toArray();
|
||
|
$values[$relation->getAlias()] = $array['class'].'_'.$initialValue;
|
||
|
} else {
|
||
|
$value = $initialValue;
|
||
|
|
||
|
// Needed to maintain bool values
|
||
|
if( is_bool($value) )
|
||
|
{
|
||
|
$value = $value ? 1:0;
|
||
|
}
|
||
|
|
||
|
$values[$col] = $value;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
$dumpData[$modelName][$pk] = $values;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// save to file(s)
|
||
|
if ($sameFile)
|
||
|
{
|
||
|
$yaml = Spyc::YAMLDump($dumpData);
|
||
|
file_put_contents($directory_or_file, $yaml);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
foreach ($dumpData as $table => $data)
|
||
|
{
|
||
|
$yaml = Spyc::YAMLDump($data);
|
||
|
file_put_contents($directory_or_file."/$table.yml", $yaml);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|