Cakephp2でページ毎のjsタグが散らばるので一括管理する

どのページにどのタグを埋めたか煩雑になるのでエレメントとヘルパーで管理する
ヘッダーでなくbodyの最後に埋めるタグがややこしくなったためテコ入れ。

Google Tag Manager使えよってコメントはなしで。


// View/Elements/body_tags.ctp でタグと読み込みページ設定

<?php
  // タグ毎に読み込むコントローラーとビューの指定
  // ['Controller'=>['action1', 'action2']];
  // のように配列で指定

  $yahoo = ['Goods'=>['index','detail'] ];
  $facebook = '*'; // 
  $user_trace = '*';
  $client_lp= ['Pages'=>['home'], 'Goods'=>['index', 'detail'], 'Contacts'=>['index']];
?>

<?php if( $this->Tags->is_able_tag($yahoo)): ?>
<!-- yahoo tag -->
  <script>
  ~~~~~
  </script>
<!--// yahoo tag -->
<?php endif ?> 

<?php if( $this->Tags->is_able_tag($facebook)): ?>
<!-- facebook tag -->
  <script>
  ~~~~~
  </script>
<!--// facebook tag -->
<?php endif ?> 

<?php if( $this->Tags->is_able_tag($user_trace)): ?>
<!-- user_trace tag -->
  <script>
  ~~~~~
  </script>
<!--// user_trace tag -->
<?php endif ?> 

// View/Helper/TagsHelper.php で判定の処理部分

<?php
App::uses('AppHelper', 'View/Helper');

class TagsHelper extends AppHelper {
    function is_able_tag($service){
      return $service==='*' || (isset($service[$this->name]) && isset(array_flip($service[$this->name])[mb_strtolower($this->action)]));
    }
}

// View/Layouts/default.ctp でエレメント読み込み

<?php

~~~~
$this->element('body_tags');
</body>

// Controller/AppController.php でヘルパー読み込み

<?php
class AppController extends Controller {
    public $helpers = ['Tags'];

余談 TagsHelperの解説

改行して訳し下してみました。

<?php
App::uses('AppHelper', 'View/Helper');

class TagsHelper extends AppHelper {
    function is_able_tag($service){
      return $service==='*'  // '*'だったらtrueで終了->常に読み込み
      || // '*'じゃなかったら 
      (
        isset($service[$this->name]) // 今のコントローラー名がキーになっていて
        &&  //かつ
        isset(
          array_flip($service[$this->name])  // その値の配列とkeyとvalueを入れ替えた時
          [strtolower(  // 念のため小文字にした
            $this->action  // アクション名が
          )] // keyになったものが  
        ) // 存在している
      );  //ならばtrue
    }}

isset(array_flip($array)[$value])
はin_arrayと同じく配列に値が含まれているか検索している。
こちらの方が早いので、valueに重複がない配列の際はおすすめ。

コントローラー名とアクション名については前回の記事をごらんあれ。

Cakephp2系でViewからビューしたいあれこれ

Cakephp2系でViewファイルから各項目へのアクセス

( Cakephp2.7 準拠)

※paramsのところをrequestにしても同じ。

@ http://example.com/user_settings/add_profile
<?php
// app/UserSettings/add_profile.ctp

// コントローラー
echo $this->name // 'UserSettings'

echo $this->params['controller'] // 'user_settings' (アクセスしたurlに依存)

// アクション
// どちらも 'add_profile'  (アクセスしたurlに依存)
echo $this->action ;
echo $this->params['action']; 

// 現在のurl
$this->params['url'] // 'user_settings/add_profile'

// 現在のパス
$this->params['here'] // '/user_settings/add_profile'

// POSTでわたされたデータ
$this->params->data;

// GETでわたされたデータ
$this->params->query;


// $this->setでセットされた変数一覧
echo $this->viewVars; 

余談 コントローラー名とアクション名の処理について

Cakephp2ではurlにするときに

  • コントローラー名はUpperCamelでもlower_snake でも有効
  • アクション名はlower_snakeでもUpper_snake (!?) でも有効

なので、"アクセスしたurlに依存"と書いたところは表記揺れが生じる。
文字列処理するならばInfrectorクラスなどを使って整形した方が良い

<?php
echo Inflector::camelize('upper_camel')  // 'UpperCamel'

https://book.cakephp.org/2.0/ja/core-utility-libraries/inflector.html

余談 2

上のはヘルパーからも同様に呼び出せる。

よいヘルパーライフを。

Cakephp3はおんなじパスワードいれても違うハッシュ値になるんやで

Cake2系だと同じパスワードだとハッシュ値も同じになっていたが、
3系のDefaultPasswordHasherは同じパスワードでも違うハッシュ値が返るようになった。

Authentication - 3.x

DefaultPasswordHasher uses the bcrypt hashing algorithm internally, which is one of the stronger password hashing solutions used in the industry.

訳すと、

DefaultPasswordHasherはbcryptのハッシュ化アルゴリズムを使用しています。これは工業的に使われている強いパスワードハッシュの解決策の一つです。

bcyptとな。と思って調べると調べた方がいらっしゃったので引用させていただく

BCrypt(Blowfish暗号)について調べたので文書化してみました - Kamiya::Memo

① $2a$ (1〜4文字目)

暗号化のバージョンです。
~~~~

② $10$ (4〜7文字目)

コストと呼ばれる数値です。ここを大きくしたほうが復号が困難になりますが、サーバへの負荷も大きくなります。4から31までが指定できるようです。

~~~~

③ OTKlbteacFY8DOeZY5imi. (コストの後からの22文字)

この22文字は、ソルトと呼ばれる文字列です。 上の文字列はドットで終わってますが、④に示す暗号本体との区切り文字は無く直接連結されています。

~~~~

④ wvNLmJ1WDenLlDSzXfFxizVX.D1BNfu (残りの部分)

暗号化パスワードの本体です。 ①〜③で指定されたオプションに従って暗号化されたパスワードの本体がこの文字列となります。

~~~~

⑤ ペッパー

~~~~

つまり、/config/app.phpにsaltを設定したのとは別にハッシュ内にsaltを持っていて、ハッシュ内のsaltがハッシュ化の度に違う値になるため同じパスワードをハッシュ化しても違う値になるということですね。

Cakephp3の認証は随分としょっぱくなっているようです。

Cakephp3でも$this->Auth->user()を使いたい!

Cakephp2系から3系へ移行した直後の方へシリーズ



$this->Auth->user()がCake3系にないのでヘルパーを作る。

幸いにも既にAuthHelperを作った方がおられるので、userメソッドだけ拡張させていただく

<?php
/**
 * AuthHelper: Authの変数にアクセスできる
 * @usage $this->Auth->get('Admin.id'), $this->Auth->get('User.email')
 * @usage $this->Auth->user(), $this->Auth->user('email')
 */
namespace App\View\Helper;
use Cake\View\Helper;
use Cake\Controller\Component;
class AuthHelper extends Helper
{
    /**
     * The current user, used for stateless authentication when
     * sessions are not available.
     *
     * @var array
     */
    protected $_user = null;
    /**
     * Initialize current user from session data
     * before rendering view.
     *
     * @return void
     */
    public function Initialize(array $config)
    {
        $this->_user = $this->request->Session()->read('Auth');
    }
    /**
     * Get the current user.
     *
     * @param  string $key field to retrieve. Leave null to get entire User record
     * @return array|null Either User record or null if no user is logged in.
     */
    public function get($key = null)
    {
        if( empty($key) ) {
            return $this->_user;
        }
        if( strpos($key, '.') !== false ) {
            list($sessionKey, $field) = explode('.', $key);
            return isset($this->_user[$sessionKey][$field]) ? $this->_user[$sessionKey][$field] : null;
        }
        return null;
    }

    public function user($key = null){
        return $this->get('User.'.$key);
    }
}

認証用ユーザーモデルがUserModelじゃない時はuser関数を
return $this->get('MyUser.'.$key);
で任意に書き換えてください。

しかしCakephp3系のコンセプトに真っ向から歯向かう改修ではある
(データ取得メソッドはgetつかってわかりやすく〜的なやつ)

Cakephp3でいい感じにログを吐き出す方法

$this->log()でいい感じに吐き出したい

ポイント
・log関数にinfoとかwarningとかのレベルを入れなきゃいけなくなったので初期値を与えてオーバーライドする
・呼び出し元をdebug_backtraceで取ってきて整形する

<?php

// AppControllerに追加してlog関数をオーバーライド

    public function log($message,$level='info',$filename='debug'){
        $bt = debug_backtrace();
        parent::log('#### Class '.$bt[1]['class'].' | function '.$bt[1]['function'].' - line '.$bt[0]['line'], $level, $filename);
        parent::log($message, $level, $filename);
    }

コントローラー内で$this->logが使える

<?php
// SomeController
  function index () {
    $this->log('hoge');
  }


// app/logs/debug.log

2017-11-01 16:29:14 Info: #### Class App\Controller\Admin\ArticlesController | function __authChk - line 746
2017-11-01 16:29:14 Info: hoge

表示形式が気に食わなかったり一つのログで2行出力すると発狂する場合はオーバーライドした関数を編集してください