春咲さんのメモ。

自分メモ的な。主にPHPについて。github:mindlessdoll(冬眠してるけど)

超初歩なVagrantメモ

CentOS入れて、Vagrant入れて、さぁ、共有されてるVagrantfileで環境作るべってなった時、Vagrantfileがあるのに次どうするか分からなかったのでメモというかなんと言うか。

Box作るの?どうするの?Vagrantfileの中みたらBoxも作ってるよ、じゃ次は何をすればいいのよ?てなって。

まぁ、ただVagrantfileのある場所で

>vagrant up

って打っただけなんですがwwwww

 

これ、なんでGoogle先生で見つからなかったんだろう。まだまだGoogle先生を使いこなせないのはなぜ。

Cakephp2 独自SQLでPaginateしたやつのソートと検索。

これもはまった。

独自SQLでPaginateするのはググると結構出てくるので割愛。

ソートにはまった。はまったはまった。

結論:「virtualFields」を使う。

あ…割愛しないでやっぱり書きます。えぇ、将来の自分のためにですとも!!

PaginateOrigin.php(この子があることで独自SQLでのPaginateが可能になります)

App::uses('AppModel', 'Model');

class PaginateOrigin extends AppModel {
    public $name = 'PaginateOrigin';
    public $useTable = false;
    public $virtualFields = array(
        'teh_experience_id' => 'PaginateOrigin.experience_id',
        'teh_nickname'      => 'PaginateOrigin.nickname',
        'teh_edit_time'     => 'PaginateOrigin.edit_time',
    );
    /**
     * ページネート実行 未審査取得
     *
     */

    public function paginate() {
        $condition = func_get_arg(0);
        $fileds    = func_get_arg(1);
        $order     = func_get_arg(2);
        $limit     = func_get_arg(3);
        $page      = func_get_arg(4);
        $recursive = func_get_arg(5);
        $extra     = func_get_arg(6);

        // SQL文
        $sql = $extra['extra']['type'];
        if (count($order) > 0) {
            $strOrderSql = '';
            $numCnt = 0;
            foreach ($order as $key => $value) {
                $keys = explode('.', $key);
                $key = $keys[1];
                if ($numCnt > 0) {
                    $strOrderSql .= ',' . $key . ' ' . $value;
                } else {
                    $strOrderSql .= $key . ' ' . $value;
                }
                $numCnt++;
            }
            $sql .= ' ORDER BY ' . $strOrderSql;
        }
        $sql .= ' LIMIT ' . $limit;
        if ($page > 1) {
            $sql .= ' OFFSET ' . ($limit * ($page - 1));
        }

        return $this->query($sql);
    }

    /**
     * ページネート実行(カウント処理)
     *
     */
    public function paginateCount() {
        $extra = func_get_arg(2);
        return count($this->query(
            preg_replace(
                '/LIMIT \d+ OFFSET \d+$/u',
                '',
                $extra['extra']['type']
            )
        ));
    }

    public function hasField($name, $checkVirtual = false) {
        return true;
    }

}

ArticleExamination.phpという独自SQLを書いたもの

App::uses('PaginateOrigin', 'Model');
class ArticleExamination extends PaginateOrigin {

    public $name = 'ArticleExamination';
    public $useTable = false;

    public function getList($in, $where) {
        $in = implode(',', $in);
        $strSql = <<< EOM
SELECT
    teh.post_status AS post_status
    ,teh.working_on_flg              AS working_on_flg
    ,teh.experience_id               AS experience_id
    ,m_group.group_name              AS group_name
    ,teh.post_title                  AS post_title
    ,user_info.nickname              AS nickname
    ,teh.edit_time                   AS edit_time
    ,teh.plan_team_judgment_status   AS plan_team_judgment_status
    ,plan_account.name               AS plan_account_name
    ,teh.editor_team_judgment_status AS editor_team_judgment_status
    ,editor_account.name             AS editor_account_name
FROM t_experience_history AS teh
LEFT OUTER JOIN m_group ON teh.post_group_id = m_group.id
LEFT OUTER JOIN
    (
        SELECT
            t_user.nickname AS nickname
            ,t_experience.id AS experience_id
        FROM t_user
        INNER JOIN t_experience ON t_user.id = t_experience.user_id
    ) AS user_info
ON teh.experience_id = user_info.experience_id
LEFT OUTER JOIN m_management_account AS plan_account ON teh.plan_team_judgment_account_id = plan_account.id
LEFT OUTER JOIN m_management_account AS editor_account ON teh.editor_team_judgment_account_id = editor_account.id
WHERE teh.post_status IN ({$in})
AND teh.delete_flg = 0
EOM;

    if ($where) {
$strWhere = <<< EOM
 AND ( user_info.nickname LIKE '%{$where}%' OR teh.post_title LIKE '%{$where}%' OR teh.experience_id LIKE '%{$where}%' )
EOM;
        $strSql .= $strWhere;
    }
        return $strSql;
    }
}

これで準備OK

さて本題のController

App::uses('AppController', 'Controller');

class ArticleExaminationController extends AppController {

    // レイアウト指定
    public $layout = 'adminMainLayout';
    public $uses   = array('PaginateOrigin', 'ArticleExamination');
    public $components = array('Admin', 'Paginator');

    public function entryList() {
        $user = $this->Auth->user();
        if (is_null($user)) {
            $this->redirect('/admin/');
        }
        // 検索データがある場合、Where句に設定
        $where = null;
        if ($this->data['search']) {
            $where = $this->data['search'];
        }

        // データ取得条件設定
        switch ($this->request->params['poststatus']) {
            case 'examination':
            // 未審査・審査中
                $in = array(TExperienceHistory::UNEXAMINED, TExperienceHistory::UNDER_EXAMINATION);
                break;
            case 'judgement':
            // 編集長判断待ち
                $in = array(TExperienceHistory::CHIEF_JUDGEMENT_WAITING);
                break;
            case 'reject':
            // 差し戻し
                $in = array(TExperienceHistory::REMAND_WAITING);
                break;
            case 'waiting':
            // 公開待ち
                $in = array(TExperienceHistory::PUBLIC_WAITING);
                break;
            case 'non_examination':
            // 公開済・差し戻し済
                $in = array(TExperienceHistory::PUBLISHED, TExperienceHistory::REMAND_ALREADY);
                break;
            default:
                $this->redirect('/admin/dashboard/');
                break;
        }
        // SQL
        $query = array(
            'order' => array('teh.id' => 'asc'),
            'limit' => 20,
            'extra' => array(
                'type' => $this->ArticleExamination->getList($in, $where),
            ),
        );

        // ページャー設定
        $this->Paginator->settings = $query;
        // データ取得
        $data = $this->Paginator->paginate('PaginateOrigin');

        // リストデータ
        $this->set('data', $data);

        // View設定
        $this->render('/Admin/ArticleExamination/entry_list');
    }

この辺は関係ないので割愛

}

あ、あとViewね。これ大事

    echo $this->Html->url(array('controller' => 'ArticleExamination', 'action' => 'entryList', 'poststatus' => $this->params['poststatus'])) . '/page:1/sort:PaginateOrigin.nickname/direction:asc';

こんな感じです

重要なのは、PaginateOrigin.php

    public $virtualFields = array(
        'teh_experience_id' => 'PaginateOrigin.experience_id',
        'teh_nickname'      => 'PaginateOrigin.nickname',
        'teh_edit_time'     => 'PaginateOrigin.edit_time',
    );

ですな。ソートで使いたいやつを宣言しておきます。

'一意になればなんでもいい' => 'モデル名.カラム名'

ってなってます。

コントローラのポイントは

$uses = array('PaginateOrigin', 'ArticleExamination');

です。PaginateOrigin($virtualFieldsを定義したModel)を一番左に書かないとソートうまく動かないんです。めんどくさい。

 

本当にざっとですみません。

Cakephpの認証時に独自テーブルを使ってはまりました。

えぇ、はまりましたよ。

Auth認証。

本家ではUserテーブルを使ってますよね。

認証 — CakePHP Cookbook 2.x ドキュメント

今回はUserテーブル使いません。usernameなんてフィールドもありません。

認証に使うテーブル:ManagementAccount

各フィールド名

 username→login_id

 password→そのまま

 

さて。

まずModel

<?php

App::uses('AppModel', 'Model');
App::uses('BlowfishPasswordHasher', 'Controller/Component/Auth');
App::uses('AuthComponent', 'Controller/Component');

class ManagementAccount extends AppModel {
    public $name = 'ManagementAccount';
    public $useTable = 'm_management_account';

    public $validate = array(
        'login_id' => array(
            'required' => array(
                'rule' => 'notBlank',
                'message' => 'A username is required'
            )
        ),
        'password' => array(
            'required' => array(
                'rule' => 'notBlank',
                'message' => 'A password is required'
            )
        ),
    );
    public function beforeSave($options = array()) {
        if (isset($this->data[$this->alias]['password'])) {
            $passwordHasher = new BlowfishPasswordHasher();
            $this->data[$this->alias]['password'] = $passwordHasher->hash(
                $this->data[$this->alias]['password']
            );
        }
        return true;
    }
}
    

ここでポイントになるのが「AuthComponent」こいつを使う宣言をすること

次にController

App::uses('AppController', 'Controller');

class AdminLoginController extends AppController {

    public $components = array('Auth');
    // レイアウト指定
    public $layout = 'adminLoginLayout';

    public function beforeFilter(){
        $this->autoLayout = false;
        parent::beforeFilter();
        $this->Auth->autoRedirect = false;
        $this->Auth->allow('index', 'logout');

        $this->Auth->loginAction    = '/admin/login/';
        $this->Auth->loginRedirect  = '/admin/dashboard';
        $this->Auth->logoutRedirect = '/admin/';

        $this->Auth->authorize = 'Controller';
        // フォームの認証設定
        $this->Auth->authenticate = array(

            // フォーム認証を利用
            'Form' => array(
                // 認証に利用するモデルの変更
                'userModel' => 'ManagementAccount', //HogeUserモデルを指定
                // 認証に利用するモデルのフィードを変更
                'fields' => array('username' => 'login_id', 'password' => 'password')
            )
        );
    }


    public function index() {
        $this->set('title_for_layout', '管理画面');
    }

    public function login() {
        if ($this->request->is('post')) {
            if ($this->Auth->login()) {
                $this->redirect('/admin/dashboard');
            } else {
                //$this->Session->setFlash(__('Invalid username or password, try again'));
                $this->redirect('/admin/');
            }
        } else {
            $this->redirect('/admin/');
        }
    }

    public function dashboard() {

    }

    public function logout() {
        $this->redirect($this->Auth->logout());
    }
}

ここでのポイントは「$this->Auth->authenticate 」の設定

次にView

<?php echo $this->Form->create('ManagementAccount', array('url' => '/admin/login')); ?>
<table>
<tbody>
<tr>
<th>
<img src="/img/admin/icon_user.gif" width="16" height="14" alt="ユーザーID">
</th>
<td>
<input name="data[ManagementAccount][login_id]" type="text" id="ManagementAccountUsername"/>
</td>
</tr>
<tr>
<th>
<img src="/img/admin/icon_pass.gif" width="16" height="17" alt="パスワード">
</th>
<td>
<?php echo $this->Form->input('password', array('label' => false)); ?>
</td>
</tr>
</tbody>
</table>
<p class="login">
</p>
<?php echo $this->Form->end('ログイン'); ?>

login_idだけ、Formヘルパーで生成するとセレクトボックスになってしまうので手書きです

これだけなんだけどね!

あとあと、重要なんだけど、パスワードはvar_dumpとかでAuthComponent::password使ってハッシュ化したものをテーブルに登録しておかないと通らないよ!

ajaxSubmitで、success時のdata.successがそんなもんねーよって言われた。

まぁね、どーしようもない理由だったんだけどね。

dataType: 'json',

これが抜けてたw

他では抜けててもうまくいってたんだけどなぁ…

あと、jsonをシングルコーテーションでくくるの忘れてJSエラーになって結構な時間悩んだり、アホな子です。

ajaxの処理が完了してから実行したい処理がある。

ajaxってさ、非同期通信で便利なんだけど、処理結果によって後続の処理をどうするか決めたい時あるじゃん?

ajax実行(登録最大値を取得している)

 ↓

処理A

って書いても、ajaxの処理中に処理Aが実行されて、登録最大値越してるのに!なんか処理A走ってる!てきなことになりました。

結論からいうと、$.when $.doneってのを使いました

	$.when(
		$.ajax({
			url:  '/check_max_user',
			type: 'POST',
			dataType: 'json',
			success: function(data, status, xhr) {
				if (!data.success) {
					max_user_flg = true;
          alert('お腹いっぱいだお');
					return false;
				} else {
					max_user_flg = false;
				}
			}
		})
	).done(function(){
	if (!max_user_flg) {
以下略

こうするとね、whenの中身実行してからdoneの処理を実行するわけですよ。

便利だな。

 

気が付いたんだけどさ、最近phpネタ書いてない…orz

jQuery File Uploadで任意のタイミングであぷろーどさせたい。

環境は一式そろってて、改修が必要だった。

現行:ファイル選択後そのままアップロード処理実行

改修内容:「確認」ボタンを押してからアップロード処理実行

addってところで、確認ボタンが押されてからsubmitするよってことになります。

それだけ。

 

$('#csvupload').fileupload({

 dataType: 'json',
 url: $.seap.webroot + 'user_account/csv/import',
 add: function(e,data) {
  data.context = $('.button_edit').click(function(){
    data.submit();
  });
 },
 done: function (e, data) {
  if(data.result.length > 0) {
   var result = true;
   var done_msg = '';
   var fail_msg = '';
   for(var fi = 0; fi < data.result.length; fi++) {
    result = result && data.result[fi]['success'];
	if(data.result[fi]['success'] == true) {
	 done_msg += "\n" + data.result[fi]['message'];
	} else {
	 fail_msg += "\n" + data.result[fi]['message'];
	}
   }
   if(result) {
	alert("アップロード完了" + done_msg);
	location.href = $.seap.webroot + 'user_account/';
   } else {
	alert("一括登録に失敗しました。" + fail_msg.replace('\\n','\n'));
	$('.filename').text('');
   }
   $('.csv_drop_field .label').html('');
   }
  },
  fail: function (e, data) {
   alert("アップロードに失敗しました");
   $('.csv_drop_field .label').html('');
  },

  progressall: function (e, data) {
   var progress = parseInt(data.loaded / data.total * 100, 10);
   var progresshtml = "アップロード中 : " + progress + "%";
   $('.csv_drop_field .label').html(progresshtml);
  },
});
以下略。

jQuery Uniform ajax

いい題名が思いつかなかったw

さて。

ページ遷移時、ajaxから結果取得してjsでHTML生成して吐き出してるのですが、その際にuniformをあてても反映されない。どうしたものか。

結果↓

    $( "button").uniform(); 
  $.uniform.update();

 今回は、buttonだけ反映させたかったのでbuttonだけ。

他にも適用させたかったら

  $( "select, input:checkbox, input:radio, input:file").uniform(); 
  $.uniform.update();

みたいに指定すればいいらしい。