腹が減ってはなんとやら

大学院博士課程から脱落しました。

gitでローカルからpushして自動で公開されるようにする。

バージョン管理しつつ複数人でサーバー上のアプリを開発できるようにgitを導入しました。

まずGitの基本であるcommit, clone, push, pull等については博多弁を喋るおサルさんに教えていただきました(サルでも分かるGit入門)。 とてもわかり易いです。 これを見れば複数人で同時に編集し、競合が起きた場合の対処まであっさり導入できました。

友人・俺「こんな簡単やったら最初からやっとけばよかったな」
意気揚々と試しに友人と一緒にに更新してみました

しかし、ここで問題発生!

リモートにpushはできてgitのlogも残るけど、サーバー上で公開しているファイルが更新されない。 どうやら大きな勘違いをしていたようです。 gitはバージョン管理ツールであって、webに公開するのはまた別の話でした。

この時点ではサーバー上のこれまで開発していたアプリのディレクトリ内でgit initして、それをローカルにcloneしました。 サーバー上のgit initしたディレクトリに向けてpushすると.git内にバージョンの情報は蓄積されるけど、ファイルは更新されませんでした。

gitのmasterの最新バージョンをサーバー上のファイルに直接反映させたい場合は別の手続きが必要でした。

ローカルからpushして自動で公開する方法

1. もし既に開発しているファイル(app/)があればそのディレクトリ内でgit initして全ファイルをadd、commitしておく。

cd app/へのパス
git init
git add .
git commit

2. サーバー上のどこかにapp.gitという名前のディレクトリを作る(中身は空)。その中でgit --bare initを実行。--bareする時は慣例としてディレクトリ名に.gitをつけるらしい。

mkdir app.git
cd app.gitへのパス
git --bare init

3. 1.でgit initしてたらそこからapp.gitにpushします。

cd app/へのパス
git push app.git/へのパス master

pushしたら1.のディレクトリは不要です。削除して問題ありません。 1.がなく1から開発を行う場合は何もする必要はありません。 READMEでも作ってadd,commitしてみましょう。

4. app.gitから製作者が各々ローカルにクローンを作ります。 これに関してはおサルさんの言うとおりにすればできるハズ!

5. サーバー内でapp.gitからドキュメントルート上にクローンを作っておきます。

git clone app.git/へのパス 公開するディレクトリのパス

これで指定したパス内にクローンのディレクトリが出来上がります。

6. app.git/hooks/post-receive.sampleをコピーしてpost-receiveという名前でその場に保存。中はshellスクリプトになっていて、1番下に

cd app.git/hooks
cp post-receive.sample post-receive

コピーしたpost-receiveの1番下に以下の文を追加

cd /var/www/html/app/
git --git-dir=.git pull

ここを参考にしました。 post-receiveはプッシュを受け付けたら実行するファイルらしいです。 つまり、プッシュがあれば自動で公開しているアプリ内でpullして更新してくれます。

これでローカルからpushしたらサーバーで公開してるファイルも自動で更新されます。

補足

3.で最初のgit initしたapp/は削除しました。 これを残しておいてwebに公開し、ここで自動pullするようにしたらいいと思ったのですが、それはどうやらダメらしい。 pullするのはクローンを作ったとこでってことらしい。

参考

CakePHPでデータベースのfieldの値を演算して更新する。

おいっす。 CakePHPでデータベースのfieldの値を変更するのに、updateAll(公式API)を使いました。

例えば、usersテーブルで登録されたbirthdayっていうfiledが今日の日付と一致してた時にageというfieldに1加算するとします。

<?php

    public function toshitotta() {
        $today = date("Y-m-d")
        $this->User->updateAll(
            array('User.age' => 'User.age + 1'),
        array('User.birthday =' =>  $today)
        );

ってな感じです。

これだと毎日toshitottaアクションを行う必要があるので、できたらcronで実行したいな。

CakePHPでカレンダー表示1

CakePHPでToDoアプリ作成中です。 アプリ内ではタスクをカレンダーを表示させましたが、それに関して少しまとめます。

カレンダー自体はスーパーサンプルを参考に作りました。

作るにあたって悩んだ点は以下、

  1. カレンダーを生成するコードはCakePHPのどこに置いたらええのん?
  2. タスクはどうやって載せるん?
  3. 前月や来月への遷移でけへん。。

ってな感じです。

1. カレンダーを生成するコードはCakePHPのどこに置いたらええのん?

カレンダーを生成するコードはヘルパーにしました。 VendorとかPluginとかいっぱいディレクトリあってよく分からん。 とりあえず分からんのやったらMVCのディレクトリ以外は極力触らない方針がいいとの結論。

2. タスクはどうやって載せるん?

最初、カレンダーをヘルパーで作って、後でJavascriptで追加したらええかと思ったんですけど、どうやらイマイチらしい。 ここではとりあえずイマイチっぽいとだけ認識して、いつか勉強します。

で、カレンダーを生成する段階でタスクも挿入されるようにヘルパーを書き換えました。 予定を載せるためのアクションを作り、載せる予定のデータをViewにsetしてviewファイルでカレンダーヘルパーを使ってカレンダーを作る時にデータを渡します。 面倒かと思ったら案外簡単でした。

3. 前月や来月への遷移でけへん。。

まず月を移動する時にタスクの情報と何月になるかの情報を渡すんですけど、getメソッドで渡しました。 初心者なもんで本当はgetを使いたくなかったんです。。。なんか怖くて(><) けど、他にいいのが思いつかなかったので。 てかこういう時こそgetを使うのか?

コードの細かいところについては気が向いたらまた記事にします。

ほなさようなら。

bootstrap.phpを攻める-CakePHPをもくじとしてPHPを学ぶ04

前回は/app/webroot/index.phpを見ていてbootstrap.phpをincludeしました。 今回はこの中身を見ます。 全部見てたらキリがないので関係ありそうな(僕がそう思ってるだけ)とこだけ見ていくことにします。

多分どっかでspl_autoload_registerって関数を使ってるので見ると160行目あたりで使ってますね。

<?php

spl_autoload_register(array('App', 'load'));

これでAppクラスのloadメソッドがクラスローダーになり、未定義のオブジェクトのインスタンスが存在しない場合、このloadメソッドが呼ばれます。 AppクラスはCore/App.phpです。その中のloadメソッドを見ると

<?php

public static function load($className) {
        if (!isset(self::$_classMap[$className])) {
            return false;
        }

        $parts = explode('.', self::$_classMap[$className], 2);
        list($plugin, $package) = count($parts) > 1 ? $parts : array(null, current($parts));

        if ($file = self::_mapped($className, $plugin)) {
            return include $file;
        }
        $paths = self::path($package, $plugin);

        if (empty($plugin)) {
            $appLibs = empty(self::$_packages['Lib']) ? APPLIBS : current(self::$_packages['Lib']);
            $paths[] = $appLibs . $package . DS;
            $paths[] = APP . $package . DS;
            $paths[] = CAKE . $package . DS;
        } else {
            $pluginPath = self::pluginPath($plugin);
            $paths[] = $pluginPath . 'Lib' . DS . $package . DS;
            $paths[] = $pluginPath . $package . DS;
        }

        $normalizedClassName = str_replace('\\', DS, $className);
        foreach ($paths as $path) {
            $file = $path . $normalizedClassName . '.php';
            if (file_exists($file)) {
                self::_map($file, $className, $plugin);
                return include $file;
            }
        }

        return false;
    }

はい533行目あたりにありました。

ここで必要なのは、どのファイル内のクラスをオートロードするかってことやけど、このソースの中で言う$classMapがそれですね。 これはAppクラスのusesメソッドで

<?php

    public static function uses($className, $location) {
        self::$_classMap[$className] = $location;
    }

と定義します。 例えば、ちょっとbootstrap.phpに戻るとspl_autoload_register関数の直後に

<?php

App::uses('ErrorHandler', 'Error');
App::uses('Configure', 'Core');
App::uses('CakePlugin', 'Core');
App::uses('Cache', 'Cache');
App::uses('Object', 'Core');
App::uses('Multibyte', 'I18n');

ってな感じでusesをスコープしてます。これでどのクラスをオートロードするのか定義します。他にも定義してるとこあります。 ちなみに、Appクラスはloadメソッドを含んでいるのでオートロードできません。 別でrequireする必要がありますが、bootstrap.phpの140行目で既にrequireされています。 これでオートロードの設定はできたことにして、次回はDispatcherを見に行きます。

課題

  • スコープ定義演算子の使いドコロがよく分からん。

/app/webroot/index.phpを読む-CakePHPをもくじとしてPHPを学ぶ03

前回に.htaccessを追って/app/webroot/index.phpにたどり着きました。 今回はindex.phpの中身を見ます。以下中身です。

<?php

if (!defined('DS')) {
    define('DS', DIRECTORY_SEPARATOR);
}

if (!defined('ROOT')) {
    define('ROOT', dirname(dirname(dirname(__FILE__))));
}

if (!defined('APP_DIR')) {
    define('APP_DIR', basename(dirname(dirname(__FILE__))));
}

if (!defined('WEBROOT_DIR')) {
    define('WEBROOT_DIR', basename(dirname(__FILE__)));
}

if (!defined('WWW_ROOT')) {
    define('WWW_ROOT', dirname(__FILE__) . DS);
}

if (php_sapi_name() == 'cli-server') {
    if ($_SERVER['REQUEST_URI'] !== '/' && file_exists(WWW_ROOT . $_SERVER['REQUEST_URI'])) {
        return false;
    }
    $_SERVER['PHP_SELF'] = '/' . basename(__FILE__);
}

まず色々定数を定義してますね。 サーバーのドキュメントルートが/var/www/htmlだったとして、そこにダウンロードした/cakephpディレクトリを置いてる場合、定義した定数はそれぞれ

  • DS = /
  • ROOT = /var/www/html/cakephp/
  • APP_DIR = app
  • WEBROOT_DIR = webroot
  • WWW_ROOT = /var/www/html/cakephp/app/webroot/
  • $_SERVER['PHP_SELF'] = /cakephp/app/webroot/index.php

になります。以下続きのコードです。

<?php

if (!defined('CAKE_CORE_INCLUDE_PATH')) {
    if (function_exists('ini_set')) {
        ini_set('include_path', ROOT . DS . 'lib' . PATH_SEPARATOR . ini_get('include_path'));
    }
    if (!include ('Cake' . DS . 'bootstrap.php')) {
        $failed = true;
    }
} else {
    if (!include (CAKE_CORE_INCLUDE_PATH . DS . 'Cake' . DS . 'bootstrap.php')) {
        $failed = true;
    }
}
if (!empty($failed)) {
    trigger_error("CakePHP core could not be found. Check the value of CAKE_CORE_INCLUDE_PATH in APP/webroot/index.php. It should point to the directory containing your " . DS . "cake core directory and your " . DS . "vendors root directory.", E_USER_ERROR);
}

App::uses('Dispatcher', 'Routing');

$Dispatcher = new Dispatcher();
$Dispatcher->dispatch(
    new CakeRequest(),
    new CakeResponse()
);

次に、パスを通してます。 CAKE_CORE_INCLUDE_PATHは定義してないので、このif文には入ります。 次に、ini_set('include_path',...)でライブラリのパスを通します。 そんでもってbootstrap.phpをincludeします。 このbootstrap.phpでは他ディレクトリにあるクラスなどを自動でロードしてくれるので、規約通りにファイル名等を設定していれば、includeやrequireしなくてもclassが使えるようになります。

その後Dispatcherというクラスのインスタンスを生成してますね。 次回はbootstrap.phpの中身を見るかDispatcherを見に行くかどっちかかな。

自動リンクが止まらない

ダミーのURLを使った記事書いてたら勝手にリンクにしてくれました。 もちろんダミーなので困ります。 調べると、[ ]〜[ ]で囲むとリンクが貼られないようです。

ほらね。 これで問題解決と思いきや、新たな問題発生。

困っていた記事で html のようにコードを書いた部分を色付けしてたんですけど、こうするとその後の[ ]〜[ ]が効かなくなった。

これは[ ]〜[ ]で囲んでます→http://example.jp

さらにリストにするとちゃんと機能します。

  • これも[ ]〜[ ]で囲んでます→http://example.jp

ほらね。 よく分からん。