/**
  * テーブルマイグレートを自動解決する
  * @param unknown $argDBO
  * @param unknown $argTable
  * @return boolean
  */
 public static function resolve($argDBO, $argTblName, $argLastMigrationHash = NULL)
 {
     static $executed = array();
     // 1プロセス内で同じテーブルに対してのマイグレーションを2度も処理しない
     if (FALSE === (isset($executed[$argTblName]) && TRUE === $executed[$argTblName])) {
         $firstMigration = TRUE;
         if (!isset(ORMapper::$modelHashs[$argTblName])) {
             // コンソールから強制マイグレーションされる時に恐らくココを通る
             $nowModel = ORMapper::getModel($argDBO, $argTblName);
         }
         // XXX ORMapperとMigrationManagerは循環しているのでいじる時は気をつけて!
         $modelHash = ORMapper::$modelHashs[$argTblName];
         // modelハッシュがmigrationハッシュに含まれていないかどうか
         $migrationHash = $argLastMigrationHash;
         if (NULL === $migrationHash) {
             // 既に見つけているマイグレーションハッシュから定義を取得する
             $diff = self::_getDiff($argDBO, $argTblName);
             if (NULL !== self::$_lastMigrationHash) {
                 $migrationHash = self::$_lastMigrationHash;
             }
         }
         debug('$migrationHash=' . $migrationHash);
         debug('$modelHash=' . $modelHash);
         // マイグレーションハッシュがある場合は
         if (NULL !== $migrationHash) {
             if (FALSE !== strpos($migrationHash, $modelHash)) {
                 // このテーブルはマイグレーション済み
                 $executed[$argTblName] = TRUE;
                 // 現在のテーブル定義と最新のマイグレーションファイル上のテーブルハッシュに差分が無いので何もしない
                 debug('exists migration! ' . $migrationHash);
                 return TRUE;
             }
             // 最後に適用している該当テーブルに対してのマイグレーションクラスを読み込んでmodelハッシュを比較する
             $migrationFilePath = getAutoMigrationPath() . $argDBO->dbidentifykey . '.' . $migrationHash . '.migration.php';
             if (TRUE === file_exists($migrationFilePath) && TRUE === is_file($migrationFilePath)) {
                 // 既にテーブルはあるとココで断定
                 $firstMigration = FALSE;
                 // 直前のマイグレーションクラスをインスタンス化
                 @(include_once $migrationFilePath);
                 // モデルハッシュが変わっているかどうかを比較
                 if ($modelHash == $migrationHash::$migrationHash) {
                     // このテーブルはマイグレーション済み
                     $executed[$argTblName] = TRUE;
                     // 現在のテーブル定義と最新のマイグレーションファイル上のテーブルハッシュに差分が無いので何もしない
                     return TRUE;
                 }
             }
         }
         // テーブル定義を取得
         $tableDefs = ORMapper::getModelPropertyDefs($argDBO, $argTblName);
         $describeDef = $tableDefs['describeDef'];
         $migrationClassDef = PHP_EOL;
         $migrationClassDef .= PHP_EOL . PHP_TAB . 'public function __construct(){' . PHP_EOL . PHP_TAB . PHP_TAB . str_replace('; ', ';' . PHP_EOL . PHP_TAB . PHP_TAB, $describeDef) . 'return;' . PHP_EOL . PHP_TAB . '}' . PHP_EOL;
         if (TRUE === $firstMigration) {
             // create指示を生成
             $migrationClassDef .= PHP_EOL . PHP_TAB . 'public function up($argDBO){' . PHP_EOL . PHP_TAB . PHP_TAB . 'return $this->create($argDBO);' . PHP_EOL . PHP_TAB . '}' . PHP_EOL;
             // drop指示を生成
             $migrationClassDef .= PHP_EOL . PHP_TAB . 'public function down($argDBO){' . PHP_EOL . PHP_TAB . PHP_TAB . 'return $this->drop($argDBO);' . PHP_EOL . PHP_TAB . '}' . PHP_EOL;
         } else {
             // ALTERかDROP指示を生成
             $upAlterDef = '$alter = array(); ';
             $downAlterDef = '$alter = array(); ';
             // 差分をフィールドを走査して特定する
             $lastModel = new $migrationHash();
             $beforeDescribes = $lastModel->describes;
             $describes = array();
             $beforeFieldKey = NULL;
             eval(str_replace('$this->', '$', $describeDef));
             // 増えてる減ってるでループの起点を切り替え
             if (count($describes) >= count($beforeDescribes)) {
                 // フィールドが増えている もしくは数は変わらない
                 foreach ($describes as $feldKey => $propary) {
                     // 最新のテーブル定義に合わせて
                     $alter = NULL;
                     if (!array_key_exists($feldKey, $beforeDescribes)) {
                         // 増えてるフィールドを単純に増やす
                         $alter = 'ADD';
                         $downAlterDef .= '$alter["' . $feldKey . '"] = array(); ';
                         $downAlterDef .= '$alter["' . $feldKey . '"]["alter"] = "DROP"; ';
                     } elseif (sha1(serialize($propary)) != sha1(serialize($beforeDescribes[$feldKey]))) {
                         // ハッシュ値が違うので新しいフィールド情報でAlterする
                         $alter = 'MODIFY';
                         // 元に戻すMODYFI
                         $alterDefs = ORMapper::getModelPropertyDefs($argDBO, $argTblName, array($feldKey => $beforeDescribes[$feldKey]));
                         $downAlterDef .= str_replace('$this->describes = array(); ', '', $alterDefs['describeDef']);
                         $downAlterDef .= '$alter["' . $feldKey . '"]["alter"] = "' . $alter . '"; ';
                     }
                     if (NULL === $alter) {
                         // 処理をスキップして次のループへ
                         $beforeFieldKey = $feldKey;
                         continue;
                     }
                     // up生成
                     $alterDefs = ORMapper::getModelPropertyDefs($argDBO, $argTblName, array($feldKey => $propary));
                     $upAlterDef .= str_replace('$this->describes = array(); ', '', $alterDefs['describeDef']);
                     $upAlterDef .= '$alter["' . $feldKey . '"]["alter"] = "' . $alter . '"; ';
                     if ('ADD' === $alter) {
                         if (NULL === $beforeFieldKey) {
                             // 先頭にフィールドが増えている
                             $upAlterDef .= '$alter["' . $feldKey . '"]["first"] = TRUE;';
                         } else {
                             // ADDする箇所の指定
                             $upAlterDef .= '$alter["' . $feldKey . '"]["after"] = "' . $beforeFieldKey . '";';
                         }
                     }
                     $beforeFieldKey = $feldKey;
                 }
             } else {
                 // フィールドが減っている
                 // XXX upとdownがただ増えている時と逆なだけ
                 foreach ($beforeDescribes as $feldKey => $propary) {
                     // 前のテーブル定義に合わせて
                     $alter = NULL;
                     if (!array_key_exists($feldKey, $describes)) {
                         // 減ってるフィールドを単純にARTER DROPする
                         $alter = 'ADD';
                         $upAlterDef .= '$alter["' . $feldKey . '"] = array(); ';
                         $upAlterDef .= '$alter["' . $feldKey . '"]["alter"] = "DROP"; ';
                     } elseif (sha1(serialize($propary)) != sha1(serialize($describes[$feldKey]))) {
                         // ハッシュ値が違うので新しいフィールド情報でAlterする
                         $alter = 'MODIFY';
                         // 元に戻すMODYFI
                         $alterDefs = ORMapper::getModelPropertyDefs($argDBO, $argTblName, array($feldKey => $describes[$feldKey]));
                         $upAlterDef .= str_replace('$this->describes = array(); ', '', $alterDefs['describeDef']);
                         $upAlterDef .= '$alter["' . $feldKey . '"]["alter"] = "' . $alter . '"; ';
                     }
                     if (NULL === $alter) {
                         // 処理をスキップして次のループへ
                         $beforeFieldKey = $feldKey;
                         continue;
                     }
                     // down生成
                     $alterDefs = ORMapper::getModelPropertyDefs($argDBO, $argTblName, array($feldKey => $propary));
                     $downAlterDef .= str_replace('$this->describes = array(); ', '', $alterDefs['describeDef']);
                     $downAlterDef .= '$alter["' . $feldKey . '"]["alter"] = "' . $alter . '"; ';
                     if ('ADD' === $alter) {
                         if (NULL === $beforeFieldKey) {
                             // 先頭にフィールドが増えている
                             $downAlterDef .= '$alter["' . $feldKey . '"]["first"] = TRUE;';
                         } else {
                             // ADDする箇所の指定
                             $downAlterDef .= '$alter["' . $feldKey . '"]["after"] = "' . $beforeFieldKey . '";';
                         }
                     }
                     $beforeFieldKey = $feldKey;
                 }
             }
             // alter指示を生成
             $migrationClassDef .= PHP_EOL . PHP_TAB . 'public function up($argDBO){' . PHP_EOL . PHP_TAB . PHP_TAB . str_replace('$this->describes', '$alter', str_replace('; ', ';' . PHP_EOL . PHP_TAB . PHP_TAB, $upAlterDef)) . PHP_EOL . PHP_TAB . PHP_TAB . 'return $this->alter($argDBO, $alter);' . PHP_EOL . PHP_TAB . '}' . PHP_EOL;
             $migrationClassDef .= PHP_EOL . PHP_TAB . 'public function down($argDBO){' . PHP_EOL . PHP_TAB . PHP_TAB . str_replace('$this->describes', '$alter', str_replace('; ', ';' . PHP_EOL . PHP_TAB . PHP_TAB, $downAlterDef)) . PHP_EOL . PHP_TAB . PHP_TAB . 'return $this->alter($argDBO, $alter);' . PHP_EOL . PHP_TAB . '}' . PHP_EOL;
         }
         // 現在の定義でマイグレーションファイルを生成する
         $migrationClassName = self::_createMigrationClassName($argTblName) . '_' . $modelHash;
         $migrationClassDef = 'class ' . $migrationClassName . ' extends MigrationBase {' . PHP_EOL . PHP_EOL . PHP_TAB . 'public $tableName = "' . strtolower($argTblName) . '";' . PHP_EOL . PHP_EOL . PHP_TAB . 'public static $migrationHash = "' . $modelHash . '";' . $migrationClassDef . '}';
         $path = getAutoMigrationPath() . $argDBO->dbidentifykey . '.' . $migrationClassName . '.migration.php';
         @file_put_contents($path, '<?php' . PHP_EOL . PHP_EOL . $migrationClassDef . PHP_EOL . PHP_EOL . '?>');
         @chmod($path, 0777);
         // 生成した場合は、生成環境のマイグレーションが最新で、適用済みと言う事になるので
         // マイグレーション済みファイルを生成し、新たにマイグレーション一覧に追記する
         @file_put_contents_e(getAutoMigrationPath() . $argDBO->dbidentifykey . '.all.migrations', $migrationClassName . PHP_EOL, FILE_APPEND);
         @file_put_contents_e(getAutoMigrationPath() . $argDBO->dbidentifykey . '.dispatched.migrations', $migrationClassName . PHP_EOL, FILE_APPEND);
         $executed[$argTblName] = TRUE;
         debug('migration! ' . $migrationClassName);
     }
     return TRUE;
 }
Пример #2
0
/**
 * クラス自動生成のキャッシュ
 */
function generateClassCache($argGeneratedPath, $argIncludePath, $argClassBuffer, $argClassName = '')
{
    $classCheck = $argClassName;
    if ('' !== $argClassName) {
        $classCheck = ' && !class_exists(\'' . $argClassName . '\', FALSE)';
    }
    // 先ず先頭に条件文を追加
    @file_put_contents_e($argGeneratedPath, '<?php' . sprintf(_getAutoGenerateIncPHPMainBase(), $argIncludePath) . '?>', FILE_PREPEND);
    // ファイルの終端に処理を追加
    @file_put_contents_e($argGeneratedPath, '<?php' . PHP_EOL . 'if(FALSE === $unlink' . $classCheck . '){ ' . PHP_EOL . $argClassBuffer . PHP_EOL . '}' . PHP_EOL . '?>', FILE_APPEND);
    @chmod($argGeneratedPath, 0777);
}