Author: pmacadden Date: 2010-03-30 20:16:40 +0200 (Tue, 30 Mar 2010) New Revision: 28887
Added: plugins/pmMigratorPlugin/trunk/README plugins/pmMigratorPlugin/trunk/lib/ plugins/pmMigratorPlugin/trunk/lib/pmMigrator.class.php plugins/pmMigratorPlugin/trunk/lib/pmMigratorCSV.class.php Log: initial import Added: plugins/pmMigratorPlugin/trunk/README =================================================================== --- plugins/pmMigratorPlugin/trunk/README (rev 0) +++ plugins/pmMigratorPlugin/trunk/README 2010-03-30 18:16:40 UTC (rev 28887) @@ -0,0 +1,73 @@ +pmMigratorPlugin +================ + +The `pmMigratorPlugin` is a symfony plugin that provides objects for performing +data migration. +You can create these objects for migrating from CSV file i.e.. + +Installation +------------ + + * Install the plugin + + * Subversion + + [bash] + $ svn co http://svn.symfony-project.com/plugins/pmMigratorPlugin/trunk pmMigratorPlugin + +Usage +----- + +You can use pmMigrator objects everywhere. In this example, I will show you how +to create a Task that permform a migration from CSV file(s) to Propel objects. +This example is assuming that you have the schema.yml and the objects created. +Also, this example is assuming that you have a CSV file with the objects data. + + * Create a task + + [bash] + $ ./symfony generate:task migration + + [php] + $migrator = new pmMigratorCSV( + // this should be the path to your CSV file + sfConfig::get("sf_data_dir")."/csv/myCSVFile.csv", + // Class name + "Address", + // Class fields: fill an array with all the columns. If any column is not used, fill in it with "null" + array(null, null, null, null, null, "street", "number", "floor", "flat", "city_id", null, null, null, null) + ); + + // set hooks for "city_id" field. Any class field can have many hooks (or none) + $migrator->setFieldHook("city_id", array("migrateTask", "getCityId")); + + // set hooks for the object + $migrator->setObjectHooks(array( + array("migrateTask", "guessStateId"), + array("migrateTask", "guessZipCode") + )); + + // migrate in debug mode. + $migrator->migrate(false, true); + + * Move the CSV file to data/csv/ (not mandatory). + + +Field hooks +----------- + +Any class field can have multiple hooks. Field hooks are callbacks that are +performed before the object is populated. + +Field hooks are set with the setFieldHook($field, $hook), where $field is the +field name and hook is a valid callback. + + +Object hooks +------------ + +An object can have multiple hooks. Object hooks are callbacks that are +performed before the object is saved (but after the object is populated). + +Object hooks are set with the setObjectHooks($hooks), where $field is the +field name and hook is a valid callback or an array of valid callbacks. Added: plugins/pmMigratorPlugin/trunk/lib/pmMigrator.class.php =================================================================== --- plugins/pmMigratorPlugin/trunk/lib/pmMigrator.class.php (rev 0) +++ plugins/pmMigratorPlugin/trunk/lib/pmMigrator.class.php 2010-03-30 18:16:40 UTC (rev 28887) @@ -0,0 +1,386 @@ +<?php + +/** + * Abstract class that provides an interface for performing migrations. + */ +abstract class pmMigrator +{ + /** + * @var string + */ + protected $class_name; + + /** + * @var string + */ + protected $class_fields; + + /** + * @var array + */ + protected $fields_hooks; + + /** + * @var array + */ + protected $object_hooks; + + /** + * Constructor + */ + public function __construct() + { + $this->class_name = ""; + $this->class_fields = array(); + $this->fields_hooks = array(); + $this->object_hooks = array(); + } + + /** + * Initializes the pmMigrator with class_name and class_fields. + * @param string $class_name The class name + * @param array $class_fields The class fields + * + * @return pmMigrator + */ + protected function init($class_name, $class_fields) + { + $this->setClassName(sfInflector::camelize($class_name)); + $this->setClassFields($class_fields); + + return $this; + } + + /** + * Create an instance of pmMigrator. + * @param string $class_name The class name + * @param array $class_fields The class fields + * + * @return pmMigrator + */ + public static function create($class_name, $class_fields) + { + $class = __CLASS__; + $migrator = new $class(); + return $migrator->init($class_name, $class_fields); + } + + /** + * Setter for $class_name attribute. + * @param string $class_name The class name to migrate + * + * @return pmMigrator + */ + public function setClassName($class_name) + { + $this->class_name = $class_name; + + return $this; + } + + /** + * Getter for $file attribute. + * + * @return string + */ + public function getClassName() + { + return $this->class_name; + } + + /** + * Setter for $class_fields attribute. + * @param array $class_fields The class fields to migrate + * + * @return pmMigrator + */ + public function setClassFields($class_fields) + { + $this->class_fields = $class_fields; + + return $this; + } + + /** + * Getter for $class_fields attribute. + * + * @return string + */ + public function getClassFields() + { + return $this->class_fields; + } + + /** + * Get a class field. + * @param int @class_field The position + * + * @return string + */ + public function getClassField($class_field) + { + if (array_key_exists($class_field, $this->getClassFields())) + { + return $this->class_fields[$class_field]; + } + else + { + return null; + } + } + + /** + * Add a $hook for $class_field. + * @param string $class_field The class field + * @param mixed $hook A valid callback for permforming the hook (could be an + * array or an array of arrays) + * + * @return pmMigrator + */ + public function setFieldHook($class_field, $hook) + { + $this->fields_hooks[$class_field] = $hook; + + return $this; + } + + /** + * Get a field hook field. + * @param int @class_field The hook index + * + * @return mixed + */ + public function getFieldHook($class_field) + { + if ($this->hasFieldHook($class_field)) + { + return $this->fields_hooks[$class_field]; + } + else + { + return null; + } + } + + /** + * Returns true if the class field has hooks. + * @param int @class_field The hook index + * + * @return boolean Wheather the class field has hooks or not. + */ + public function hasFieldHook($class_field) + { + return array_key_exists($class_field, $this->fields_hooks); + } + + /** + * Setter for $fields_hooks attribute. + * @param array An array of hooks + * + * @return pmMigrator + */ + public function setFieldsHooks($hooks) + { + $this->fields_hooks = $hooks; + + return $this; + } + + /** + * Getter for $fields_hooks attribute. + * + * @return mixed + */ + public function getFieldsHooks() + { + return $this->fields_hooks; + } + + /** + * Setter for $object_hooks attribute. + * @param array An array of object hooks + * + * @return pmMigrator + */ + public function setObjectHooks($hooks) + { + $this->object_hooks = $hooks; + + return $this; + } + + /** + * Getter for $object_hooks attribute. + * + * @return mixed + */ + public function getObjectHooks() + { + return $this->object_hooks; + } + + /** + * Perform the migration. + * @param boolean $dry Run in dry mode + * @param boolean $debug Run in debug mode + */ + public abstract function migrate($dry = false, $debug = false); + + /** + * Create an object + * @param bool $debug Run in debug mode + * + * @return mixed + */ + protected function createObject($debug) + { + if ($debug) + { + echo "\$object = new ".$this->class_name."();\n"; + } + $object = new $this->class_name; + + return $object; + } + + /** + * Populate $object $field with $value + * @param mixed $object The object + * @param string $field The field + * @param string $value The value + * @param string $debug Run in debug mode + * + * @return pmMigrator + */ + protected function populateObjectField($object, $field, $value, $debug) + { + if ($hooks = $this->getFieldHook($field)) + { + if (is_array($hooks[0])) + { + foreach ($hooks as $hook) + { + if (is_callable($hook)) + { + if ($debug) + { + echo "Running hook for {$field}\n"; + } + $value = call_user_func($hook, $value); + } + else + { + if ($debug) + { + echo "Field hook for {$field} is not callable\n"; + } + } + } + } + else + { + if (is_callable($hooks)) + { + if ($debug) + { + echo "Running hook for {$field}\n"; + } + $value = call_user_func($hooks, $value); + } + else + { + if ($debug) + { + echo "Field hook for {$field} is not callable\n"; + } + } + } + } + + $setter = "set".sfInflector::camelize($field); + if ($debug) + { + echo "\$object->$setter($value);\n"; + } + call_user_func(array($object, $setter), $value); + + return $this; + } + + /** + * Run the object hooks + * @param mixed $object The object + * @param bool $debug Run in debug mode + * + * @return pmMigrator + */ + protected function runObjectHooks($object, $debug) + { + if ($object_hooks = $this->getObjectHooks()) + { + if (is_array($object_hooks[0])) + { + foreach ($object_hooks as $hook) + { + if (is_callable($hook)) + { + if ($debug) + { + echo "Running object hook\n"; + } + call_user_func($hook, $object); + } + else + { + if ($debug) + { + echo "Object hook for is not callable\n"; + } + } + } + } + else + { + if (is_callable($object_hooks)) + { + if ($debug) + { + echo "Running object hook\n"; + } + call_user_func($object_hooks, $object); + } + else + { + if ($debug) + { + echo "Object hook for is not callable\n"; + } + } + } + } + + return $this; + } + + /** + * Run the object hooks + * @param mixed $object The object + * @param bool $dry Run in dry mode + * @param bool $debug Run in debug mode + * + * @return pmMigrator + */ + protected function saveObject($object, $dry, $debug) + { + if (!$dry) + { + if ($debug) + { + echo "Saving object\n"; + } + $object->save(); + } + + return $this; + } +} Added: plugins/pmMigratorPlugin/trunk/lib/pmMigratorCSV.class.php =================================================================== --- plugins/pmMigratorPlugin/trunk/lib/pmMigratorCSV.class.php (rev 0) +++ plugins/pmMigratorPlugin/trunk/lib/pmMigratorCSV.class.php 2010-03-30 18:16:40 UTC (rev 28887) @@ -0,0 +1,89 @@ +<?php + +/** + * Concrete class that provides an implementation for performing migrations. + * This class migrates CSV files into objects. + */ +class pmMigratorCSV extends pmMigrator +{ + /** + * @var string The CSV file path + */ + protected $file; + + /** + * Create an instance of pmMigratorCSV. + * @param string $file The path to the CSV file + * @param string $class_name The class name + * @param array $class_fields The class fields + * + * @return pmMigratorCSV + */ + public static function create($file, $class_name, $class_fields) + { + $class = __CLASS__; + $migrator = new $class(); + $migrator->init($class_name, $class_fields); + $migrator->setFile($file); + + return $migrator; + } + + /** + * Setter for $file attribute. + * @param string The CSV file path + * + * @return pmMigratorCSV + */ + public function setFile($file) + { + $this->file = $file; + return $this; + } + + /** + * Getter for $file attribute. + * + * @return string + */ + public function getFile() + { + return $this->file; + } + + /** + * Perform the migration. + * @param boolean $dry Run in dry mode + * @param boolean $debug Run in debug mode + */ + public function migrate($dry = false, $debug = false) + { + $handle = fopen($this->getFile(), "r"); + + if ($handle) + { + while($data = fgetcsv($handle)) + { + $object = $this->createObject($debug); + + for ($i = 0; $i < count($data); $i++) + { + if (!is_null($this->getClassField($i))) + { + $value = $data[$i]; + $this->populateObjectField($object, $this->getClassField($i), $value, $debug); + } + } + + $this->runObjectHooks($object, $debug); + $this->saveObject($object, $dry, $debug); + } + + fclose($handle); + } + else + { + throw new Exception("File {$this->getFile()} could not be opened."); + } + } +} -- You received this message because you are subscribed to the Google Groups "symfony SVN" group. To post to this group, send email to [email protected]. To unsubscribe from this group, send email to [email protected]. For more options, visit this group at http://groups.google.com/group/symfony-svn?hl=en.
