function checkForSK(&$obj)
 {
     return LumineTypes::checkIDField($obj, $this->params['dialect']);
 }
Exemplo n.º 2
0
 /**
  * Disable foreign key checks 
  */
 function disableForeignKeys($dialect)
 {
     if (!defined('LUMINE_TYPES_STARTED')) {
         LumineTypes::start($dialect);
     }
     switch ($dialect) {
         // mysql
         case 'mysqlt':
         case 'mysqli':
         case 'mysql':
             return 'SET FOREIGN_KEY_CHECKS=0';
             break;
     }
     return '';
 }
 /**
  * Create the database tables
  * <code>
  * require_once 'pah_to_lumine/LumineSchema.php';
  * $schema = new LumineSchema('your-conf-file.xml');
  * $schema->createSchema();
  * </code>
  * @author Hugo Ferreira da Silva
  * @access public
  * @return boolean True on success
  */
 function createSchema()
 {
     LumineLog::logger(1, 'Criando nova instancia do XML DOMIT', __FILE__, __LINE__);
     $doc =& new DOMIT_Document();
     $doc->resolveErrors(true);
     if (!$doc->loadXML($this->xml)) {
         LumineLog::logger(3, 'Arquivo de configuração com erros: ' . $doc->getErrorString(), __FILE__, __LINE__);
         $this->dienice("Erro no XML: " . $doc->getErrorString());
     }
     // item de configração
     LumineLog::logger(1, 'Verificando o bloco de configuração', __FILE__, __LINE__);
     $item =& $doc->getElementsByPath("/lumine-configuration/configuration", 1);
     if (!$item) {
         LumineLog::logger(3, 'Bloco de configuração não encontrado', __FILE__, __LINE__);
         $this->dienice("Elemento de configuração (<strong>configuration</strong>) não encontrado!");
     }
     // pega as configurações
     LumineLog::logger(1, 'Analisando itens da configuração', __FILE__, __LINE__);
     $config = array();
     for ($i = 0; $i < count($item->childNodes); $i++) {
         if ($item->childNodes[$i]->nodeType == 1) {
             $key = $item->childNodes[$i]->nodeName;
             $config[$key] = $item->childNodes[$i]->firstChild->nodeValue;
         }
     }
     // mapeamentos
     LumineLog::logger(1, 'Analisando mapeamentos', __FILE__, __LINE__);
     $maplist =& $doc->getElementsByPath("/lumine-configuration/mapping", 1);
     if (!$maplist) {
         LumineLog::logger(3, 'Bloco de mapeamentos não encontrado', __FILE__, __LINE__);
         $this->dienice("Bloco de mapemaento de entidades não encontrado");
     }
     // checa os itens do mapeamento
     LumineLog::logger(1, 'Solicitando itens dos mapeamentos', __FILE__, __LINE__);
     $maps =& $maplist->getElementsByPath("item");
     if ($maps->getLength() == 0) {
         LumineLog::logger(3, 'Não há mapeamentos para serem criados no banco', __FILE__, __LINE__);
         $this->dienice("Não há mapeamentos dentro da lista de mapas");
     }
     // checa se os arquivos informados existem
     LumineLog::logger(1, 'Checando existencia de itens', __FILE__, __LINE__);
     $files = array();
     for ($i = 0; $i < $maps->getLength(); $i++) {
         $it =& $maps->item($i);
         $file = $config['class-path'] . "/" . str_replace(".", "/", $it->getAttribute("src")) . ".xml";
         if (!file_exists($file)) {
             LumineLog::logger(3, 'Arquivo de mapeamento ' . $file . ' não existe!', __FILE__, __LINE__);
             $this->dienice("O arquivo de confiração do mapeamento <strong>{$file}</strong> não existe");
         }
         // checa o xml do mapeamento para ver se não há erros
         LumineLog::logger(1, 'Checando mapeamento: ' . $file, __FILE__, __LINE__);
         $xmlMap =& new DOMIT_Document();
         $xmlMap->resolveErrors(true);
         if (!$xmlMap->loadXML($file)) {
             LumineLog::logger(3, 'Arquivo de configuração ' . $file . ' com erros: ' . $xmlMap->getErrorString(), __FILE__, __LINE__);
             $this->dienice("Erro no arquivo de configuração <strong>{$file}</strong>: " . $xmlMap->getErrorString());
         }
         // carrega o xml de cada um e coloca numa matriz
         $files[$file] =& $xmlMap;
     }
     // recupera os tipo
     require_once LUMINE_INCLUDE_PATH . '/LumineTypes.php';
     LumineTypes::start($config['dialect']);
     // checa se o dialeto não foi informado
     if ($config['dialect'] == '') {
         LumineLog::logger(3, 'Dialeto não informado para conexão com o banco', __FILE__, __LINE__);
         $this->dienice("Dialeto não informado");
     }
     // checa se o dialeto existe
     LumineLog::logger(1, 'Incluindo arquivo de conexão com o banco: ' . $config['dialect'] . '.php', __FILE__, __LINE__);
     // importa a classe ADODB
     include_once LUMINE_INCLUDE_PATH . '/adodb/adodb.inc.php';
     // se não conseguir criar a instância do banco
     if (!($conn =& ADONewConnection($config['dialect']))) {
         LumineLog::logger(3, 'Classe de conexão <i>' . $config['dialect'] . '</i> não encontrada!', __FILE__, __LINE__);
         exit;
     }
     $this->cn =& $conn;
     $this->cn->SetFetchMode(ADODB_FETCH_ASSOC);
     if (!defined('LUMINE_RANDOM_FUNC')) {
         define('LUMINE_RANDOM_FUNC', $this->cn->random);
     }
     $ifschema = '';
     // verifica se foi informado o schema
     if (isset($config['schema']) && $config['schema'] != '') {
         // então cria o schema no banco
         $this->cn->query("CREATE SCHEMA " . $config['schema']);
         $ifschema = $config['schema'] . '.';
     } else {
         if (isset($config['schema-authorization']) && $config['schema-authorization'] != '') {
             // verifica se foi informado o schema-authorization
             // então cria o schema no banco
             $this->cn->query("CREATE SCHEMA AUTHORIZATION " . $config['schema-authorization']);
             $ifschema = $config['schema-authorization'] . '.';
         }
     }
     // se o schema foi informado, mudamos para ele
     if ($ifschema != '') {
         $this->cn->query("SET search_path TO " . substr($ifschema, 0, strlen($ifschema) - 1));
     }
     // inicia a escrita das tabelas
     $td =& $this->classes;
     foreach ($files as $file => $entity) {
         $first =& $entity->getElementsByPath("/lumine-map", 1);
         if (!$first) {
             $this->dienice("Elemento de definição incorreto para <strong>{$file}</strong>");
         }
         // table definition
         $table = $first->getAttribute("table");
         $td[$table]['class'] = $first->getAttribute("class");
         $td[$table]['tablename'] = $table;
         $td[$table]['extends'] = $first->getAttribute("extends");
         $id =& $first->getElementsByPath("id", 1);
         if ($id) {
             if ($id->getAttribute("name") == '') {
                 $this->dienice("O atributo <strong>name</strong> deve ser informado na definição da chave de sequencia do arquivo <strong>{$file}</strong>");
             }
             $generator =& $id->getElementsByPath("generator", 1);
             $column = @$id->getAttribute("column") == '' ? $id->getAttribute("name") : $id->getAttribute('column');
             $name = $id->getAttribute("name");
             //**********************************************************
             //** classes extendidas
             //**********************************************************
             if (!$generator && $id->hasAttribute("linkOn")) {
                 $td[$table]['primary-keys'][] = $column;
                 $fk =& $this->_getDefinitionByClass($td[$table]['extends']);
                 $fd =& $this->_getFieldDefinition($fk, $id->getAttribute('linkOn'));
                 $td[$table]['foreign-keys'][$name]['linkOn'] = $fd['column'];
                 $td[$table]['foreign-keys'][$name]['references'] = $fk['tablename'];
                 $td[$table]['foreign-keys'][$name]['ondelete'] = 'cascade';
                 $td[$table]['foreign-keys'][$name]['onupdate'] = 'cascade';
                 $td[$table]['foreign-keys'][$name]['not-null'] = true;
             } else {
                 if ($generator) {
                     $td[$table]['sequence-key']['column'] = $column;
                     $td[$table]['sequence-key']['name'] = $id->getAttribute('name');
                     $td[$table]['sequence-key']['generator'] = $generator->getAttribute("class");
                     $td[$table]['primary-keys'][] = $column;
                 } else {
                     LumineLog::logger(3, "Erro de definição de {$file}", __FILE__, __LINE__);
                     $this->dienice("não foi informado se a classe extende outra ou ao menos o gerador de sequencia desta classe");
                 }
             }
         }
         // propriedades
         $prop =& $first->getElementsByPath("property");
         for ($i = 0; $i < $prop->getLength(); $i++) {
             $node =& $prop->item($i);
             $name = $node->getAttribute("name");
             $type = $node->getAttribute("type");
             $notnull = $node->getAttribute("not-null") == 'true' ? true : false;
             $primary = $node->getAttribute("primary-key") == 'true' ? true : false;
             $default = $node->getAttribute("default");
             $column = $node->getAttribute("column") == '' ? $name : $node->getAttribute("column");
             if ($name == '') {
                 $this->dienice("O atributo <strong>name</strong> deve ser informado no elemento {$i} do arquivo <strong>{$file}</strong>");
             }
             if ($type == '') {
                 $this->dienice("Você deve informa o tipo da coluna");
             }
             $td[$table]['columns'][$name]['column'] = $column;
             $td[$table]['columns'][$name]['type'] = $type;
             if ($default != '') {
                 $td[$table]['columns'][$name]['default'] = $default;
             }
             if ($notnull == true) {
                 $td[$table]['columns'][$name]['not-null'] = true;
             }
             if ($primary == true) {
                 $td[$table]['primary-keys'][] = $column;
             }
         }
     }
     // reinicia a matriz, para procurarmos por chaves estrangeiras
     reset($files);
     // many-to-many relationships
     $many_to_many = array();
     $chaves = array_keys($files);
     foreach ($files as $file => $entity) {
         // procura many-to-one
         $first =& $entity->getElementsByPath("/lumine-map", 1);
         $table = $first->getAttribute("table");
         // chaves many-to-one
         $mto =& $first->getElementsByPath("many-to-one");
         for ($i = 0; $i < $mto->getLength(); $i++) {
             $node =& $mto->item($i);
             $class =& $node->getElementsByPath("class", 1);
             //echo "$file: " . $class->getAttribute("name") . "<br>";
             if (!$class) {
                 $this->dienice("A classe para a chave estrangeira <strong>{$name}</strong> não foi informada no arquivo <strong>{$file}</strong>");
             }
             $fk = $this->_getDefinitionByClass($class->getAttribute("name"));
             $name = $node->getAttribute("name");
             $reftable = $fk['tablename'];
             $linkOn = $class->getAttribute("linkOn");
             $column = $class->getAttribute("column");
             $ondelete = $class->getAttribute("ondelete");
             $onupdate = $class->getAttribute("onupdate");
             $notnull = $class->getAttribute("not-null") == 'true';
             //echo "$table, $name, $reftable, $linkOn, $column, $ondelete, $onupdate, $notnull<br>";
             if ($node->getAttribute("primary-key") == 'true') {
                 $td[$table]['primary-keys'][] = $column;
             }
             $td[$table]['foreign-keys'][$name]['column'] = $column;
             if ($linkOn == $fk['sequence-key']['column'] || $linkOn == $fk['sequence-key']['name']) {
                 $td[$table]['foreign-keys'][$name]['type'] = SEQUENCE_TYPE;
                 $linkOn = $fk['sequence-key']['column'];
             } else {
                 $td[$table]['foreign-keys'][$name]['type'] = $fd['type'];
                 $linkOn = $fd['column'];
             }
             $td[$table]['foreign-keys'][$name]['linkOn'] = $linkOn;
             $td[$table]['foreign-keys'][$name]['references'] = $reftable;
             $td[$table]['foreign-keys'][$name]['ondelete'] = $ondelete;
             $td[$table]['foreign-keys'][$name]['onupdate'] = $onupdate;
             $td[$table]['foreign-keys'][$name]['not-null'] = $notnull;
         }
         // procurando por chaves many-to-many
         $mtm = $first->getElementsByPath("many-to-many");
         for ($i = 0; $i < $mtm->getLength(); $i++) {
             $node =& $mtm->item($i);
             $class = $node->getElementsByPath("class", 1);
             if (!$class) {
                 $this->dienice("O elemento <strong>class</strong> necessário para chaves many-to-many não foi encontrado no arquivo <strong>{$file}</strong>");
             }
             $name = $node->getAttribute("name");
             $classname = $class->getAttribute("name");
             $linkOn = $class->getAttribute("linkOn");
             $reftable = $node->getAttribute("table");
             if ($name == '') {
                 $this->dienice("O atributo <strong>name</strong> para criação da chave many-to-many no arquivo <strong>{$file}</strong> deve ser informado");
             }
             if ($classname == '') {
                 $this->dienice("O atributo <strong>class.name</strong> para criação da chave many-to-many no arquivo <strong>{$file}</strong> deve ser informado");
             }
             if ($linkOn == '') {
                 $this->dienice("O atributo <strong>class.linkOn</strong> para criação da chave many-to-many no arquivo <strong>{$file}</strong> deve ser informado");
             }
             if ($reftable == '') {
                 $this->dienice("O atributo <strong>class.table</strong> para criação da chave many-to-many no arquivo <strong>{$file}</strong> deve ser informado");
             }
             $fk = $this->_getDefinitionByClass($classname);
             $c = array();
             $c['column'] = $fk['sequence-key']['column'] || $column == $fk['sequence-key']['name'] ? $fk['sequence-key']['column'] : $linkOn;
             // if($linkOn == $fk['sequence-key']['column'] || $linkOn == $fk['sequence-key']['name']) {
             $c['type'] = SEQUENCE_TYPE;
             // } else {
             //$c['type'] = $fk['columns'][$column]['type'];
             // }
             $c['references'] = $fk['tablename'];
             $c['ondelete'] = $class->getAttribute("ondelete");
             $c['onupdate'] = $class->getAttribute("onupdate");
             $many_to_many[$reftable][] = $c;
         }
     }
     // agora começaremos a criar as tabelas
     $tables = array();
     $alters = array();
     foreach ($this->classes as $name => $def) {
         $sql = "CREATE TABLE {$ifschema}{$name} (";
         // sequence key
         if (isset($def['sequence-key']) && $def['sequence-key']) {
             $sql .= $def['sequence-key']['column'] . ' ' . SEQUENCE_DEFINITION . ', ';
         }
         // foreign keys
         if (isset($def['foreign-keys']) && is_array($def['foreign-keys'])) {
             foreach ($def['foreign-keys'] as $fkname => $fkp) {
                 if (isset($fkp['column'])) {
                     $sql .= $fkp['column'] . ' ' . $fkp['type'];
                 } else {
                     if (isset($fkp['linkOn']) && isset($def['primary-keys']) && in_array($fkname, $def['primary-keys'])) {
                         $class_tmp = $this->classes[$fkp['references']];
                         $fk_tmp = $this->_getFieldDefinition($class_tmp, $fkp['linkOn']);
                         $sql .= $fkname . ' ' . SEQUENCE_TYPE;
                     }
                 }
                 if (isset($fkp['not-null']) && $fkp['not-null']) {
                     $sql .= ' not null';
                 }
                 $sql .= ', ';
             }
         }
         // campos
         if (is_array($def['columns'])) {
             foreach ($def['columns'] as $cname => $cdef) {
                 $sql .= $cdef['column'] . ' ' . $cdef['type'];
                 if (isset($cdef['not-null']) && $cdef['not-null'] == true) {
                     $sql .= ' not null';
                 }
                 $sql .= ', ';
             }
         }
         // colocando os INDEX para chaves estrangeiras
         if (isset($def['foreign-keys']) && is_array($def['foreign-keys'])) {
             reset($def['foreign-keys']);
             foreach ($def['foreign-keys'] as $fname => $fkp) {
                 if (CREATE_INDEX_FOR_FK) {
                     $sql .= "INDEX `FK_" . strtoupper(substr(md5(rand(0, time())), 0, 10)) . "`({$fkp['column']})";
                     $sql .= ', ';
                 }
                 $c = strtoupper(substr(md5(rand(0, time())), 0, 15));
                 if (!isset($fkp['column'])) {
                     $fkp['column'] = $fname;
                 }
                 $alter = "ALTER TABLE {$ifschema}{$name} ADD FOREIGN KEY({$fkp['column']}) REFERENCES {$ifschema}{$fkp['references']}({$fkp['linkOn']})";
                 if ($fkp['ondelete'] != '') {
                     $alter .= " ON DELETE {$fkp['ondelete']}";
                 }
                 if ($fkp['onupdate'] != '') {
                     $alter .= " ON UPDATE {$fkp['onupdate']}";
                 }
                 $alters[] = $alter;
             }
         }
         // colocando as primary keys
         if (isset($def['primary-keys']) && is_array($def['primary-keys'])) {
             $sql .= "PRIMARY KEY(";
             foreach ($def['primary-keys'] as $pname) {
                 $sql .= $pname . ", ";
             }
             $sql = substr($sql, 0, strlen($sql) - 2);
             $sql .= ")";
         }
         if (substr($sql, strlen($sql) - 2) == ', ') {
             $sql = substr($sql, 0, strlen($sql) - 2);
         }
         $sql .= ") " . TABLE_DEFINITION;
         $tables[$name] = $sql;
     }
     // agora, as many-to-many
     foreach ($many_to_many as $name => $def) {
         $sql = "CREATE TABLE {$ifschema}{$name} (";
         foreach ($def as $d) {
             $sql .= $d['column'] . ' ' . $d['type'] . ' not null, ';
         }
         $sql .= "PRIMARY KEY(";
         reset($def);
         foreach ($def as $d) {
             $sql .= $d['column'] . ', ';
         }
         $sql = substr($sql, 0, strlen($sql) - 2);
         $sql .= "), ";
         reset($def);
         foreach ($def as $d) {
             $x = strtoupper(substr(md5(rand(0, time())), 0, 15));
             if (CREATE_INDEX_FOR_FK) {
                 $sql .= "INDEX ({$d['column']}), ";
             }
             $alter = "ALTER TABLE " . $ifschema . $name . " ADD FOREIGN KEY({$d['column']}) REFERENCES {$ifschema}{$d['references']}({$d['column']})";
             if ($d['ondelete'] != '') {
                 $alter .= " ON DELETE {$d['ondelete']}";
             }
             if ($d['onupdate'] != '') {
                 $alter .= " ON UPDATE {$d['onupdate']}";
             }
             $alters[] = $alter;
         }
         $sql = substr($sql, 0, strlen($sql) - 2);
         $sql .= ") " . TABLE_DEFINITION;
         $tables[$name] = $sql;
     }
     // agora, cria no banco de dados
     /////// PARA MYSQL (POR ENQUANTO)
     $this->cn->connect($config['host'], $config['user'], $config['password'], $config['database']);
     $fkc = LumineTypes::disableForeignKeys($config['dialect']);
     if ($fkc != '') {
         $this->cn->query($fck);
     }
     $TablesInDatabase = $this->cn->MetaTables();
     foreach ($tables as $name => $sql) {
         if (in_array($name, $TablesInDatabase)) {
             LumineLog::logger(1, 'Dropando tabela existente: ' . $ifschema . $name, __FILE__, __LINE__);
             $this->cn->query("DROP TABLE " . $name);
         }
         LumineLog::logger(1, 'Executando SQL: ' . $sql, __FILE__, __LINE__);
         $this->cn->query($sql);
     }
     foreach ($alters as $sql) {
         LumineLog::logger(1, 'Executando SQL: ' . $sql, __FILE__, __LINE__);
         $this->cn->query($sql);
     }
     // se optou por criar as classes
     if ($config['create-classes'] == 1) {
         LumineLog::logger(1, 'Chamando rotina de criação das classes', __FILE__, __LINE__);
         $this->_createClasses($maps, $config);
     }
     // terminado
     return true;
 }