logger->log($message, $level); } /** * Constructor. */ public function __construct($config = null) { parent::__construct($config); $this->stats = sfIsisImporterStats::getInstance(); // Get a logger instance. $this->logger = sfIsisImporterLog::getInstance(); } /** * Get the model foreign table id. * * @param object $model Model * @return string Model table id */ static function getModelId($model) { return sfInflector::underscore(get_class($model)) .'_id'; } /** * Get the relation foreign table id. * * @param string $model Relation name * @return string Relation table id */ static function getRelationId($relation) { return sfInflector::underscore($relation) .'_id'; } /** * Get the model and relation tablename. * * @param object $model Model * @param string $model Relation name * @return string Relation table name */ static function getModelRelation($model, $relation) { return sfInflector::camelize(self::getModelName($model)) . sfInflector::camelize($relation); } /** * Get the entity name from a subfield. * * @param string $subfield Subfield name * @return string Genre name */ static function entityName($subfield) { return ucfirst($subfield); } /** * Get the model name. * * @param object $model Model * @return string Model name */ static function getModelName($model) { return get_class($model); } /** * Default implementation for parseName. * * @param mixed $value Name * @return mixed Name */ public function parseName($value) { return $value; } /** * Add a single entry from the database. * * @param string $base_model Model to use * @param int $entry Entry number */ public function addEntry($base_model, $entry) { // Get data and setup the model. $this->read($entry); $model = $this->newModel($base_model, $entry); if ($model) { $this->log("Importing $base_model $entry..."); // Dispatch to custom import procedures. foreach (new IsisMethodIterator($this) as $method => $field) { if (!$this->hasDeniedCombinations($base_model, $field)) { $this->{$method}($model, $field); } } $model->save(); $model->free(true); } else { $this->log("Skipping existing entry $entry for $base_model."); } } /** * Create a new model just if doesn't exist for a given entry. For that * to work the entry must provide and id. * * @param string $base_model Model to use * @param int $entry Entry number * @return mixed New model or false */ public function newModel($base_model, $entry) { $model = new $base_model(); $id = $this->getBaseModelId($model); if ($id) { $existing = call_user_func(array($base_model, 'getById'), $id); if (!$existing) { $this->setBaseModelId($model); return $model; } elseif ($this->skipExisting()) { return false; } else { return $existing; } } return $model; } /** * Check if ISIS database configuration is set to not skip existing * entries during an import. * * @return boolean */ public function skipExisting() { if (isset($this->format['import']['skip_existing'])) { return $this->format['import']['skip_existing']; } return true; } /** * Set the primary key for the model by getting it or just saving it. * * @param object $model Base model */ public function setBaseModelId(&$model) { $model->id = $this->getBaseModelId($model); $model->save(); } /** * Get the primary key for the base model. * * @param object $model Base model * @return int Base model id */ public function getBaseModelId(&$model) { $method = 'get' . $this->getModelName($model) .'PrimaryKey'; if (method_exists($this, $method)) { return $this->{$method}($model); } } /** * Import a single field into a model. * * @param object $model Model * @param array $field Field data from ISIS database schema * @param int $row Row number */ public function addField(&$model, $field, $row = 0) { $value = $this->filterBrackets($this->getMainItem($field, $row)); if ($value != null) { $map = $this->getMap($field); $model->{$map}($value); } } /** * Import a single subfield into a model. * * @param object $model Model * @param array $field Field data from ISIS database schema * @param string $subfield Subfield name * @param int $row Row number */ public function addSubfield(&$model, $field, $subfield, $row = 0) { $value = $this->filterBrackets($this->getSubfield($field, $subfield, $row)); if ($value != null) { $map = $this->getMap($field, $subfield); $model->{$map}($value); } } /** * Import single values into the model. * * Currently undefined mappings for a field/subfield * are not saved as we would need to make sure a corresponding * field exists in the model. This prevents the map * configurations like $map = array('type' => 'value'); to work. * * As we are importing single values, here we don't care with * row numbers as we assume that just the first row should be * imported. * * @param object $model Model object * @param array $field Field data */ public function importValues(&$model, array $field) { if ($this->fieldHasMap($field)) { $this->addField($model, $field); } foreach ($this->getSubfieldList($field) as $subfield) { if ($this->subfieldHasMap($field, $subfield)) { $this->addSubfield($model, $field, $subfield); } } } /** * Get an existing entity. * * @param string $entity Entity name * @param string $value Value to search for * @param string $by Field to search $value * @return mixed Entity data or false */ public function getEntity($entity, $value, $by = 'name') { $findby = 'findOneBy'. ucfirst($by); $data = Doctrine_Core::getTable($entity)->{$findby}($value); if ($data) { return $data; } return false; } /** * Add a new entity into the database if needed, returning * the corresponding object. * * @param string $entity Entity name * @param string $name Name value * @return object Entity data */ public function addEntity($entity, $name) { $name = $this->entityName($name); $data = $this->getEntity($entity, $name); if (!$data) { $this->log("Adding new $entity $name."); $data = new $entity(); $data->name = $name; $data->save(); } return $data; } /** * Import one to one data. * * @param object $model Model * @param array $field Field data from ISIS database schema * @param string $relation Relation name */ public function addOneToOne(&$model, array $field, $relation) { foreach (new IsisRowIterator($this, $field) as $row) { $data = new $relation(); foreach ($this->getSubfieldList($field) as $subfield) { $this->addSubfield($data, $field, $subfield, $row); } $data->save(); $key = sfInflector::underscore($relation) .'_id'; $model->$key = $data->id; } } /** * Import many to many data. * * @param object $model Model * @param array $values Values to be added * @param string $relation Relation name */ public function addManyToMany(&$model, array $values, $relation) { $method = 'add'. $relation; foreach ($values as $value) { // Populate related data. if (is_callable(array($this, $method))) { $data = $this->{$method}($value); } else { $data = $this->addEntity($relation, $value); } // Get model and relation names and id fields. $model_id = $this->getModelId($model); $relation_id = $this->getRelationId($relation); $model_relation = $this->getModelRelation($model, $relation); // Make the relation. $model_data = new $model_relation(); $model_data->{$model_id} = $model->id; $model_data->{$relation_id} = $data->id; $model_data->save(); } } /** * Import one to one data. * * @param object $model Model * @param string $relation Relation name * @return object Relation model object */ public function addOneToMany(&$model, $relation) { $model_id = $this->getModelId($model); $data = new $relation(); $data->{$model_id} = $model->id; $data->save(); return $data; } /** * Add simple entities data into the model. * * @param object $model Model * @param array $field Field data from ISIS database schema */ public function addOneToManyEntities(&$model, array $field, $entity, $key = 'name') { foreach (new IsisMainItemIterator($this, $field) as $row => $value) { $this->log("Entity: $entity; Value: $value", 'debug'); $data = $this->addOneToMany($model, $entity); $data->{$key} = $value; $data->save(); } } /** * Add field values in a many-to-many relation. * * @param object $model Model * @param array $field Field data from ISIS database schema * @param string $relation Relation name */ public function addManyToManyField(&$model, array $field, $relation) { foreach (new IsisMainItemIterator($this, $field) as $value) { $this->addManyToMany($model, $this->explodeBrackets($value), $relation); } } /** * Add an element into the database if needed, returning * the resulting object. * * @param string $entity Entity name * @param string $value Entity value * @return object Entity data */ public function newOrExisting($entity, $value) { // Check for a null value. if ($value == null) { $this->log("Null element value for $entity.", 'debug'); return; } // Get name. $name = $this->parseName($value); // Get existing element. $element = call_user_func(array($entity, 'getByName'), $name); // Create new element if needed. if (!$element) { $this->log("Adding new $entity $value."); $element = call_user_func(array($entity, 'addByName'), $name); } return $element; } /** * Check denied combinations inside a field. * * @param string $model Model name * @param array $field Field data from ISIS database schema * @return boolean True if has a denied combination, false otherwise * @todo Wildcard * @todo Test */ public function hasDeniedCombinations($model, $field) { if (method_exists($this, 'getDeniedCombinations')) { foreach ($this->getDeniedCombinations($model, $field) as $combination) { $has = true; foreach ($combination as $item) { foreach (new IsisRowIterator($this, $field) as $row) { if (!$this->hasDeniedItem($field, $item, $row)) { $has = false; break 2; } } } if ($has) { $denied[$row] = $combination; } } } if (isset($denied)) { foreach ($denied as $row => $combination) { $combination = implode(',', $combination); $this->log("Found denied combination for row $row: $combination"); } return true; } return false; } /** * Check if a field has a denied item. * * @param array $field Field data from ISIS database schema * @param string $item Item code * @param int $row Row number * @return boolean True if has a denied combination, false otherwise * @todo Wildcard * @todo Test */ public function hasDeniedItem($field, $item, $row) { // Default condition: presence requirement for an item. $condition = true; // Check if item has the negation (absence) requirement for an item. if (substr($item, 0, 1) == '!') { $item = substr($item, 1); $condition = false; } // Check if the item exists. $has = $this->hasItem($field, $item, $row); if ($condition == true) { // If the condition is true, a denied combination won't be fulfilled if // the item is not present. if (!$has) { return false; } } else { // If the condition is false, a denied combination won't be fulfilled if // the item is present. if ($has) { return false; } } return true; } }