/** * buildRelationships * * Loop through an array of schema information and build all the necessary relationship information * Will attempt to auto complete relationships and simplify the amount of information required * for defining a relationship * * @param string $array * @return void */ protected function _buildRelationships($array) { // Handle auto detecting relations by the names of columns // User.contact_id will automatically create User hasOne Contact local => contact_id, foreign => id foreach ($array as $className => $properties) { if (isset($properties['columns']) && !empty($properties['columns']) && isset($properties['detect_relations']) && $properties['detect_relations']) { foreach ($properties['columns'] as $column) { // Check if the column we are inflecting has a _id on the end of it before trying to inflect it and find // the class name for the column if (strpos($column['name'], '_id')) { $columnClassName = Doctrine_Inflector::classify(str_replace('_id', '', $column['name'])); if (isset($array[$columnClassName]) && !isset($array[$className]['relations'][$columnClassName])) { $array[$className]['relations'][$columnClassName] = array(); } } } } } foreach ($array as $name => $properties) { if (!isset($properties['relations'])) { continue; } $className = $properties['className']; $relations = $properties['relations']; foreach ($relations as $alias => $relation) { $class = isset($relation['class']) ? $relation['class'] : $alias; $relation['class'] = $class; $relation['alias'] = isset($relation['alias']) ? $relation['alias'] : $alias; // Attempt to guess the local and foreign if (isset($relation['refClass'])) { $relation['local'] = isset($relation['local']) ? $relation['local'] : Doctrine::tableize($name) . '_id'; $relation['foreign'] = isset($relation['foreign']) ? $relation['foreign'] : Doctrine::tableize($class) . '_id'; } else { $relation['local'] = isset($relation['local']) ? $relation['local'] : Doctrine::tableize($relation['class']) . '_id'; $relation['foreign'] = isset($relation['foreign']) ? $relation['foreign'] : 'id'; } if (isset($relation['refClass'])) { $relation['type'] = 'many'; } if (isset($relation['type']) && $relation['type']) { $relation['type'] = $relation['type'] === 'one' ? Doctrine_Relation::ONE : Doctrine_Relation::MANY; } else { $relation['type'] = Doctrine_Relation::ONE; } if (isset($relation['foreignType']) && $relation['foreignType']) { $relation['foreignType'] = $relation['foreignType'] === 'one' ? Doctrine_Relation::ONE : Doctrine_Relation::MANY; } $relation['key'] = $this->_buildUniqueRelationKey($relation); $this->_validateSchemaElement('relation', array_keys($relation)); $this->_relations[$className][$alias] = $relation; } } // Now we auto-complete opposite ends of relationships $this->_autoCompleteOppositeRelations(); // Make sure we do not have any duplicate relations $this->_fixDuplicateRelations(); // Set the full array of relationships for each class to the final array foreach ($this->_relations as $className => $relations) { $array[$className]['relations'] = $relations; } return $array; }
/** * printTasks * * Prints an index of all the available tasks in the CLI instance * * @return void */ public function printTasks($task = null, $full = false) { $task = Doctrine::classify(str_replace('-', '_', $task)); $tasks = $this->getLoadedTasks(); echo $this->_formatter->format("Doctrine Command Line Interface", 'HEADER') . "\n\n"; foreach ($tasks as $taskName) { if ($task != null && strtolower($task) != strtolower($taskName)) { continue; } $className = 'Doctrine_Task_' . $taskName; $taskInstance = new $className(); $taskInstance->taskName = str_replace('_', '-', Doctrine::tableize($taskName)); $syntax = $this->_scriptName . ' ' . $taskInstance->getTaskName(); echo $this->_formatter->format($syntax, 'INFO'); if ($full) { echo " - " . $taskInstance->getDescription() . "\n"; $args = null; $requiredArguments = $taskInstance->getRequiredArgumentsDescriptions(); if (!empty($requiredArguments)) { foreach ($requiredArguments as $name => $description) { $args .= $this->_formatter->format($name, "ERROR"); if (isset($this->_config[$name])) { $args .= " - " . $this->_formatter->format($this->_config[$name], 'COMMENT'); } else { $args .= " - " . $description; } $args .= "\n"; } } $optionalArguments = $taskInstance->getOptionalArgumentsDescriptions(); if (!empty($optionalArguments)) { foreach ($optionalArguments as $name => $description) { $args .= $name . ' - ' . $description . "\n"; } } if ($args) { echo "\n" . $this->_formatter->format('Arguments:', 'HEADER') . "\n" . $args; } } echo "\n"; } }
/** * __construct * * Since this is an abstract classes that extend this must follow a patter of Doctrine_Task_{TASK_NAME} * This is what determines the task name for executing it. * * @return void */ public function __construct($dispatcher = null) { $this->dispatcher = $dispatcher; $this->taskName = str_replace('_', '-', Doctrine::tableize(str_replace('Doctrine_Task_', '', get_class($this)))); }
/** * __call * * Adds support for magic finders. * findByColumnName, findByRelationAlias * findById, findByContactId, etc. * * @return void */ public function __call($method, $arguments) { if (substr($method, 0, 6) == 'findBy') { $by = substr($method, 6, strlen($method)); $method = 'findBy'; } else { if (substr($method, 0, 9) == 'findOneBy') { $by = substr($method, 9, strlen($method)); $method = 'findOneBy'; } } if (isset($by)) { if (!isset($arguments[0])) { throw new Doctrine_Table_Exception('You must specify the value to findBy'); } $fieldName = Doctrine::tableize($by); $hydrationMode = isset($arguments[1]) ? $arguments[1] : null; if ($this->hasColumn($fieldName)) { return $this->{$method}($fieldName, $arguments[0], $hydrationMode); } else { if ($this->hasRelation($by)) { $relation = $this->getRelation($by); if ($relation['type'] === Doctrine_Relation::MANY) { throw new Doctrine_Table_Exception('Cannot findBy many relationship.'); } return $this->{$method}($relation['local'], $arguments[0], $hydrationMode); } else { throw new Doctrine_Table_Exception('Cannot find by: ' . $by . '. Invalid column or relationship alias.'); } } } }
/** * buildRelationships * * Loop through an array of schema information and build all the necessary relationship information * Will attempt to auto complete relationships and simplify the amount of information required for defining a relationship * * @param string $array * @return void */ protected function _buildRelationships($array) { foreach ($array as $name => $properties) { if (!isset($properties['relations'])) { continue; } $className = $properties['className']; $relations = $properties['relations']; foreach ($relations as $alias => $relation) { $class = isset($relation['class']) ? $relation['class'] : $alias; // Attempt to guess the local and foreign if (isset($relation['refClass'])) { $relation['local'] = isset($relation['local']) ? $relation['local'] : Doctrine::tableize($name) . '_id'; $relation['foreign'] = isset($relation['foreign']) ? $relation['foreign'] : Doctrine::tableize($class) . '_id'; } else { $relation['local'] = isset($relation['local']) ? $relation['local'] : Doctrine::tableize($class) . '_id'; $relation['foreign'] = isset($relation['foreign']) ? $relation['foreign'] : 'id'; } $relation['alias'] = isset($relation['alias']) ? $relation['alias'] : $alias; $relation['class'] = $class; if (isset($relation['refClass'])) { $relation['type'] = 'many'; } if (isset($relation['type']) && $relation['type']) { $relation['type'] = $relation['type'] === 'one' ? Doctrine_Relation::ONE : Doctrine_Relation::MANY; } else { $relation['type'] = Doctrine_Relation::ONE; } if (isset($relation['foreignType']) && $relation['foreignType']) { $relation['foreignType'] = $relation['foreignType'] === 'one' ? Doctrine_Relation::ONE : Doctrine_Relation::MANY; } $relation['key'] = $this->_buildUniqueRelationKey($relation); $this->_relations[$className][$alias] = $relation; } } // Now we fix all the relationships and auto-complete opposite ends of relationships $this->_fixRelationships(); }
/** * the constructor * @throws Doctrine_Connection_Exception if there are no opened connections * @throws Doctrine_Table_Exception if there is already an instance of this table * @return void */ public function __construct($name, Doctrine_Connection $conn) { $this->conn = $conn; $this->setParent($this->conn); $this->options['name'] = $name; $this->_parser = new Doctrine_Relation_Parser($this); if (!class_exists($name) || empty($name)) { throw new Doctrine_Exception("Couldn't find class " . $name); } $record = new $name($this); $names = array(); $class = $name; // get parent classes do { if ($class == "Doctrine_Record") { break; } $name = $class; $names[] = $name; } while ($class = get_parent_class($class)); // reverse names $names = array_reverse($names); // save parents array_pop($names); $this->options['parents'] = $names; // create database table if (method_exists($record, 'setTableDefinition')) { $record->setTableDefinition(); // set the table definition for the given tree implementation if ($this->isTree()) { $this->getTree()->setTableDefinition(); } $this->columnCount = count($this->columns); if (isset($this->columns)) { // get the declaring class of setTableDefinition method $method = new ReflectionMethod($this->options['name'], 'setTableDefinition'); $class = $method->getDeclaringClass(); $this->options['declaringClass'] = $class; if (!isset($this->options['tableName'])) { $this->options['tableName'] = Doctrine::tableize($class->getName()); } switch (count($this->primaryKeys)) { case 0: $this->columns = array_merge(array('id' => array('type' => 'integer', 'length' => 20, 'autoincrement' => true, 'primary' => true)), $this->columns); $this->primaryKeys[] = 'id'; $this->identifier = 'id'; $this->identifierType = Doctrine::IDENTIFIER_AUTOINC; $this->columnCount++; break; default: if (count($this->primaryKeys) > 1) { $this->identifier = $this->primaryKeys; $this->identifierType = Doctrine::IDENTIFIER_COMPOSITE; } else { foreach ($this->primaryKeys as $pk) { $e = $this->columns[$pk]; $found = false; foreach ($e as $option => $value) { if ($found) { break; } $e2 = explode(':', $option); switch (strtolower($e2[0])) { case 'autoincrement': case 'autoinc': $this->identifierType = Doctrine::IDENTIFIER_AUTOINC; $found = true; break; case 'seq': case 'sequence': $this->identifierType = Doctrine::IDENTIFIER_SEQUENCE; $found = true; if ($value) { $this->options['sequenceName'] = $value; } else { if (($sequence = $this->getAttribute(Doctrine::ATTR_DEFAULT_SEQUENCE)) !== null) { $this->options['sequenceName'] = $sequence; } else { $this->options['sequenceName'] = $this->conn->getSequenceName($this->options['tableName']); } } break; } } if (!isset($this->identifierType)) { $this->identifierType = Doctrine::IDENTIFIER_NATURAL; } $this->identifier = $pk; } } } } } else { throw new Doctrine_Table_Exception("Class '{$name}' has no table definition."); } $record->setUp(); // if tree, set up tree if ($this->isTree()) { $this->getTree()->setUp(); } $this->repository = new Doctrine_Table_Repository($this); }
/** * generateMigrationClass * * @return void */ public function generateMigrationClass($className, $options = array(), $up = null, $down = null, $return = false) { $className = Doctrine_Inflector::urlize($className); $className = str_replace('-', '_', $className); $className = Doctrine_Inflector::classify($className); if ($return || !$this->getMigrationsPath()) { return $this->buildMigrationClass($className, null, $options, $up, $down); } else { if (!$this->getMigrationsPath()) { throw new Doctrine_Migration_Exception('You must specify the path to your migrations.'); } $next = (string) $this->migration->getNextVersion(); $fileName = str_repeat('0', 3 - strlen($next)) . $next . '_' . Doctrine::tableize($className) . $this->suffix; $class = $this->buildMigrationClass($className, $fileName, $options, $up, $down); $path = $this->getMigrationsPath() . DIRECTORY_SEPARATOR . $fileName; if (class_exists($className) || file_exists($path)) { return false; } file_put_contents($path, $class); return true; } }