/** * Provided a modelClassName, members and corresponding rules columns array is generated for schema generation. * Members with unique validators are tracked separately to be used with index array generation later. * @param string $modelClassName * @param array $members * @param array $rules * @param $messageLogger * @return array * @throws CException */ public static function resolve($modelClassName, array $members, array $rules, &$messageLogger) { $messageLogger->addInfoMessage(Zurmo::t('Core', 'Building Column definitions for {{model}}', array('{{model}}' => $modelClassName))); $membersWithRules = array(); $columns = array(); foreach ($rules as $rule) { if (in_array($rule[0], $members)) { $membersWithRules[$rule[0]][] = $rule; } } foreach ($membersWithRules as $member => $rules) { $column = RedBeanModelMemberRulesToColumnAdapter::resolve($modelClassName, $rules, $messageLogger); if ($column) { $columns[] = $column; } else { $errorMessage = Zurmo::t('Core', 'Failed to resolve {{model}}.{{member}} to column', array('{{model}}' => $modelClassName, '{{member}}' => $member)); $messageLogger->addErrorMessage($errorMessage); throw new CException($errorMessage); } } if (count($members) != count($columns)) { $errorMessage = Zurmo::t('Core', 'Not all members for {{model}} could be translated to columns.', array('{{model}}' => $modelClassName)); $messageLogger->addErrorMessage($errorMessage); $errorMessage .= Zurmo::t('Core', 'Members') . ': ('; $errorMessage .= join(', ', $members); $errorMessage .= '),' . Zurmo::t('Core', 'Columns') . ' ('; // Not Coding Standard $columnNames = RedBeanModelMemberToColumnUtil::resolveColumnNamesArrayFromColumnSchemaDefinition($columns); $columnNames = join(', ', $columnNames); $errorMessage .= $columnNames . ')'; throw new CException($errorMessage); } $messageLogger->addInfoMessage(Zurmo::t('Core', 'Column definitions Built')); return $columns; }
/** * Generates Table schema for a model class using its metadata of members, relations, mixins and indexes. * @param string $modelClassName * @param $messageLogger * @return array|bool */ public static function resolve($modelClassName, &$messageLogger) { if (empty($modelClassName) || !@class_exists($modelClassName) || !$modelClassName::getCanHaveBean()) { return false; } $metadata = $modelClassName::getMetadata(); $modelMetadata = array(); if (isset($metadata[$modelClassName])) { $modelMetadata = $metadata[$modelClassName]; } $memberColumns = array(); $relationColumns = array(); $indexes = array(); $uniqueIndexesFromValidators = array(); $parentColumnName = null; if (isset($modelMetadata['members'])) { if (!isset($modelMetadata['rules'])) { $errorMessage = Zurmo::t('Core', '{{model}} must have both, members and rules, set.', array('{{model}}' => $modelClassName)); $messageLogger->addErrorMessage($errorMessage); throw new CException($errorMessage); } $memberColumns = RedBeanModelMemberRulesToColumnsAdapter::resolve($modelClassName, $modelMetadata['members'], $modelMetadata['rules'], $messageLogger); $uniqueIndexesFromValidators = RedBeanModelMemberRulesToColumnAdapter::resolveUniqueIndexesFromValidator($modelClassName); } if (isset($modelMetadata['relations'])) { $relationColumns = RedBeanModelRelationsToColumnsAdapter::resolve($modelClassName, $modelMetadata['relations'], $messageLogger); } if (isset($modelMetadata['indexes']) || !empty($uniqueIndexesFromValidators)) { $indexesMetadata = $uniqueIndexesFromValidators; if (!empty($modelMetadata['indexes'])) { if (!empty($indexesMetadata)) { $indexesMetadata = CMap::mergeArray($indexesMetadata, $modelMetadata['indexes']); } else { $indexesMetadata = $modelMetadata['indexes']; } } if (!empty($indexesMetadata)) { $indexes = RedBeanModelMemberIndexesMetadataAdapter::resolve($modelClassName, $indexesMetadata, $messageLogger); } } $parentColumnName = RedBeanModelChildParentRelationshipToColumnAdapter::resolve($modelClassName); if ($parentColumnName) { $memberColumns[] = $parentColumnName; } $mixinColumns = RedBeanModelMixinsToColumnsAdapter::resolve($modelClassName, $messageLogger); $columns = CMap::mergeArray($memberColumns, $mixinColumns, $relationColumns); $tableName = $modelClassName::getTableName(); $schemaDefinition = array($tableName => array('columns' => $columns, 'indexes' => $indexes)); return $schemaDefinition; }
/** * Adds externalSystemId column to specific table if it does not exist * @param $tableName * @param $maxLength * @param $columnName */ public static function addExternalIdColumnIfMissing($tableName, $maxLength = 255, $columnName = null) { if (!isset($columnName)) { $columnName = static::EXTERNAL_SYSTEM_ID_COLUMN_NAME; } // check if external_system_id exists in fields $columnExists = ZurmoRedBean::$writer->doesColumnExist($tableName, $columnName); if (!$columnExists) { // if not, update model and add an external_system_id field $type = 'string'; $length = null; RedBeanModelMemberRulesToColumnAdapter::resolveStringTypeAndLengthByMaxLength($type, $length, $maxLength); $columns = array(); $columns[] = RedBeanModelMemberToColumnUtil::resolveColumnMetadataByHintType($columnName, $type, $length); $schema = CreateOrUpdateExistingTableFromSchemaDefinitionArrayUtil::getTableSchema($tableName, $columns); CreateOrUpdateExistingTableFromSchemaDefinitionArrayUtil::generateOrUpdateTableBySchemaDefinition($schema, new MessageLogger()); } }
protected static function getReservedColumnMetadata() { $columns = array(); $reservedColumnsTypes = array('status' => 'integer', 'serializedMessages' => 'string', 'analysisStatus' => 'integer', 'serializedAnalysisMessages' => 'string'); foreach ($reservedColumnsTypes as $columnName => $type) { $length = null; $unsigned = null; if ($type === 'string') { // populate the proper type given it would be 1024 char string depending on db type. RedBeanModelMemberRulesToColumnAdapter::resolveStringTypeAndLengthByMaxLength($type, $length, 1024); } else { // forcing integers to be unsigned $unsigned = DatabaseCompatibilityUtil::resolveUnsignedByHintType($type, false); } // last argument is false because we do not want these column names to be resolved to lower characters $columns[] = RedBeanModelMemberToColumnUtil::resolveColumnMetadataByHintType($columnName, $type, $length, $unsigned, null, null, null, false); } return $columns; }
/** * @depends testResolveUniqueIndexesFromValidator */ public function testResolveWithUniqueValidator() { $unsigned = null; $assumedSigned = RedBeanModelMemberRulesToColumnAdapter::ASSUME_SIGNED; if (!$assumedSigned) { $unsigned = 'UNSIGNED'; } $modelClassName = 'AuditEvent'; $rules = array(array('attributeName', 'unique'), array('attributeName', 'type', 'type' => 'integer')); $column = RedBeanModelMemberRulesToColumnAdapter::resolve($modelClassName, $rules, static::$messageLogger); $this->assertNotEmpty($column); $this->assertArrayHasKey('name', $column); $this->assertArrayHasKey('type', $column); $this->assertArrayHasKey('unsigned', $column); $this->assertArrayHasKey('notNull', $column); $this->assertArrayHasKey('collation', $column); $this->assertArrayHasKey('default', $column); $this->assertEquals('attributename', $column['name']); $this->assertEquals('INT(11)', $column['type']); $this->assertEquals($unsigned, $column['unsigned']); $this->assertEquals('NULL', $column['notNull']); // Not Coding Standard $this->assertNull($column['collation']); $this->assertEquals('DEFAULT NULL', $column['default']); // Not Coding Standard $uniqueIndex = RedBeanModelMemberRulesToColumnAdapter::resolveUniqueIndexesFromValidator($modelClassName); $this->assertNotEmpty($uniqueIndex); $this->assertCount(1, $uniqueIndex); $indexName = key($uniqueIndex); $this->assertCount(2, $uniqueIndex[$indexName]); $this->assertArrayHasKey('members', $uniqueIndex[$indexName]); $this->assertArrayHasKey('unique', $uniqueIndex[$indexName]); $this->assertCount(1, $uniqueIndex[$indexName]['members']); $this->assertEquals('attributeName', $uniqueIndex[$indexName]['members'][0]); $this->assertTrue($uniqueIndex[$indexName]['unique']); }