diff --git a/lib/Doctrine/Data.php b/lib/Doctrine/Data.php new file mode 100644 index 000000000..29c78a664 --- /dev/null +++ b/lib/Doctrine/Data.php @@ -0,0 +1,258 @@ +. + */ + +/** + * Doctrine_Data + * + * Base Doctrine_Data class + * + * @package Doctrine + * @author Jonathan H. Wage + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @category Object Relational Mapping + * @link www.phpdoctrine.com + * @since 1.0 + * @version $Revision: 2552 $ + */ +class Doctrine_Data +{ + /** + * formats + * + * array of formats data can be in + * + * @var string + */ + public $formats = array('csv', 'yml', 'xml'); + /** + * format + * + * the default and current format we are working with + * + * @var string + */ + public $format = 'yml'; + /** + * directory + * + * array of directory/yml paths or single directory/yml file + * + * @var string + */ + public $directory = null; + /** + * models + * + * specified array of models to use + * + * @var string + */ + public $models = array(); + /** + * exportIndividualFiles + * + * whether or not to export data to individual files instead of 1 + * + * @var string + */ + public $exportIndividualFiles = false; + /** + * setFormat + * + * Set the current format we are working with + * + * @param string $format + * @return void + * @author Jonathan H. Wage + */ + public function setFormat($format) + { + $this->format = $format; + } + /** + * getFormat + * + * Get the current format we are working with + * + * @return void + * @author Jonathan H. Wage + */ + public function getFormat() + { + return $this->format; + } + /** + * getFormats + * + * Get array of available formats + * + * @author Jonathan H. Wage + */ + public function getFormats() + { + return $this->formats; + } + /** + * setDirectory + * + * Set the array/string of directories or yml file paths + * + * @author Jonathan H. Wage + */ + public function setDirectory($directory) + { + $this->directory = $directory; + } + /** + * getDirectory + * + * Get directory to work with + * + * @return void + * @author Jonathan H. Wage + */ + public function getDirectory() + { + return $this->directory; + } + /** + * setModels + * + * Set the array of specified models to work with + * + * @param string $models + * @return void + * @author Jonathan H. Wage + */ + public function setModels($models) + { + $this->models = $models; + } + /** + * getModels + * + * Get the array of specified models to work with + * + * @return void + * @author Jonathan H. Wage + */ + public function getModels() + { + return $this->models; + } + /** + * exportIndividualFiles + * + * Set/Get whether or not to export individual files + * + * @author Jonathan H. Wage + */ + public function exportIndividualFiles($bool = null) + { + if ($bool !== null) { + $this->exportIndividualFiles = $bool; + } + + return $this->exportIndividualFiles; + } + /** + * exportData + * + * Interface for exporting data to fixtures files from Doctrine models + * + * @param string $directory + * @param string $format + * @param string $models + * @param string $exportIndividualFiles + * @return void + * @author Jonathan H. Wage + */ + public static function exportData($directory, $format = 'yml', $models = array(), $exportIndividualFiles = false) + { + $export = new Doctrine_Data_Export($directory); + $export->setFormat($format); + $export->setModels($models); + $export->exportIndividualFiles($exportIndividualFiles); + + return $export->doExport(); + } + /** + * importData + * + * Interface for importing data from fixture files to Doctrine models + * + * @param string $directory + * @param string $format + * @param string $models + * @return void + * @author Jonathan H. Wage + */ + public static function importData($directory, $format = 'yml', $models = array()) + { + $import = new Doctrine_Data_Import($directory); + $import->setFormat($format); + $import->setModels($models); + + return $import->doImport(); + } + /** + * importDummyData + * + * Interface for importing dummy data to models + * + * @param string $num + * @param string $models + * @return void + * @author Jonathan H. Wage + */ + public static function importDummyData($num = 3, $models = array()) + { + $import = new Doctrine_Data_Import(); + $import->setModels($models); + + $import->doImportDummyData($num); + } + /** + * isRelation + * + * Check if a fieldName on a Doctrine_Record is a relation, if it is we return that relationData + * + * @param string $Doctrine_Record + * @param string $fieldName + * @return void + * @author Jonathan H. Wage + */ + public function isRelation(Doctrine_Record $record, $fieldName) + { + $relations = $record->getTable()->getRelations(); + + foreach ($relations as $relation) { + $relationData = $relation->toArray(); + + if ($relationData['local'] === $fieldName) { + return $relationData; + } + + } + + return false; + } +} \ No newline at end of file diff --git a/lib/Doctrine/Data/Exception.php b/lib/Doctrine/Data/Exception.php new file mode 100644 index 000000000..44c83e978 --- /dev/null +++ b/lib/Doctrine/Data/Exception.php @@ -0,0 +1,4 @@ +. + */ + +/** + * Doctrine_Data_Export + * + * @package Doctrine + * @author Jonathan H. Wage + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @category Object Relational Mapping + * @link www.phpdoctrine.com + * @since 1.0 + * @version $Revision: 2552 $ + */ +class Doctrine_Data_Export extends Doctrine_Data +{ + /** + * constructor + * + * @param string $directory + * @return void + * @author Jonathan H. Wage + */ + public function __construct($directory) + { + $this->setDirectory($directory); + } + /** + * doExport + * + * @return void + * @author Jonathan H. Wage + */ + public function doExport() + { + $models = Doctrine::getLoadedModels(); + $specifiedModels = $this->getModels(); + + $data = array(); + + $outputAll = true; + + foreach ($models AS $name) { + + if (!empty($specifiedModels) AND !in_array($name, $specifiedModels)) { + continue; + } + + $class = new $name(); + $table = $class->getTable(); + $result = $table->findAll(); + + if (!empty($result)) { + $data[$name] = $result; + } + } + + $data = $this->prepareData($data); + + return $this->dumpData($data); + } + /** + * dumpData + * + * Dump the prepared data to the fixtures files + * + * @param string $array + * @return void + * @author Jonathan H. Wage + */ + public function dumpData(array $data) + { + $directory = $this->getDirectory(); + $format = $this->getFormat(); + + if ($this->exportIndividualFiles()) { + + if (is_array($directory)) { + throw new Doctrine_Data_Exception('You must specify a single path to a folder in order to export individual files.'); + } + + foreach ($data as $className => $classData) { + Doctrine_Parser::dump($classData->toArray(), $directory.DIRECTORY_SEPARATOR.$className.'.'.$format, $format); + } + } else { + if (is_dir($directory)) { + throw new Doctrine_Data_Exception('You must specify the path to a '.$format.' file to export. You specified a directory.'); + } + + return Doctrine_Parser::dump($data, $directory, $format); + } + } + /** + * prepareData + * + * Prepare the raw data to be exported with the parser + * + * @param string $data + * @return array + * @author Jonathan H. Wage + */ + public function prepareData($data) + { + $preparedData = array(); + + foreach ($data AS $className => $classData) { + + foreach ($classData as $record) { + $className = get_class($record); + $recordKey = $className . '_' . implode('_', $record->identifier()); + + $recordData = $record->toArray(); + + foreach ($recordData as $key => $value) { + if (!$value) { + continue; + } + + if ($relation = $this->isRelation($record, $key)) { + $relationAlias = $relation['alias']; + $relationRecord = $record->$relationAlias; + + // If collection then get first so we have an instance of the related record + if ($relationRecord instanceof Doctrine_Collection) { + $relationRecord = $relationRecord->getFirst(); + } + + // If relation is null or does not exist then continue + if ($relationRecord instanceof Doctrine_Null || !$relationRecord) { + continue; + } + + // Get class name for relation + $relationClassName = get_class($relationRecord); + + $relationValue = $relationClassName . '_' . $value; + + $preparedData[$className][$recordKey][$relationClassName] = $relationValue; + } else { + // skip single primary keys, we need to maintain composite primary keys + $keys = $record->getTable()->getPrimaryKeys(); + + if (count($keys) <= 1 && in_array($key, $keys)) { + continue; + } + + $preparedData[$className][$recordKey][$key] = $value; + } + } + } + } + + return $preparedData; + } +} \ No newline at end of file diff --git a/lib/Doctrine/Data/Import.php b/lib/Doctrine/Data/Import.php new file mode 100644 index 000000000..a71d6cc81 --- /dev/null +++ b/lib/Doctrine/Data/Import.php @@ -0,0 +1,177 @@ +. + */ + +/** + * Doctrine_Data_Import + * + * @package Doctrine + * @author Jonathan H. Wage + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @category Object Relational Mapping + * @link www.phpdoctrine.com + * @since 1.0 + * @version $Revision: 2552 $ + */ +class Doctrine_Data_Import extends Doctrine_Data +{ + /** + * constructor + * + * @param string $directory + * @return void + * @author Jonathan H. Wage + */ + + public function __construct($directory = null) + { + if ($directory !== null) { + $this->setDirectory($directory); + } + } + /** + * doImport + * + * @return void + * @author Jonathan H. Wage + */ + public function doImport() + { + $directory = $this->directory; + + $array = array(); + + if ($directory !== null) { + foreach ((array) $directory as $dir) { + $e = explode('.', $dir); + + // If they specified a specific yml file + if (end($e) == 'yml') { + $array = array_merge($array, Doctrine_Parser::load($dir, $this->getFormat())); + // If they specified a directory + } else if(is_dir($dir)) { + $it = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir), + RecursiveIteratorIterator::LEAVES_ONLY); + + foreach ($it as $file) { + $e = explode('.', $file->getFileName()); + if (in_array(end($e), $this->getFormats())) { + $array = array_merge($array, Doctrine_Parser::load($file->getPathName(), $this->getFormat())); + } + } + } + } + } + + $this->loadData($array); + } + /** + * loadData + * + * @param string $array + * @return void + * @author Jonathan H. Wage + */ + protected function loadData(array $array) + { + $specifiedModels = $this->getModels(); + + $pendingRelations = array(); + + $primaryKeys = array(); + + foreach ($array as $className => $data) { + + if (!empty($specifiedModels) && !in_array($className, $specifiedModels)) { + continue; + } + + foreach ($data as $rowKey => $row) { + $obj = new $className(); + + foreach ($row as $key => $value) { + // If row key is a relation store it for later fixing once we have all primary keys + if ($obj->getTable()->hasRelation($key)) { + $relation = $obj->getTable()->getRelation($key); + + $pendingRelations[] = array('key' => $value, 'obj' => $obj, 'local' => $relation['local'], 'foreign' => $relation['foreign']); + // If we have a normal column + } else if ($obj->getTable()->hasColumn($key)) { + $obj->$key = $value; + // Otherwise lets move on + } else { + continue; + } + } + + $obj->save(); + + $primaryKeys[$rowKey] = $obj->identifier(); + } + } + + foreach ($pendingRelations as $rowKey => $pending) { + $obj = $pending['obj']; + $key = $pending['key']; + $local = $pending['local']; + $foreign = $pending['foreign']; + $pks = $primaryKeys[$key]; + $obj->$local = $pks['id']; + + $obj->save(); + } + } + /** + * doImportDummyData + * + * @param string $num + * @return void + * @author Jonathan H. Wage + */ + public function doImportDummyData($num = 3) + { + $models = Doctrine::getLoadedModels(); + + $specifiedModels = $this->getModels(); + + foreach ($models as $name) { + if (!empty($specifiedModels) && !in_array($name, $specifiedModels)) { + continue; + } + + for ($i = 0; $i < $num; $i++) { + $obj = new $name(); + $columns = array_keys($obj->toArray()); + $pks = $obj->getTable()->getPrimaryKeys(); + + foreach ($columns as $column) { + + if (!in_array($column, $pks)) { + $obj->$column = uniqid(); + } + } + + $obj->save(); + + $ids[get_class($obj)][] = $obj->identifier(); + } + } + } +} \ No newline at end of file