読者です 読者をやめる 読者になる 読者になる

CakePHPで使うneocomplcache.vim用スニペットを書いてみた。

最近、CakePHP1.3系を使ってるのですが、素晴らしい!
さくさく楽しい開発ライフです。


でも、自分は覚えが悪いので、
「アレどうやるんだっけ?」 → CakePHPのマニュアルを引く、本を見る
となって時間を費やしてしまっています。


コードを書くときにはVimを使っています。
neocomplcache.vim、zencoding.vimなど素晴らしいプラグインやテキストオブジェクトのおかげで、
タイプミスも少なく素早くコードが書けるようになりました。


でも、もっともっと速く書きたい。。。


よく使うCakePHPの記述はneocomplcacheのスニペットにしたら楽かも・・・!
んで覚えられるかも!よし、スニペットを書いてみよう!


ということで、やってみました。

ユーザ定義用スニペットファイル

スニペットの場所は、.vimrcで指定しています。

" ユーザー定義スニペット保存ディレクトリ
let g:neocomplcache_snippets_dir = $HOME.'/.vim/snippets'


思い立ったらすぐ追加/編集/確認ができるように、
esで(現在のファイルタイプの)ユーザ定義用スニペットファイルを開くようにしました。

" :NeoComplCacheEditSnippets [filetype]
" ユーザ定義用のスニペットファイルの編集ができる。
" ftを指定しなければ現在のftのスニペットファイルを開く。
" ちなみに、プラグインに組み込まれてるスニペットファイルは下記にある。
" ~/.vim/autoload/neocomplcache/sources/snippets_complete/
nnoremap <silent> <Space>es  :<C-u>NeoComplCacheEditSnippets 

:NeoComplCacheEditSnippets の後ろには半角スペースが1個入っています。


スニペットファイルは、ファイルタイプがphpの場合、~/.vim/snippets/php.snip になります。
なければ、自動的につくられるようです。



で、こんな感じになりました。

~/.vim/snippets/php.snip

# c : Controller
# m : Model
# p : <?php
# e : echo
# h : Htmlヘルパー
# f : Formヘルパー

# --------------------------------------------------
# Controller
# --------------------------------------------------
snippet controller
	<?php
	class ${1}Controller extends ${3:AppController} {
		
		var $name = '${2}';
		var $uses = null;
		// var $scaffold;
		// var $view = 'Theme';
		// var $theme = '';
		// var $layout = 'default';
		// var $components = array();
		// var $helpers = array();
		
		function index() {
		}
		${0}
	}

snippet cset
        $this->set('${1:name}', ${2:value});${0}
snippet credirect
        $this->redirect(array('controller' => '${1:controller_name}', 'action' => '${2:action_name}'));${0}


# --------------------------------------------------
# Model
# --------------------------------------------------
snippet model
	class ${1:singular_name} extends ${2:AppModel} {
	
		var $name = '${3:singular_name}';
		var $validate = array(
	
		);
		${0}
	}

snippet mhasone
    var $hasOne = array(
        '${1:model_name}' => array(
            'className' => '${2:model_name}',
            'foreignKey' => '${3}',
            'conditions' => array(),    // 該当レコードに追加する検索条件
            'fields' => array(),        // 該当フィールド名
            'dependent' => false,       // 自分を削除した場合にアソシエーション側も削除する場合はtrue。
        ),
    );
    ${0}

snippet mhasmeny
    var $hasMany = array(
        '${1:model_name}' => array(
            'className' => '${2:model_name}',
            'foreignKey' => '${3}', // 自分(モデル)のどのカラムが上記モデルの外部キーとなっているか
            // 'conditions' => array(), // 該当レコードに追加する検索条件
            // 'fields' => array(), // 該当フィールド名
            // 'order' => array('' => 'desc/asc'), // 並び替え絵を行うフィールド
            // 'limit' => 10, // 取得したいレコード最大数
            // 'offset' => 5, // スキップするレコード数
            // 'dependent' => true, // 自分を削除した場合にアソシエーション側も削除する場合true
            // 'exclusive' => false, // deleteAllによって一括で削除を行いたい場合はtrue
            // 'finderQuery' => '', // find時に独自のSQLが必要な場合に指定する
        ),
    );
    ${0}



snippet mbelongsto
    var $belongsTo = array(
        '${1:model_name}' => array(
            'className' => '${2:model_name}',
            'foreignKey' => '${3}',		// 自分のどのカラムが上記モデルの外部キーとなっているか
            'conditions' => array(),	// 該当レコードに追加する検索条件
            'fields' => array(),		// 該当フィールド名
            'dependent' => false,		// 自分を削除した場合にアソシエーション側も削除する場合はtrue。
        ),
    );
    ${0}

snippet mfind
    $this->${1:model_name}->find(
        '${2:all/first/count/list/threaded/neighbours}',
        array(
            'conditions' => array(
                '${3:where_column}' => ${4:where_condition},
            ),
            // 'fields' => array('',''),
            // 'fields' => array('sum(hoge_count) as "Hoge.hoge_count"'),
            // 'limit' => 10,
            // 'order' => array('Model.col' => 'desc/asc'),
            // 'recursive' => -1,
        )
    );
    ${0}



snippet mv
	'${1:field_name}' => array(
		'rule' => '${2:rule}',
		'message' => '${3:error_message}',
		// 'required' => true, /* 必須*/
		// 'allowEmpty' => true, /* 空文字の許可*/
		// 'last' => false, /* そのエラーが発生した時点で以降のバリデーションは打ち切り */
		// 'on' => 'update', /* 'create'か'update'時にバリデーションを限定する */
	),
    ${0}

snippet mvrnotempty
    'rule' => 'notEmpty',${0}

snippet mvrblank
    'rule' => 'blank',${0}

snippet mvrnumeric
    'rule' => 'numeric',${0}

snippet mvralphanumeric
    'rule' => 'alphaNumeric',${0}

snippet mvrboolean
    'rule' => 'boolean',${0}

snippet mvrdecimal
    'rule' => array('decimal', ${1:number_of_decimal_places}),${0}

snippet mvrminlength
    'rule' => array('minLength', ${1:length}),${0}

snippet mvrmaxlength
    'rule' => array('maxLength', ${1:length}),${0}

snippet mvrbetween
    'rule' => array('between', ${1:min<=}, ${2:<=max}),${0}

snippet mvrrange
    'rule' => array('range', ${1:min<}, ${2:<max}),${0}

snippet mvrinlist
    'rule' => array('inList', array(${1:value}, ${2:value})),${0}

snippet mvrcomparison
    'rule' => array('comparison', '${1:>/</>=/<=/==/!=}', ${2:value}),${0}

snippet mvrequalto
    'rule' => array('equalTo', '${1:value}'),${0}

snippet mvremail
    'rule' => 'email',${0}

snippet mvrextension
    'rule' => array('extension', ${1:array('gif', 'jpeg', 'png', 'jpg')}),${0}

snippet mvrip
    'rule' => array('ip', '${1:ipv4/ipv6/both}'),${0}

snippet mvrmoney
    'rule' => array('money', '${1:left/right}'),${0}

snippet mvrmultiplein
    'rule' => array('multiple', array(${1:value_list})),${0}

snippet mvrmultiplecount
    'rule' => array('multiple', array('min' => ${1:min_selected}, 'max' => ${2:max_selected})),${0}

snippet mvrurl
    'rule' => 'url',${0}

snippet mvrcustom
    'rule' => array('custom', '${1:/regex/}'),${0}

snippet mvrregex
    'rule' => array('custom', '${1:/regex/}'),${0}

snippet mvrcreditcard
    'rule' => array('cc', '${1:fast/all/amex/diners/jcb/mc/visa}', ${2:true}),${0}

snippet mvrcc
    'rule' => array('cc', '${1:fast/all/amex/diners/jcb/mc/visa}', ${2:true}),${0}

snippet mvrdate
    'rule' => array('date', '${1:ymd}'),${0}

snippet mvrtime
    'rule' => 'time',${0}

snippet msave
    $this->${1:model_name}->save( ${2:array_data}, ${3:true}, ${4:array_validate_fields})${0}


# --------------------------------------------------
# View
# --------------------------------------------------
snippet pelement
    <?php e($this->element('${1:element_name}')); ?>${0}


# --------------------------------------------------
# Html helper
# --------------------------------------------------
snippet pehdoctype
    <?php echo $html->doctype('${1:html4-strict/html4-trans/html4-frame/xhtml-strict/xhtml-trans/xhtml-frame/xhtml11}'); ?>${0}

snippet pehmeta
    <?php echo $html->meta('${1:keywords/description}', '{$2:content}'); ?>${0}

snippet pehfavicon
    <?php echo $html->meta('icon', '/favicon.ico'); ?>${0}

snippet pehcharset
    <?php echo $html->charset('${1:UTF-8}'); ?>${0}

snippet pehcss
    <?php echo $html->css('${1:css_name}'); ?>${0}

snippet pehscript
    <?php echo $html->script('${1:js_name}', array('inline' => ${2:true})); ?>${0}

snippet pehscriptcode
	<?php echo $html->scriptStart(array('inline' => ${1:true}, 'safe' => ${2:true})); ?>${0}
	$(function(){
	${1}
	});
	<?php echo $html->scriptEnd(); ?>
	${0}

snippet pehlink
    <?php e( $html->link('${1:title}', array('controller' => '${2:controller}', 'action' => '${3:action}', 'admin' => ${4:false} ), array('escape' => ${5:true})) ); ?>${0}

snippet pehlink_confirm
    <?php e( $html->link('${1:title}', array('controller' => '${2:controller}', 'action' => '${3:action}', 'admin' => ${4:false} ), array('escape' => ${5:true}), '${6:confirm_text}') ); ?>${0}

snippet pehlink_url
    <?php echo( $html->link('${1:title}', '${2:url}', array('escape' => ${3:false})) ); ?>${0}

snippet pehlink_img
    <?php e( $html->link($html->image('${1:path from /img}', array('alt' => '${2}')), array('controller' => '${3:controller}', 'action' => '${4:action}', 'admin' => ${5:false} ), array('escape' => ${6:false})) ); ?>${0}

snippet pehimg
    <?php echo $html->image('${1:path from /img}', array('alt' => '${2}' ,'url' => '${3}')); ?>${0}

snippet pehtag
    <?php echo $html->tag('${1:tag_name}', ${2:inner_html}, array('escape' => ${3:false}, ${4:attribute})); ?>${0}


# --------------------------------------------------
# Form helper
# --------------------------------------------------
snippet pefcreate
    <?php echo $form->create(); ?>${0}

snippet pefcreate_model
    <?php echo $form->create('${1:model_name}'); ?>${0}

snippet pefcreate_detail
    <?php echo $form->create('url' => array('controller' => '${1:controller_name}', 'action' => '${2:action_name}', 'admin' => false), 'id' => '${3:id_name}'); ?>${0}

snippet pefend
    <?php echo $form->end(); ?>${0}

snippet pefitext
    <?php echo $form->input('${1:field_name}', array('type' => 'text', 'maxLength' => ${2:max_length}, 'label' => false , 'error' => ${3:false}, 'class' => '${4:class_name}')); ?>${0}

snippet pefipassword
    <?php echo $form->input('${1:field_name}', array('type' => 'password', 'label' => false, 'error' => ${2:false}, 'class' => '${3:class_name}')); ?>${0}

snippet peficheckbox
    <?php echo $form->input('${1:field_name}', array('type' => 'checkbox', 'label' => false, 'error' => ${2:false}, 'class' => '${3:class_name}')); ?>${0}

snippet pefiselect
    <?php echo $form->input('${1:field_name}', array('type' => 'select', 'options' => array(${2:value} => '${3:text}'), 'empty' => ${4:false}, 'label' => false, 'error' => ${5:false}, 'class' => '${6:class_name}')); ?>${0}

snippet pefiradio
    <?php echo $form->input('${1:field_name}', array('type' => 'radio', 'options' => array(${2:value} => '${3:text}'), 'label' => false, 'legend' => ${4:false}, 'error' => ${5:false}, 'class' => '${6:class_name}')); ?>${0}

snippet pefitextarea
    <?php echo $form->input('${1:field_name}', array('type' => 'textarea', 'rows' => ${2:rows}, 'cols' => ${3:cols}, 'maxLength' => ${4:max_length}, 'label' => false, 'error' => ${5:false}, 'class' => '${6:class_name}')); ?>${0}

snippet pefihidden
    <?php echo $form->input('${1:field_name}', array('type' => 'hidden', 'label' => false , 'error' => ${2:false})); ?>${0}

snippet pefsubmit
    <?php echo $form->submit('${1:caption}', array('class' => '${2}')); ?>${0}

snippet pefbutton
    <?php echo $form->button('${1:title}', array('type' => '${2:button/reset/submit}', 'id' => '${3}', 'class' => '${4}', 'escape' => ${5:false})); ?>${0}

snippet peferror
    <?php echo $form->error('${1:field_name}', ${2:null}, array( 'wrap' => '${3:}', 'escape' => ${4:false})); ?>${0}

# --------------------------------------------------
# App
# --------------------------------------------------
snippet import
    App::import('${1:type}', '${2:name}');${0}

# --------------------------------------------------
# Set
# --------------------------------------------------
snippet set_extract
    Set::extract('${1:path}', ${2:array_data});${0}

snippet set_combine
    Set::combine(${1:array_data}, '${2:key_path}', '${3:value_path}','${4:group_path}');${0}

# --------------------------------------------------
# Configure
# --------------------------------------------------
snippet configure_load
    Configure::load('${1:file_name}');${0}

snippet configure_read
    Configure::read('${1:one.two.three.four}');${0}

# --------------------------------------------------
# Router
# --------------------------------------------------
snippet router_url
    Router::url(array('controller' => '${1:controller_name}', 'action' => '${2:action_name}', 'admin' => ${3:false}), false);${0} // ドメインを含むフルパスでURLを取得する場合は第二引数をtrueにする。

# --------------------------------------------------
# misc
# --------------------------------------------------
snippet e
    e(${1});${0}

snippet pr
    pr(${1});${0}

snippet ife
    ife(${1:condition}, ${2:ifNotEmpty}, ${3:ifEmpty});${0}

snippet pe
    <?php e(${1}); ?>${0}

snippet peh
    <?php e(h(${1})); ?>${0}

snippet error
    $this->cakeError('${1:error/error404/error500}', array('${2:param_name}' => '${3:param_value}'));${0}

snippet log
    CakeLog::write(${1:LOG_INFO}, '${2:message}');${0}



# --------------------------------------------------
# Component
# --------------------------------------------------
snippet component
    <?php

    class ${1:component_name}Component extends Object {

		/**
		 * コンポーネントの初期化の時に呼ばれるコールバック。
		 *
		 * @param object $controller コントローラのインスタンス
		 * @param mixed $settings コントローラ内の$componentsプロパティに登録するときに連想配列で受け取るパラメータ。
		 * @return void
		 */
		function initialize(&$controller, $settings) {
		
		}
		
		/**
		 * コントローラのbeforeFilter()が呼び出された後に実行されるコールバック。
		 *
		 * @param object $controller コントローラのインスタンス。
		 * @return void
		 */
		function startup(&$controller) {
		    
		}
		
		/**
		 * コントローラ内でrender()が実行される直前に実行されるコールバック。
		 *
		 * @param object $controller コントローラのインスタンス。
		 * @return void
		 */
		function beforeRender(&$controller) {
		    
		}
		
		/**
		 * リダイレクト実行直前に呼ばれるコールバック。
		 *
		 * @param object $controller コントローラのインスタンス。
		 * @param mixed $url Controller::redirect()で指定されたURL。Router::url()形式かstring。
		 * @param int $status Controllr::redirect()で指定されたHTTPステータスコード。通常200。
		 * @param bool $exit trueの場合、コントローラ内でexit()が呼び出されることを意味している。
		 * @return void
		 */
		function beforeRedirect(&$controller, $url, $status, $exit) {
		
		}
		
		/**
		 * コントローラのafterFilter()が実行される直前に実行されるコールバック。
		 *
		 * @param object $controller コントローラのインスタンス。
		 * @return void
		 */
		function shutdown(&$controller) {
		
		}
    }
    ${0}

# --------------------------------------------------
# JsHelper
# --------------------------------------------------
snippet js
    <?php
		${0}

		e($js->writeBuffer(array('inline' => true)));
    ?>

snippet jsbuffer
    $js->buffer(${1:script});${0}

snippet jsget
    $js->get("${1:id/class}");${0}

snippet jsevent
    // イベント対象は予め$js->get()で対象にしておく必要がある。
    $js->event("${1:event}", ${2:callback});

snippet jsalert
    $js->alert(${1:message});${0}

snippet jsvalue
    $js->set(${1:mixed});${0}

snippet jsset
    $js->set("${1:key}", ${2:value});${0}

snippet jsset_array
    $js->set(array("${1:key}" => ${2:value}));${0}

snippet jsdomready
    $js->domReady(${1:script});${0}


# --------------------------------------------------
# Ktai Library
# --------------------------------------------------
snippet emoji
    <?php $ktai->emoji(${1}); ?>${0}


# --------------------------------------------------
# php
# --------------------------------------------------
snippet func
	function ${1}(${2}) {
		${0:# code...}
	}

snippet vd
    var_dump( ${1} );${0}

snippet php
    <?php
    ${1}


snippet pfore
	<?php foreach ($${1:variable} as $${2:key}${3: =>}): ?>
	${0}
	<?php endforeach ?>

snippet pife
	<?php if (${1:condition}): ?>
	${2}
	<?php else: ?>
	${0}
	<?php endif ?>

snippet pif
	<?php if (${1:condition}): ?>
	${0}
	<?php endif ?>

snippet pelse
	<?php else: ?>


シンタックスエラーを出す回数も少なくなり、さくさく進んで楽しいです。
まだまだCakePHP初心者で勉強中なので、よく使う文がまたでてきたら書き足して育てていこうと思いました。



Pocket詳解 CakePHP辞典

Pocket詳解 CakePHP辞典


CakePHPブログチュートリアルをやった後には、この本を手元に置いておくのがオススメです。
自分以外の周りの人用にも買っちゃいました!


CakePHP、楽しいな−。