Zend Framework1 + Doctrine2 + twigを組み合わせる(その6)

(その5から続く)

前回からさらに間隔があいてしまい、その間Doctrineは2.2へ、twigは1.6.1へと進化しました。連載で使用しているZend Framework1 + Doctrine2統合用ライブラリはgithubのコミットログを見るとDoctrine2.2への対応を取り込んでいるのでそのまま使えると思います。(ただし未検証)

さて今回はDoctrine2へのビヘイビアの取込です。Doctrine1では元々ビヘイビアの機能があったのですが、Doctrine2ではビヘイビアは本体からは取り除かれサードパーティに委ねられることになりました。現在githubにはDoctrine2用のエクステンションとして次の二つのプロジェクトがあります。(両者はクラスの名前空間が異なるので併用する場合は別階層に配置するか利用者が適当なマッピングをする必要があります。)

https://github.com/l3pp4rd/DoctrineExtensions

https://github.com/beberlei/DoctrineExtensions

今回は簡単な例としてTimestampableというビヘイビアを利用してみます。早い話が作成日・更新日を自動でupdateする機能です。
https://github.com/l3pp4rd/DoctrineExtensionsからlib/Gedmoをプロジェクトのlibrary/にコピーします。

wb portal front Zend Framework1 + Doctrine2 + twigを組み合わせる(その6)

Gedmoという名前空間をDoctrineに認識させるための設定を加えます。

resources.doctrine.orm.entityManagers.default.metadataDrivers.annotationRegistry.annotationNamespaces.0.namespace = "Gedmo"
resources.doctrine.orm.entityManagers.default.metadataDrivers.annotationRegistry.annotationNamespaces.0.includePath = APPLICATION_PATH "/../library"
view raw gistfile1.cfg This Gist brought to you by GitHub.

TimeStampableを利用するためにEventManagerとリスナーを登録します。

resources.doctrine.dbal.connections.default.eventManagerClass = "Doctrine\Common\EventManager"
resources.doctrine.dbal.connections.default.eventSubscribers[] = "Gedmo\Timestampable\TimestampableListener"
view raw gistfile1.cfg This Gist brought to you by GitHub.

TimeStampableを利用するための準備が出来たので、モデルにビヘイビアを追記します。まずアノテーションを利用するためのインポートをクラスの先頭で行います。

<?php

namespace Kdf\Entity;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;

/**
* User
*
* @Table(name="USER")
* @Entity(repositoryClass="Kdf\Entity\Repository\UserRepository")
*/
class User
{
 // (略)
view raw gistfile1.aw This Gist brought to you by GitHub.

モデルの作成日・更新日の定義にビヘイビアをアノテーションに記述します。

<?php

namespace Kdf\Entity;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;

/**
* User
*
* @Table(name="USER")
* @Entity(repositoryClass="Kdf\Entity\Repository\UserRepository")
*/
class User
{

// ... (略)...

    /**
* @var datetime $registerDate
*
* @ORM\Column(name="REGISTER_DATE", type="datetime")
* @Gedmo\Timestampable(on="create")
*/
    private $registerDate;

    /**
* @var datetime $updateDate
*
* @ORM\Column(name="UPDATE_DATE", type="datetime")
* @Gedmo\Timestampable(on="update")
*/
    private $updateDate;

view raw gistfile1.aw This Gist brought to you by GitHub.

以上でこのモデルに作成・更新がかかった場合は自動でタイムスタンプが更新されるようになります。

まとめ

ZF1とDoctrine2の統合については一旦これで終わります。他のビヘイビアの使い方についてもドキュメントは英語ですがgithub上のプロジェクトに説明がありますので、コード例を見れば比較的容易に使い方は判ると思います。ZF2が正式版になればDoctrineとの統合はより一層容易になると思われるので期待したいと思います。

Posted in 技術・開発ツール | Tagged , | Leave a comment

Zend Framework1 + Doctrine2 + twigを組み合わせる(その5)

その4から続く)

すっかり間隔があいてしまいました。いつのまにかTwigが1.5になってたりDoctrineもまもなく2.2になると発表されたりとぼやぼやしているとエントリを書き終わらないうちに陳腐化してしまう可能性がでてきました(汗

※なお、Zend FrameworkとTwigの連携に使用しているこのライブラリは今のところTwig1.5では動作しないので、Twig1.4をこのまま使用するものとします。

さて、Twigの動作が確認できたところでdebugの方法を早めに知っておきましょう。じつはTwig1.5からはdebugのための関数が標準で組み込まれるようになったのですが、Twig1.4ではdebugはextensionとして自分で組み込む必要があります。ここから持ってきます。

git clone https://github.com/fabpot/Twig-extensions.git

取得できたらTwig-extensions/lib/Twig/Extensionsをプロジェクトのlib/Twig配下にコピーします。

kdf Zend Framework1 + Doctrine2 + twigを組み合わせる(その5)

application.iniファイルでDebugエクステンションを読み込むように設定します。

resources.view.engines.twig.extensions.debug.class = "Twig_Extensions_Extension_Debug"

debugを行うのはもちろん開発環境だけなので.iniファイルのdevelopmentセクションにdebug結果を表示するように設定します。

[development : production]
  ...
resources.view.engines.twig.options.debug = 1

index.twigの{{name}}の前に{% debug name %}という行を加えて表示させるとこんな風に表示されるはずです。

http   kdf.localhost 8888  Zend Framework1 + Doctrine2 + twigを組み合わせる(その5)

このように{% debug ビューに表示する変数名 %}というコードをビュー(.twigファイル)に挿入すれば任意の変数の中身を確認することが出来ます。もし{% debug %}と記述した場合は現在のコンテキストにおけるtwigオブジェクトの中身がすべて出力されます。

この公式(?)extensionには他にもいくつかの便利関数があるのですが、数字のフォーマットを行う機能がありません。そこで探すとhttps://github.com/falmp/Twig-extensions/blob/master/lib/Twig/Extensions/Extension/Number.phpというのが見つかりました。このサードパーティのtwigエクステンションを追加する場合はプロジェクト内にlibrary/Twig/Extensions/Extension/Number.php として取得し

resources.view.engines.twig.extensions.number.class = "Twig_Extensions_Extension_Number"

を設定ファイルに加えます。ビューの中では

{{price | number() }}

とすれば3桁のカンマ区切りで表示されます。(なお、このextensionにはドキュメントが存在しないのですがソースを見ればどのようなフォーマットで出力できるのかは分かると思います。)

Twigのエクステンションは今のところそれほど豊富に存在していませんが既存のものを参考にすることで簡単に拡張できるようです。もちろん自分で書くのも良いのですが、symfonyな皆さんが便利なものをいろいろこれから作ってくれるはずなので期待しましょう。(笑)

今回の作業でapplication.iniはこんな感じになります。

; -----------------------------
; forked from https://github.com/guilhermeblanco/ZendFramework1-Doctrine2/blob/master/application/configs/application.ini
; -----------------------------

[production]

; --------------------------
; PHP Specific Configuration
; --------------------------
phpSettings.display_startup_errors = 0
phpSettings.display_errors = 0

includePaths.library = APPLICATION_PATH "/../library"
includePaths.models = APPLICATION_PATH "/models"

; ----------------------------------------
; Zend Framework Application Configuration
; ----------------------------------------
bootstrap.path = APPLICATION_PATH "/Bootstrap.php"
bootstrap.class = "Bootstrap"

pluginPaths.Bisna\Application\Resource\ = "Bisna/Application/Resource"
pluginPaths.Ano_Application_Resource = APPLICATION_PATH "/../library/Ano/Application/Resource"

autoloaderNamespaces[] = Bisna
autoloaderNamespaces[] = Symfony
autoloaderNamespaces[] = Doctrine
autoloaderNamespaces[] = Kdf\Entity
autoloaderNamespaces[] = "Twig_"
autoloaderNamespaces[] = "Ano_"

; ------------------------------
; Front Controller Configuration
; ------------------------------

resources.frontController.controllerDirectory = APPLICATION_PATH "/controllers"
resources.frontController.params.displayExceptions = 0


; ------------------------------------------------------------------------------
; Doctrine Class Loader Configuration
; ------------------------------------------------------------------------------

; ------------------------------------------------------------------------------
; Doctrine Cache Configuration
; ------------------------------------------------------------------------------

; Points to default cache instance to be used. Optional is only one cache is defined
resources.doctrine.cache.defaultCacheInstance = default

; Cache Instance configuration for "default" cache
;resources.doctrine.cache.instances.default.id = default
resources.doctrine.cache.instances.default.adapterClass = "Doctrine\Common\Cache\MemcacheCache"

resources.doctrine.cache.instances.default.namespace = "Application_"
resources.doctrine.cache.instances.default.options.servers.0.host = localhost
resources.doctrine.cache.instances.default.options.servers.0.port = 11211
;resources.doctrine.cache.instances.default.options.servers.0.persistent = true
;resources.doctrine.cache.instances.default.options.servers.0.weight = 1
;resources.doctrine.cache.instances.default.options.servers.0.timeout = 1
;resources.doctrine.cache.instances.default.options.servers.0.retryInterval = 15
;resources.doctrine.cache.instances.default.options.servers.0.status = true

; ------------------------------------------------------------------------------
; Doctrine DBAL Configuration
; ------------------------------------------------------------------------------

; Points to default connection to be used. Optional if only one connection is defined
resources.doctrine.dbal.defaultConnection = default

; DBAL Connection configuration for "default" connection
;resources.doctrine.dbal.connections.default.id = default
;resources.doctrine.dbal.connections.default.eventManagerClass = "Doctrine\Common\EventManager"
;resources.doctrine.dbal.connections.default.eventSubscribers[] = "DoctrineExtensions\Sluggable\SluggableSubscriber"
;resources.doctrine.dbal.connections.default.configurationClass = "Doctrine\DBAL\Configuration"
;resources.doctrine.dbal.connections.default.sqlLoggerClass = "Doctrine\DBAL\Logging\EchoSQLLogger"
;resources.doctrine.dbal.connections.default.types.my_type = "Application\DBAL\Type\MyType"

; Database configuration
;resources.doctrine.dbal.connections.default.parameters.wrapperClass = ""
resources.doctrine.dbal.connections.default.parameters.driver = "pdo_mysql"
resources.doctrine.dbal.connections.default.parameters.dbname = "fmm"
resources.doctrine.dbal.connections.default.parameters.host = "localhost"
resources.doctrine.dbal.connections.default.parameters.port = 3306
resources.doctrine.dbal.connections.default.parameters.charset = "utf8"
resources.doctrine.dbal.connections.default.parameters.user = "root"
resources.doctrine.dbal.connections.default.parameters.password = "password"
;resources.doctrine.dbal.connections.default.parameters.driverOptions.ATTR_USE_BUFFERED_QUERIES = true


; ------------------------------------------------------------------------------
; Doctrine ORM Configuration
; ------------------------------------------------------------------------------

; Points to default EntityManager to be used. Optional if only one EntityManager is defined
resources.doctrine.orm.defaultEntityManager = default

; EntityManager configuration for "default" manager
;resources.doctrine.orm.entityManagers.default.id = default
;resources.doctrine.orm.entityManagers.default.entityManagerClass = "Doctrine\ORM\EntityManager"
;resources.doctrine.orm.entityManagers.default.configurationClass = "Doctrine\ORM\Configuration"
;resources.doctrine.orm.entityManagers.default.entityNamespaces.app = "Application\Entity"
resources.doctrine.orm.entityManagers.default.connection = default
resources.doctrine.orm.entityManagers.default.proxy.autoGenerateClasses = false
resources.doctrine.orm.entityManagers.default.proxy.namespace = "Kdf\Entity\Proxy"
resources.doctrine.orm.entityManagers.default.proxy.dir = APPLICATION_PATH "/models/Kdf/Entity/Proxy"
;resources.doctrine.orm.entityManagers.default.metadataCache = default
;resources.doctrine.orm.entityManagers.default.queryCache = default
;resources.doctrine.orm.entityManagers.default.resultCache = default
;resources.doctrine.orm.entityManagers.default.DQLFunctions.numeric.PI = "DoctrineExtensions\ORM\Query\Functions\Numeric\PiFunction"
resources.doctrine.orm.entityManagers.default.metadataDrivers.annotationRegistry.annotationFiles[] = APPLICATION_PATH "/../library/Doctrine/ORM/Mapping/Driver/DoctrineAnnotations.php"
;resources.doctrine.orm.entityManagers.default.metadataDrivers.annotationRegistry.annotationNamespaces.0.namespace = "Gedmo"
;resources.doctrine.orm.entityManagers.default.metadataDrivers.annotationRegistry.annotationNamespaces.0.includePath = APPLICATION_PATH "/../library/vendor"
resources.doctrine.orm.entityManagers.default.metadataDrivers.drivers.0.adapterClass = "Doctrine\ORM\Mapping\Driver\AnnotationDriver"
resources.doctrine.orm.entityManagers.default.metadataDrivers.drivers.0.mappingNamespace = "Kdf\Entity"
resources.doctrine.orm.entityManagers.default.metadataDrivers.drivers.0.mappingDirs[] = APPLICATION_PATH "/models/Kdf/Entity"
resources.doctrine.orm.entityManagers.default.metadataDrivers.drivers.0.annotationReaderClass = "Doctrine\Common\Annotations\AnnotationReader"
resources.doctrine.orm.entityManagers.default.metadataDrivers.drivers.0.annotationReaderCache = default
;resources.doctrine.orm.entityManagers.default.metadataDrivers.drivers.0.annotationReaderNamespaces.App = "Application\DoctrineExtensions\ORM\Mapping"

; ------------------------------
; View and Lanout Configuration
; ------------------------------

resources.layout.layout = "layout"
resources.layout.layoutPath = APPLICATION_PATH "/layouts/scripts/"

resources.view.engines.php.class = "Ano_View_Engine_PhpEngine"
resources.view.engines.php.viewSuffix = "phtml"

resources.view.engines.twig.class = "Ano_ZFTwig_View_Engine_TwigEngine"
resources.view.engines.twig.isDefault = 1
resources.view.engines.twig.viewSuffix = "twig"
resources.view.engines.twig.options.charset = "utf-8"
resources.view.engines.twig.options.strict_variables = 0
resources.view.engines.twig.options.cache = APPLICATION_PATH "/../var/cache/twig"
resources.view.engines.twig.options.auto_escape = 1
resources.view.engines.twig.options.auto_reload = 1
resources.view.engines.twig.options.debug = 0
resources.view.engines.twig.options.trim_blocks = 1
resources.view.engines.twig.extensions.helper.class = "Ano_ZFTwig_Extension_HelperExtension"
resources.view.engines.twig.extensions.trans.class = "Ano_ZFTwig_Extension_TransExtension"
;;Twig Extension
resources.view.engines.twig.extensions.debug.class = "Twig_Extensions_Extension_Debug"
resources.view.engines.twig.extensions.number.class = "Twig_Extensions_Extension_Number"

[staging : production]


[testing : production]
phpSettings.display_startup_errors = 1
phpSettings.display_errors = 1


[development : production]
phpSettings.display_startup_errors = 1
phpSettings.display_errors = 1
resources.frontController.params.displayExceptions = 1

resources.doctrine.cache.instances.default.adapterClass = "Doctrine\Common\Cache\ArrayCache"
resources.doctrine.orm.entityManagers.default.proxy.autoGenerateClasses = true

resources.doctrine.dbal.connections.default.parameters.host = "localhost"
resources.doctrine.dbal.connections.default.parameters.dbname = "kdfdb"
resources.doctrine.dbal.connections.default.parameters.user = "kdf"
resources.doctrine.dbal.connections.default.parameters.password = "kdfpass"

resources.view.engines.twig.options.debug = 1
view raw gistfile1.cfg This Gist brought to you by GitHub.

次回からはDoctrine2の設定に戻りたいと思います。

Posted in 技術・開発ツール | Tagged , , | 1 Comment

Zend Framework1 + Doctrine2 + twigを組み合わせる(その4)

その3から続く)

Doctrine2との連携が確認できたところでひとまずDoctrineから離れてTwigとの連携を行うことにします。

Twigを公式サイトからDLして(2011/12/27現在最新版stableは1.4.0)Twig/をプロジェクトのlibrary/直下に持ってきます。

Zend Framework + Twigについてはいくつかの試みがネット上にありますが、今回は以下のライブラリを使うことにします。

https://github.com/benjamindulau/Ano_ZFTwig

※このライブラリはZend ApplicationによりTwigの設定を.iniファイルにまとめている点、および任意のviewヘルパーが使えることをきちんと明記している点が気に入ったので採用しました。

git clone https://github.com/benjamindulau/Ano_ZFTwig.git

で取得し、中のAno/をプロジェクトのlibrary/直下に持ってきます。

追加したライブラリをアプリケーションが読めるようにnamespaceを.iniファイルに追加します。

autoloaderNamespaces[] = "Twig_" 
autoloaderNamespaces[] = "Ano_"

pluginの登録をします。

pluginPaths.Ano_Application_Resource = APPLICATION_PATH "/../library/Ano/Application/Resource"

更にドキュメントに従って以下の設定を追加します。

resources.view.engines.php.class = "Ano_View_Engine_PhpEngine"
resources.view.engines.php.viewSuffix = "phtml"
 
resources.view.engines.twig.class = "Ano_ZFTwig_View_Engine_TwigEngine"
resources.view.engines.twig.isDefault = 1
resources.view.engines.twig.viewSuffix = "twig"    
resources.view.engines.twig.options.charset = "utf-8"
resources.view.engines.twig.options.strict_variables = 0
resources.view.engines.twig.options.cache = APPLICATION_PATH "/../var/cache/twig"
resources.view.engines.twig.options.auto_escape = 1
resources.view.engines.twig.options.auto_reload = 1
resources.view.engines.twig.options.debug = 0
resources.view.engines.twig.options.trim_blocks = 1
resources.view.engines.twig.extensions.helper.class = "Ano_ZFTwig_Extension_HelperExtension"
resources.view.engines.twig.extensions.trans.class = "Ano_ZFTwig_Extension_TransExtension"

※Twigのcacheを保存するディレクトリ(上記の設定では/path/to/project/var/cache/twig)をあらかじめプロジェクト内に作っておく必要があります。

さてここで、このライブラリを使ってTwigを使用する際にZend Layoutを使うかどうかの選択をしなければなりません。Zend_Layoutを使う場合にはTwigが持つ継承機能(extends)やblockが使えません。ドキュメントにはZend Layoutを使う場合/使わない場合それぞれの記述例が載っていますが、自分が試したところZend Layoutを使わずTwigの継承機能を使う場合はcacheが動作せず、ライブラリが提供しているappzfという便利なグローバル変数も使えないという不具合があります。(githubで作者に報告していますが今のところガン無視されていますw)cacheが使えないと描画のパフォーマンスが悪くなるのは明らかなので今回はZend Layoutを使った方法を採用することにします。

zfコマンドを実行し、

zf enable layout

以下を.iniファイルに追加します。

resources.layout.layout = "layout" 
resources.layout.layoutPath = APPLICATION_PATH "/layouts/scripts/"

layoutファイルはこんな感じ

application/layouts/scripts/layout.twig

<head>
    {{ headTitle() }}
    {% meta, {'http-equiv': 'Content-Type', 'content': 'text/html; charset=utf-8'} %}
    {% javascript 'js/jquery.js', {'mode': 'prepend'} %}
    {% stylesheet 'css/layout.css', {'mode': 'prepend'} %}
    <base href="{{ zf.serverUrl() }}/{{ zf.baseUrl() }}" />
    {{ metas() }}
    {{ javascripts() }}
    {{ stylesheets() }}
</head>
<body>
    {{ layoutBlock('content') }}
</body>

errorコントローラー用のviewが無いと怒られてしまうのでこんな内容で作ります。

application/views/scripts/error/error.twig

<h1>An error occurred</h1>
 
<h2>{{ error.code }}: {{ message }}</h2>
 
{% if exception %}
 
<h3>Exception information:</h3>
 
<p>
    <b>Message:</b> {{ exception.message }}
</p>
 
<h3>Stack trace:</h3>
<pre>{{ exception.getTraceAsString() }}</pre>
 
<h3>Request Parameters:</h3>
{% for key, val in request.getParams() %}
{{key}} => {{val}} {{', '}}
{% endfor %}
 
{% endif %}

index.phtmlをindex.twigとリネームして内容をtwigで書き換えます。
application/views/scripts/index/index.twig

<!DOCTYPE HTML>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
 
findOneBy():</br>
{{name}}
 
</br></br>
 
findAll():</br>
{% for user in all_user %}
{{user.getName()}}</br>
{% endfor %}
</br>
 
ユーザ定義: </br>
{{second_user_name}}
 
</body>
</html>

index.phpにアクセスして前回と同じ結果が表示されれば成功です。Zend_Viewを使った場合と比較してTwigを使えば非常にシンプルに記述できることが分かると思います。

プロジェクトの構造はこうなります。

kdf 2 Zend Framework1 + Doctrine2 + twigを組み合わせる(その4)

application.iniです。

; -----------------------------
; forked from https://github.com/guilhermeblanco/ZendFramework1-Doctrine2/blob/master/application/configs/application.ini
; -----------------------------

[production]

; --------------------------
; PHP Specific Configuration
; --------------------------
phpSettings.display_startup_errors = 0
phpSettings.display_errors = 0

includePaths.library = APPLICATION_PATH "/../library"
includePaths.models = APPLICATION_PATH "/models"

; ----------------------------------------
; Zend Framework Application Configuration
; ----------------------------------------
bootstrap.path = APPLICATION_PATH "/Bootstrap.php"
bootstrap.class = "Bootstrap"

pluginPaths.Bisna\Application\Resource\ = "Bisna/Application/Resource"
pluginPaths.Ano_Application_Resource = APPLICATION_PATH "/../library/Ano/Application/Resource"

autoloaderNamespaces[] = Bisna
autoloaderNamespaces[] = Symfony
autoloaderNamespaces[] = Doctrine
autoloaderNamespaces[] = Kdf\Entity
autoloaderNamespaces[] = "Twig_"
autoloaderNamespaces[] = "Ano_"

; ------------------------------
; Front Controller Configuration
; ------------------------------

resources.frontController.controllerDirectory = APPLICATION_PATH "/controllers"
resources.frontController.params.displayExceptions = 0


; ------------------------------------------------------------------------------
; Doctrine Class Loader Configuration
; ------------------------------------------------------------------------------

; ------------------------------------------------------------------------------
; Doctrine Cache Configuration
; ------------------------------------------------------------------------------

; Points to default cache instance to be used. Optional is only one cache is defined
resources.doctrine.cache.defaultCacheInstance = default

; Cache Instance configuration for "default" cache
;resources.doctrine.cache.instances.default.id = default
resources.doctrine.cache.instances.default.adapterClass = "Doctrine\Common\Cache\MemcacheCache"

resources.doctrine.cache.instances.default.namespace = "Application_"
resources.doctrine.cache.instances.default.options.servers.0.host = localhost
resources.doctrine.cache.instances.default.options.servers.0.port = 11211
;resources.doctrine.cache.instances.default.options.servers.0.persistent = true
;resources.doctrine.cache.instances.default.options.servers.0.weight = 1
;resources.doctrine.cache.instances.default.options.servers.0.timeout = 1
;resources.doctrine.cache.instances.default.options.servers.0.retryInterval = 15
;resources.doctrine.cache.instances.default.options.servers.0.status = true

; ------------------------------------------------------------------------------
; Doctrine DBAL Configuration
; ------------------------------------------------------------------------------

; Points to default connection to be used. Optional if only one connection is defined
resources.doctrine.dbal.defaultConnection = default

; DBAL Connection configuration for "default" connection
;resources.doctrine.dbal.connections.default.id = default
;resources.doctrine.dbal.connections.default.eventManagerClass = "Doctrine\Common\EventManager"
;resources.doctrine.dbal.connections.default.eventSubscribers[] = "DoctrineExtensions\Sluggable\SluggableSubscriber"
;resources.doctrine.dbal.connections.default.configurationClass = "Doctrine\DBAL\Configuration"
;resources.doctrine.dbal.connections.default.sqlLoggerClass = "Doctrine\DBAL\Logging\EchoSQLLogger"
;resources.doctrine.dbal.connections.default.types.my_type = "Application\DBAL\Type\MyType"

; Database configuration
;resources.doctrine.dbal.connections.default.parameters.wrapperClass = ""
resources.doctrine.dbal.connections.default.parameters.driver = "pdo_mysql"
resources.doctrine.dbal.connections.default.parameters.dbname = "fmm"
resources.doctrine.dbal.connections.default.parameters.host = "localhost"
resources.doctrine.dbal.connections.default.parameters.port = 3306
resources.doctrine.dbal.connections.default.parameters.charset = "utf8"
resources.doctrine.dbal.connections.default.parameters.user = "root"
resources.doctrine.dbal.connections.default.parameters.password = "password"
;resources.doctrine.dbal.connections.default.parameters.driverOptions.ATTR_USE_BUFFERED_QUERIES = true


; ------------------------------------------------------------------------------
; Doctrine ORM Configuration
; ------------------------------------------------------------------------------

; Points to default EntityManager to be used. Optional if only one EntityManager is defined
resources.doctrine.orm.defaultEntityManager = default

; EntityManager configuration for "default" manager
;resources.doctrine.orm.entityManagers.default.id = default
;resources.doctrine.orm.entityManagers.default.entityManagerClass = "Doctrine\ORM\EntityManager"
;resources.doctrine.orm.entityManagers.default.configurationClass = "Doctrine\ORM\Configuration"
;resources.doctrine.orm.entityManagers.default.entityNamespaces.app = "Application\Entity"
resources.doctrine.orm.entityManagers.default.connection = default
resources.doctrine.orm.entityManagers.default.proxy.autoGenerateClasses = false
resources.doctrine.orm.entityManagers.default.proxy.namespace = "Kdf\Entity\Proxy"
resources.doctrine.orm.entityManagers.default.proxy.dir = APPLICATION_PATH "/models/Kdf/Entity/Proxy"
;resources.doctrine.orm.entityManagers.default.metadataCache = default
;resources.doctrine.orm.entityManagers.default.queryCache = default
;resources.doctrine.orm.entityManagers.default.resultCache = default
;resources.doctrine.orm.entityManagers.default.DQLFunctions.numeric.PI = "DoctrineExtensions\ORM\Query\Functions\Numeric\PiFunction"
resources.doctrine.orm.entityManagers.default.metadataDrivers.annotationRegistry.annotationFiles[] = APPLICATION_PATH "/../library/Doctrine/ORM/Mapping/Driver/DoctrineAnnotations.php"
;resources.doctrine.orm.entityManagers.default.metadataDrivers.annotationRegistry.annotationNamespaces.0.namespace = "Gedmo"
;resources.doctrine.orm.entityManagers.default.metadataDrivers.annotationRegistry.annotationNamespaces.0.includePath = APPLICATION_PATH "/../library/vendor"
resources.doctrine.orm.entityManagers.default.metadataDrivers.drivers.0.adapterClass = "Doctrine\ORM\Mapping\Driver\AnnotationDriver"
resources.doctrine.orm.entityManagers.default.metadataDrivers.drivers.0.mappingNamespace = "Kdf\Entity"
resources.doctrine.orm.entityManagers.default.metadataDrivers.drivers.0.mappingDirs[] = APPLICATION_PATH "/models/Kdf/Entity"
resources.doctrine.orm.entityManagers.default.metadataDrivers.drivers.0.annotationReaderClass = "Doctrine\Common\Annotations\AnnotationReader"
resources.doctrine.orm.entityManagers.default.metadataDrivers.drivers.0.annotationReaderCache = default
;resources.doctrine.orm.entityManagers.default.metadataDrivers.drivers.0.annotationReaderNamespaces.App = "Application\DoctrineExtensions\ORM\Mapping"

; ------------------------------
; View and Lanout Configuration
; ------------------------------

resources.layout.layout = "layout"
resources.layout.layoutPath = APPLICATION_PATH "/layouts/scripts/"

resources.view.engines.php.class = "Ano_View_Engine_PhpEngine"
resources.view.engines.php.viewSuffix = "phtml"

resources.view.engines.twig.class = "Ano_ZFTwig_View_Engine_TwigEngine"
resources.view.engines.twig.isDefault = 1
resources.view.engines.twig.viewSuffix = "twig"
resources.view.engines.twig.options.charset = "utf-8"
resources.view.engines.twig.options.strict_variables = 0
resources.view.engines.twig.options.cache = APPLICATION_PATH "/../var/cache/twig"
resources.view.engines.twig.options.auto_escape = 1
resources.view.engines.twig.options.auto_reload = 1
resources.view.engines.twig.options.debug = 0
resources.view.engines.twig.options.trim_blocks = 1
resources.view.engines.twig.extensions.helper.class = "Ano_ZFTwig_Extension_HelperExtension"
resources.view.engines.twig.extensions.trans.class = "Ano_ZFTwig_Extension_TransExtension"


[staging : production]


[testing : production]
phpSettings.display_startup_errors = 1
phpSettings.display_errors = 1


[development : production]
phpSettings.display_startup_errors = 1
phpSettings.display_errors = 1
resources.frontController.params.displayExceptions = 1

resources.doctrine.cache.instances.default.adapterClass = "Doctrine\Common\Cache\ArrayCache"
resources.doctrine.orm.entityManagers.default.proxy.autoGenerateClasses = true

resources.doctrine.dbal.connections.default.parameters.host = "localhost"
resources.doctrine.dbal.connections.default.parameters.dbname = "kdfdb"
resources.doctrine.dbal.connections.default.parameters.user = "kdf"
resources.doctrine.dbal.connections.default.parameters.password = "kdfpass"
view raw gistfile1.cfg This Gist brought to you by GitHub.

(その5へ続く)

Posted in 技術・開発ツール | Tagged , | 1 Comment

Zend Framework1 + Doctrine2 + twigを組み合わせる(その3)

(その2から続く)

ではMVCから呼び出してみます。

application/controllers/IndexController.php

<?php
 
class IndexController extends Zend_Controller_Action
{
 
    public function init()
    {
        /* Initialize action controller here */
    }
 
    public function indexAction()
    {
 
        // EntityManagerの取得
        $container = Zend_Registry::get('doctrine');
        $em = $container->getEntityManager();
        // Repositoryの取得
        $repo = $em->getRepository('Kdf\Entity\User');
 
        // 組み込みメソッド(単数)
        $user = $repo->findOneBy(array('id'=>1));
        $this->view->name = $user->getName();
        // 組み込みメソッド(複数)
        $this->view->all_user = $repo->findAll();
        // ユーザ定義メソッド
        $second_user = $repo->secondUserName();
        $this->view->second_user_name = $second_user['name'];
 
    }
 
}

plugin(library/Bisna/Application/Resource/Doctrine.php)の中でZend_Registryに登録を行っているのでこれを呼び出してEntityManagerおよびRepositoryを取得します。取得したRepositoryに対してメソッドを発行して目的のデータを取得します。メソッドには組み込み済みのものとユーザー定義のものがあります。ユーザ定義のメソッドはRepositoryクラスに記述します。つまりこれがモデルの核心部分(=ビジネスロジック)になるわけです。(※これに加えてService層を作ることでより一層ビジネスロジックの抽象化を図ることも出来ますね。)

application/models/Kdf/Entity/Repository/UserRepository.php

<?php
 
namespace Kdf\Entity\Repository;
 
use Doctrine\ORM\EntityRepository;
 
/**
 * UserRepository
 *
 * This class was generated by the Doctrine ORM. Add your own custom
 * repository methods below.
 */
class UserRepository extends EntityRepository
{
    public function secondUserName()
    {
        $qb = $this->_em->createQueryBuilder();
        $qb->select('u.name')
            ->from('Kdf\Entity\User', 'u')
            ->where('u.name  = :name')
            ->setParameter('name', 'ふがふが');
 
        return $qb->getQuery()->getOneOrNullResult();
    }
}

Repositoryクラスはその2で行ったようにCLIツールでひな形が自動で作成されますのでこの中にメソッドを追加していきます。Repositoryクラスの中から $this->_em でEntityManagerにアクセスできます。EntityManagerを取得した後はQueryBuilderを使うかDQLを直接記述していくことになります。QueryBuilderを使う利点はIDEと組み合わせた場合にコード補完が効くことでしょうか。

application/views/scripts/index/index.phtml

<!DOCTYPE HTML>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
 
findOneBy():</br>
<?= $this->escape($this->name); ?></br></br>
 
findAll():</br>
    <?php foreach ($this->all_user as $key => $val): ?>
        <?= $this->escape($val->getName()); ?></br>
    <?php endforeach; ?>
</br>
 
ユーザ定義: </br>
    <?= $this->escape($this->second_user_name); ?></br>
 
</body>
</html>

viewの中ではこんな風に値を取得します。

出力結果:

http   kdf.localhost 8888  Zend Framework1 + Doctrine2 + twigを組み合わせる(その3)

まとめ

Doctrine2の要はEntityManagerです。これとZend Frameworkとの統合という面倒な部分はBisnaライブラリが行ってくれますので、使う側は楽にDoctrine2を使うことが出来ます。
(その4へつづく)

Posted in 技術・開発ツール | Tagged , | 1 Comment

Zend Framework1 + Doctrine2 + twigを組み合わせる(その2)

(その1から続く)

CLIが動くようになったのでDoctrineのコマンドラインツールが使えるようになりました。このツールは開発においてとても重要な役割を果たすことになります。

モデルのディレクトリ構成

プロジェクトのmodels/配下にDoctrineがモデルクラスを作成するようにします。Doctrine2ではEntity, Proxy, Repositoryという3つのクラス群が必要になります。(これらが何を意味するのか、そしてなぜ必要なのかについては解説の範囲外なので、Doctrine2が標準のORMとして使われているsymfonyな人たちのblogを見てみましょう。また公式サイトのhttp://docs.symfony.gr.jp/symfony2/book/doctrine.html に概略の説明があります。)

さてこれら3つのレイアウトですが、今回はこのように作ることにします。

application Zend Framework1 + Doctrine2 + twigを組み合わせる(その2)

この構造に合わせてiniファイルを設定していきます。

まずDoctrineがこの構造を読めるようにプロジェクトにpathとnamespaceを追加します。

...
includePaths.models = APPLICATION_PATH "/models"
...
autoloaderNamespaces[] = Kdf\Entity

生成されるProxyのnamespaceおよびディレクトリを指定してあげる必要があります。

resources.doctrine.orm.entityManagers.default.proxy.namespace = "Kdf\Entity\Proxy"
...
resources.doctrine.orm.entityManagers.default.proxy.dir = APPLICATION_PATH "/models/Kdf/Entity/Proxy"

metadata driverのnamespaceおよびマッピングディレクトリも指定します。

resources.doctrine.orm.entityManagers.default.metadataDrivers.drivers.0.mappingNamespace = "Kdf\Entity"
resources.doctrine.orm.entityManagers.default.metadataDrivers.drivers.0.mappingDirs[] = APPLICATION_PATH "/models/Kdf/Entity"

Proxyの自動生成パラメータを開発環境ではONにしておくとProxyが自動で作成されるので開発が楽になります。しかしパフォーマンス的には悪影響を及ぼすので本番環境ではOFFにします。

[production]
 
...
 
resources.doctrine.orm.entityManagers.default.proxy.autoGenerateClasses = false
 
[development : production]
 
...
 
resources.doctrine.orm.entityManagers.default.proxy.autoGenerateClasses = true

開発環境用の接続DB情報をdevelopmentセクションに設定します。(※これらを使用してあらかじめMySQLにデータベースおよびユーザを作成して置く必要があります。)

[development : production]
 
...
 
resources.doctrine.dbal.connections.default.parameters.host = "localhost"
 
resources.doctrine.dbal.connections.default.parameters.dbname = "kdfdb"
 
resources.doctrine.dbal.connections.default.parameters.user = "user"
 
resources.doctrine.dbal.connections.default.parameters.password = "pass"

iniファイルの設定が出来たので、Entityを作ってみます。

application/models/Kdf/Entity/User.php

<?php
 
namespace Kdf\Entity;
use Doctrine\ORM\Mapping as ORM;
 
/**
 * User
 *
 * @Table(name="USER")
 * @Entity(repositoryClass="Kdf\Entity\Repository\UserRepository")
 */
class User
{
    /**
     * @var integer $id
     *
     * @ORM\Column(name="ID", type="integer")
     * @Id
     * @GeneratedValue(strategy="IDENTITY")
     */
    private $id;
 
    /**
     * @var string $userName
     *
     * @ORM\Column(name="NAME", type="string", length=50)
     */
    private $name;
 
    /**
     * @var string $password
     *
     * @ORM\Column(name="PASSWORD", type="string", length=20)
     */
    private $password;
 
    /**
     * @var datetime $registerDate
     *
     * @ORM\Column(name="REGISTER_DATE", type="datetime")
     */
    private $registerDate;
 
    /**
     * @var datetime $updateDate
     *
     * @ORM\Column(name="UPDATE_DATE", type="datetime")
     */
    private $updateDate;
}

準備が出来たのでDoctrineコマンドを使ってみます。

スキーマを生成します。


php bin/doctrine.php orm:schema-tool:create

ATTENTION: This operation should not be executed in a production environment. 

Creating database schema...
Database schema created successfully! 


php bin/doctrine.php orm:generate-entities application/models

このコマンドを実行するとgetter, setterが生成されます。

Processing entity "Kdf\Entity\User" 

Entity classes generated to "/Path/to/project/application/models"


php bin/doctrine.php orm:generate-proxies

proxyを手動で生成してみます。(生成先のパスは.iniファイルで指定しているので不要です。)

Processing entity "Kdf\Entity\User" 

Proxy classes generated to "/Path/to/project/application/models/Kdf/Entity/Proxy" 


php bin/doctrine.php orm:generate-repositories application/models

repositoryを生成します。

Processing repository "Kdf\Entity\Repository\UserRepository" 

Repository classes generated to "/Path/to/project/application/models" 

まとめ

Doctrineコマンドを使ってEntity, Proxy, Repositoryが生成できるようになりました。今回設定した結果のiniファイルは以下です。

; -----------------------------
; forked from https://github.com/guilhermeblanco/ZendFramework1-Doctrine2/blob/master/application/configs/application.ini
; -----------------------------

[production]

; --------------------------
; PHP Specific Configuration
; --------------------------
phpSettings.display_startup_errors = 0
phpSettings.display_errors = 0

includePaths.library = APPLICATION_PATH "/../library"
includePaths.models = APPLICATION_PATH "/models"

; ----------------------------------------
; Zend Framework Application Configuration
; ----------------------------------------
bootstrap.path = APPLICATION_PATH "/Bootstrap.php"
bootstrap.class = "Bootstrap"

pluginPaths.Bisna\Application\Resource\ = "Bisna/Application/Resource"

autoloaderNamespaces[] = Bisna
autoloaderNamespaces[] = Symfony
autoloaderNamespaces[] = Doctrine
autoloaderNamespaces[] = Kdf\Entity


; ------------------------------
; Front Controller Configuration
; ------------------------------

resources.frontController.controllerDirectory = APPLICATION_PATH "/controllers"
resources.frontController.params.displayExceptions = 0


; ------------------------------------------------------------------------------
; Doctrine Class Loader Configuration
; ------------------------------------------------------------------------------

; ------------------------------------------------------------------------------
; Doctrine Cache Configuration
; ------------------------------------------------------------------------------

; Points to default cache instance to be used. Optional is only one cache is defined
resources.doctrine.cache.defaultCacheInstance = default

; Cache Instance configuration for "default" cache
;resources.doctrine.cache.instances.default.id = default
resources.doctrine.cache.instances.default.adapterClass = "Doctrine\Common\Cache\MemcacheCache"

resources.doctrine.cache.instances.default.namespace = "Application_"
resources.doctrine.cache.instances.default.options.servers.0.host = localhost
resources.doctrine.cache.instances.default.options.servers.0.port = 11211
;resources.doctrine.cache.instances.default.options.servers.0.persistent = true
;resources.doctrine.cache.instances.default.options.servers.0.weight = 1
;resources.doctrine.cache.instances.default.options.servers.0.timeout = 1
;resources.doctrine.cache.instances.default.options.servers.0.retryInterval = 15
;resources.doctrine.cache.instances.default.options.servers.0.status = true

; ------------------------------------------------------------------------------
; Doctrine DBAL Configuration
; ------------------------------------------------------------------------------

; Points to default connection to be used. Optional if only one connection is defined
resources.doctrine.dbal.defaultConnection = default

; DBAL Connection configuration for "default" connection
;resources.doctrine.dbal.connections.default.id = default
;resources.doctrine.dbal.connections.default.eventManagerClass = "Doctrine\Common\EventManager"
;resources.doctrine.dbal.connections.default.eventSubscribers[] = "DoctrineExtensions\Sluggable\SluggableSubscriber"
;resources.doctrine.dbal.connections.default.configurationClass = "Doctrine\DBAL\Configuration"
;resources.doctrine.dbal.connections.default.sqlLoggerClass = "Doctrine\DBAL\Logging\EchoSQLLogger"
;resources.doctrine.dbal.connections.default.types.my_type = "Application\DBAL\Type\MyType"

; Database configuration
;resources.doctrine.dbal.connections.default.parameters.wrapperClass = ""
resources.doctrine.dbal.connections.default.parameters.driver = "pdo_mysql"
resources.doctrine.dbal.connections.default.parameters.dbname = "fmm"
resources.doctrine.dbal.connections.default.parameters.host = "localhost"
resources.doctrine.dbal.connections.default.parameters.port = 3306
resources.doctrine.dbal.connections.default.parameters.charset = "utf8"
resources.doctrine.dbal.connections.default.parameters.user = "root"
resources.doctrine.dbal.connections.default.parameters.password = "password"
;resources.doctrine.dbal.connections.default.parameters.driverOptions.ATTR_USE_BUFFERED_QUERIES = true


; ------------------------------------------------------------------------------
; Doctrine ORM Configuration
; ------------------------------------------------------------------------------

; Points to default EntityManager to be used. Optional if only one EntityManager is defined
resources.doctrine.orm.defaultEntityManager = default

; EntityManager configuration for "default" manager
;resources.doctrine.orm.entityManagers.default.id = default
;resources.doctrine.orm.entityManagers.default.entityManagerClass = "Doctrine\ORM\EntityManager"
;resources.doctrine.orm.entityManagers.default.configurationClass = "Doctrine\ORM\Configuration"
;resources.doctrine.orm.entityManagers.default.entityNamespaces.app = "Application\Entity"
resources.doctrine.orm.entityManagers.default.connection = default
resources.doctrine.orm.entityManagers.default.proxy.autoGenerateClasses = false
resources.doctrine.orm.entityManagers.default.proxy.namespace = "Kdf\Entity\Proxy"
resources.doctrine.orm.entityManagers.default.proxy.dir = APPLICATION_PATH "/models/Kdf/Entity/Proxy"
;resources.doctrine.orm.entityManagers.default.metadataCache = default
;resources.doctrine.orm.entityManagers.default.queryCache = default
;resources.doctrine.orm.entityManagers.default.resultCache = default
;resources.doctrine.orm.entityManagers.default.DQLFunctions.numeric.PI = "DoctrineExtensions\ORM\Query\Functions\Numeric\PiFunction"
resources.doctrine.orm.entityManagers.default.metadataDrivers.annotationRegistry.annotationFiles[] = APPLICATION_PATH "/../library/Doctrine/ORM/Mapping/Driver/DoctrineAnnotations.php"
;resources.doctrine.orm.entityManagers.default.metadataDrivers.annotationRegistry.annotationNamespaces.0.namespace = "Gedmo"
;resources.doctrine.orm.entityManagers.default.metadataDrivers.annotationRegistry.annotationNamespaces.0.includePath = APPLICATION_PATH "/../library/vendor"
resources.doctrine.orm.entityManagers.default.metadataDrivers.drivers.0.adapterClass = "Doctrine\ORM\Mapping\Driver\AnnotationDriver"
resources.doctrine.orm.entityManagers.default.metadataDrivers.drivers.0.mappingNamespace = "Kdf\Entity"
resources.doctrine.orm.entityManagers.default.metadataDrivers.drivers.0.mappingDirs[] = APPLICATION_PATH "/models/Kdf/Entity"
resources.doctrine.orm.entityManagers.default.metadataDrivers.drivers.0.annotationReaderClass = "Doctrine\Common\Annotations\AnnotationReader"
resources.doctrine.orm.entityManagers.default.metadataDrivers.drivers.0.annotationReaderCache = default
;resources.doctrine.orm.entityManagers.default.metadataDrivers.drivers.0.annotationReaderNamespaces.App = "Application\DoctrineExtensions\ORM\Mapping"


[staging : production]


[testing : production]
phpSettings.display_startup_errors = 1
phpSettings.display_errors = 1


[development : production]
phpSettings.display_startup_errors = 1
phpSettings.display_errors = 1
resources.frontController.params.displayExceptions = 1

resources.doctrine.cache.instances.default.adapterClass = "Doctrine\Common\Cache\ArrayCache"
resources.doctrine.orm.entityManagers.default.proxy.autoGenerateClasses = true

resources.doctrine.dbal.connections.default.parameters.host = "localhost"
resources.doctrine.dbal.connections.default.parameters.dbname = "kdfdb"
resources.doctrine.dbal.connections.default.parameters.user = "kdf"
resources.doctrine.dbal.connections.default.parameters.password = "kdfpass"
view raw gistfile1.cfg This Gist brought to you by GitHub.

その3へ続く

Posted in 技術・開発ツール | Tagged , | 1 Comment

Zend Framework1 + Doctrine2 + twigを組み合わせる(その1)

最近Zend Framework1.11をベースにORMにDoctrine2、viewにtwigという組み合わせを試してみました。

書く予定のネタ

  • Zend FrameworkへのDoctrine2およびCLIツールの組み込み
  • Doctrine2 Extensionの組み込み
  • Doctrine2へのビヘイビア(Timestampable)の組み込み
  • Zend Frameworkへのtwigの組み込み
  • twigのデバッグ方法
  • twigへのExtensionの組み込み

※長いので今回はZend FrameworkとDoctrine2の組み込みおよびDoctrine CLIの動作確認までとします。

ライブラリのDLと配置

Zend Framework

Zend Framework 1.11.11を使用します。このエントリを読んでいる人はすでにZend Frameworkを使っているはずなので設定方法は省略します。

zf create project project_name

で標準的な構成のプロジェクトを作ります。

話をシンプルにするためにサードパーティライブラリも自作ライブラリもフラットにlibrary/以下に置くことにします。

※本当は外部ライブラリはvendor/などのディレクトリを切ってその下に置くべきなんでしょうね。symfonyやCakePHPはそのあたりのルールがきちんとしていますがZend Frameworkは自由に置けるので(以下略

Doctrine2

http://www.doctrine-project.org/projects/orm/download

からDoctrine2 ORMパッケージをDLします。(2011/12/16現在最新は2.1.4)

解凍したらDoctrine/配下にある4つのディレクトリ(Common, DBAL, ORM, Symfony)をプロジェクトのlibrary/の下にこのように配置します。

kdf 1 262x300 Zend Framework1 + Doctrine2 + twigを組み合わせる(その1)

Zend FrameworkとDoctrine2を統合するライブラリ(Bisna)

Zend Framework1とDoctrine2の結合についてはいくつかのソリューションがあるのですが、自分が探した中で最もエレガントな統合を行っているのは以下でした。

https://github.com/guilhermeblanco/ZendFramework1-Doctrine2

※詳しいドキュメント(英語)は以下にあります。

http://www.kurttest.com/zfa/bisna.html

ライブラリを

git clone https://github.com/guilhermeblanco/ZendFramework1-Doctrine2.git zfdooctrine

で持ってきたらlibrary/Bisnaをプロジェクトのlibrary/直下に移動します。ライブラリ内のapplication.iniでプロジェクトのapplication.ini上書きしてください。さらにbin/doctrine.phpをプロジェクトに取り込みます。(上図を参考にしてください)

※ライブラリ内のapplication/Bootstrap.phpは今回不要です。_initAutoloaderNamespacesというメソッドは、Doctrine2をpear経由でインストールした場合に名前空間のマッピングをするためのものです。

設定

application.iniの修正

名前空間の追加

次の2行を追加します

autoloaderNamespaces[] = Symfony
autoloaderNamespaces[] = Doctrine

“Doctrine Class Loader Configuration”の削除

これは、Doctrine2取得の際にgithubからのclone & git submoduleという方法で取得した際のディレクトリ構造とプロジェクトの名前空間のマッピングを行うための設定です。今回Doctrine2はpackageとして取得していますのでこの部分は不要です。

cacheの設定

resources.doctrine.cache.instances.default.adapterClass = "Doctrine\Common\Cache\MemcacheCache"

となっていますが、開発環境のPHPにmemcachedモジュールが入っていない場合はDoctrine CLIでエラーが出てしまいます。自分でmemcachedを入れるなり他のcacheモジュールを使うなりしましょう。MAMPを使用している場合はAPCがすでに組み込まれているので

resources.doctrine.cache.instances.default.adapterClass = "Doctrine\Common\Cache\ApcCache"

としておけばよいでしょう。

なお、開発中は最もベーシックなArrayCacheを使うと都合が良いのでdevelopmentセクションに

resources.doctrine.cache.instances.default.adapterClass = "Doctrine\Common\Cache\ArrayCache"

を追加します。

Doctrine ORM Configurationセクションのパス修正

Doctrineのパス指定をプロジェクトの構成に合わせます。

resources.doctrine.orm.entityManagers.default.metadataDrivers.annotationRegistry.annotationFiles[] = APPLICATION_PATH "/../library/Doctrine/ORM/Mapping/Driver/DoctrineAnnotations.php"

コマンドラインツールの設定

CLIを使わなくてもDoctrineは動作しますが開発作業には実質不可欠なツールです。Bisnaが提供しているbin/doctrine.phpをプロジェクトにコピーするだけです。ただしCLIを使うのはdevelopment環境に限定したいので

defined('APPLICATION_ENV')
|| define('APPLICATION_ENV', (getenv('APPLICATION_ENV') ? getenv('APPLICATION_ENV') : 'production'));

defined('APPLICATION_ENV')
|| define('APPLICATION_ENV', 'development');

とします。

設定の確認

コマンドラインでプロジェクトのルートに移動して

php bin/doctrine.php

を実行します。

こんな感じでプロンプトが出力されればOKです。

resize 300x159 Zend Framework1 + Doctrine2 + twigを組み合わせる(その1)

今回設定した結果のapplication.iniファイルは以下です。

; -----------------------------
; forked from https://github.com/guilhermeblanco/ZendFramework1-Doctrine2/blob/master/application/configs/application.ini
; -----------------------------

[production]

; --------------------------
; PHP Specific Configuration
; --------------------------
phpSettings.display_startup_errors = 0
phpSettings.display_errors = 0

includePaths.library = APPLICATION_PATH "/../library"


; ----------------------------------------
; Zend Framework Application Configuration
; ----------------------------------------
bootstrap.path = APPLICATION_PATH "/Bootstrap.php"
bootstrap.class = "Bootstrap"

pluginPaths.Bisna\Application\Resource\ = "Bisna/Application/Resource"

autoloaderNamespaces[] = Bisna
autoloaderNamespaces[] = Symfony
autoloaderNamespaces[] = Doctrine
autoloaderNamespaces[] = Application\Entity

appnamespace = "Application"


; ------------------------------
; Front Controller Configuration
; ------------------------------

resources.frontController.controllerDirectory = APPLICATION_PATH "/controllers"
resources.frontController.params.displayExceptions = 0


; ------------------------------------------------------------------------------
; Doctrine Class Loader Configuration
; ------------------------------------------------------------------------------

; resources.doctrine.classLoader.loaderClass = "Doctrine\Common\ClassLoader"
; resources.doctrine.classLoader.loaderFile = APPLICATION_PATH "/../library/vendor/Doctrine/lib/vendor/doctrine-common/lib/Doctrine/Common/ClassLoader.php"
;
; resources.doctrine.classLoader.loaders.doctrine_common.namespace = "Doctrine\Common"
; resources.doctrine.classLoader.loaders.doctrine_common.includePath = APPLICATION_PATH "/../library/vendor/Doctrine/lib/vendor/doctrine-common/lib"
;
; resources.doctrine.classLoader.loaders.doctrine_dbal.namespace = "Doctrine\DBAL"
; resources.doctrine.classLoader.loaders.doctrine_dbal.includePath = APPLICATION_PATH "/../library/vendor/Doctrine/lib/vendor/doctrine-dbal/lib"
;
; resources.doctrine.classLoader.loaders.doctrine_orm.namespace = "Doctrine\ORM"
; resources.doctrine.classLoader.loaders.doctrine_orm.includePath = APPLICATION_PATH "/../library/vendor/Doctrine/lib"
;
; resources.doctrine.classLoader.loaders.symfony_console.namespace = "Symfony\Component\Console"
; resources.doctrine.classLoader.loaders.symfony_console.includePath = APPLICATION_PATH "/../library/vendor/Doctrine/lib/vendor"
;
; resources.doctrine.classLoader.loaders.symfony_yaml.namespace = "Symfony\Component\Yaml"
; resources.doctrine.classLoader.loaders.symfony_yaml.includePath = APPLICATION_PATH "/../library/vendor/Doctrine/lib/vendor"

; ------------------------------------------------------------------------------
; Doctrine Cache Configuration
; ------------------------------------------------------------------------------

; Points to default cache instance to be used. Optional is only one cache is defined
resources.doctrine.cache.defaultCacheInstance = default

; Cache Instance configuration for "default" cache
;resources.doctrine.cache.instances.default.id = default
resources.doctrine.cache.instances.default.adapterClass = "Doctrine\Common\Cache\MemcacheCache"

resources.doctrine.cache.instances.default.namespace = "Application_"
resources.doctrine.cache.instances.default.options.servers.0.host = localhost
resources.doctrine.cache.instances.default.options.servers.0.port = 11211
;resources.doctrine.cache.instances.default.options.servers.0.persistent = true
;resources.doctrine.cache.instances.default.options.servers.0.weight = 1
;resources.doctrine.cache.instances.default.options.servers.0.timeout = 1
;resources.doctrine.cache.instances.default.options.servers.0.retryInterval = 15
;resources.doctrine.cache.instances.default.options.servers.0.status = true

; ------------------------------------------------------------------------------
; Doctrine DBAL Configuration
; ------------------------------------------------------------------------------

; Points to default connection to be used. Optional if only one connection is defined
resources.doctrine.dbal.defaultConnection = default

; DBAL Connection configuration for "default" connection
;resources.doctrine.dbal.connections.default.id = default
;resources.doctrine.dbal.connections.default.eventManagerClass = "Doctrine\Common\EventManager"
;resources.doctrine.dbal.connections.default.eventSubscribers[] = "DoctrineExtensions\Sluggable\SluggableSubscriber"
;resources.doctrine.dbal.connections.default.configurationClass = "Doctrine\DBAL\Configuration"
;resources.doctrine.dbal.connections.default.sqlLoggerClass = "Doctrine\DBAL\Logging\EchoSQLLogger"
;resources.doctrine.dbal.connections.default.types.my_type = "Application\DBAL\Type\MyType"

; Database configuration
;resources.doctrine.dbal.connections.default.parameters.wrapperClass = ""
resources.doctrine.dbal.connections.default.parameters.driver = "pdo_mysql"
resources.doctrine.dbal.connections.default.parameters.dbname = "fmm"
resources.doctrine.dbal.connections.default.parameters.host = "localhost"
resources.doctrine.dbal.connections.default.parameters.port = 3306
resources.doctrine.dbal.connections.default.parameters.user = "root"
resources.doctrine.dbal.connections.default.parameters.password = "password"
;resources.doctrine.dbal.connections.default.parameters.driverOptions.ATTR_USE_BUFFERED_QUERIES = true


; ------------------------------------------------------------------------------
; Doctrine ORM Configuration
; ------------------------------------------------------------------------------

; Points to default EntityManager to be used. Optional if only one EntityManager is defined
resources.doctrine.orm.defaultEntityManager = default

; EntityManager configuration for "default" manager
;resources.doctrine.orm.entityManagers.default.id = default
;resources.doctrine.orm.entityManagers.default.entityManagerClass = "Doctrine\ORM\EntityManager"
;resources.doctrine.orm.entityManagers.default.configurationClass = "Doctrine\ORM\Configuration"
;resources.doctrine.orm.entityManagers.default.entityNamespaces.app = "Application\Entity"
resources.doctrine.orm.entityManagers.default.connection = default
resources.doctrine.orm.entityManagers.default.proxy.autoGenerateClasses = true
resources.doctrine.orm.entityManagers.default.proxy.namespace = "Application\Entity\Proxy"
resources.doctrine.orm.entityManagers.default.proxy.dir = APPLICATION_PATH "/../library/Application/Entity/Proxy"
;resources.doctrine.orm.entityManagers.default.metadataCache = default
;resources.doctrine.orm.entityManagers.default.queryCache = default
;resources.doctrine.orm.entityManagers.default.resultCache = default
;resources.doctrine.orm.entityManagers.default.DQLFunctions.numeric.PI = "DoctrineExtensions\ORM\Query\Functions\Numeric\PiFunction"
resources.doctrine.orm.entityManagers.default.metadataDrivers.annotationRegistry.annotationFiles[] = APPLICATION_PATH "/../library/Doctrine/ORM/Mapping/Driver/DoctrineAnnotations.php"
;resources.doctrine.orm.entityManagers.default.metadataDrivers.annotationRegistry.annotationNamespaces.0.namespace = "Gedmo"
;resources.doctrine.orm.entityManagers.default.metadataDrivers.annotationRegistry.annotationNamespaces.0.includePath = APPLICATION_PATH "/../library/vendor"
resources.doctrine.orm.entityManagers.default.metadataDrivers.drivers.0.adapterClass = "Doctrine\ORM\Mapping\Driver\AnnotationDriver"
resources.doctrine.orm.entityManagers.default.metadataDrivers.drivers.0.mappingNamespace = "Application\Entity"
resources.doctrine.orm.entityManagers.default.metadataDrivers.drivers.0.mappingDirs[] = APPLICATION_PATH "/../library/Application/Entity"
resources.doctrine.orm.entityManagers.default.metadataDrivers.drivers.0.annotationReaderClass = "Doctrine\Common\Annotations\AnnotationReader"
resources.doctrine.orm.entityManagers.default.metadataDrivers.drivers.0.annotationReaderCache = default
;resources.doctrine.orm.entityManagers.default.metadataDrivers.drivers.0.annotationReaderNamespaces.App = "Application\DoctrineExtensions\ORM\Mapping"


[staging : production]


[testing : production]
phpSettings.display_startup_errors = 1
phpSettings.display_errors = 1


[development : production]
phpSettings.display_startup_errors = 1
phpSettings.display_errors = 1
resources.frontController.params.displayExceptions = 1
resources.doctrine.cache.instances.default.adapterClass = "Doctrine\Common\Cache\ArrayCache"

view raw gistfile1.cfg This Gist brought to you by GitHub.

(その2へ続く)

Posted in 技術・開発ツール | Tagged , | 1 Comment

WebStorm/PHPStormでMercurialプラグインを扱う

※ 2011/12/21 追記:  はてなブックマークのコメントで教えてもらいましたが、~/.MacOSX/environment.plist を編集してHGENCODINGをutf8としてセットしログインし直すだけでOKでした。(PHPStorm 3.0 / Mac OSX  10.7.2で確認)以下の作業は不要です。

JetBrains社のPHP統合開発環境であるPHPStormは連携するVCSとして標準でmercurialが使えますが、Mac上で使用する場合標準の設定では日本語のコミットメッセージは文字化けします。これの回避方法がわかったので書きます。

Version Control 300x134 WebStorm/PHPStormでMercurialプラグインを扱う

環境

  • Mac OSX 10.6.8
  • PHPStorm 2.1.2
  • 文字コード設定はutf-8

[注]
※1 WebStormはPHPStormのサブセットなので、本エントリの内容はWebStormでもそのまま適用されるはずです。また他のJetBrains製IDEもおそらく同じ方法が使えると思います。
※2 他のプラットフォーム・環境の方は自分の環境に置き換えて読んでください。

前提

既存のmercurialがそもそも正しく日本語コミットメッセージを扱えていることが必要です。つまりコマンドラインからhgコマンドを使って正しく日本語のコミットメッセージ正しく扱える必要があります。これについては

.bashrcなどに

export HGENCODING=utf-8

と記述し環境変数HGENCODINGを設定すれば大抵の場合OKのはずです。

設定

ポイントは

  1. HGENCODINGの値をPHPStormに認識させること。
  2. PHPStorm起動時にJVMの文字エンコーディングをutf-8にすること。

の2点です。

最初のポイントですが、実はPHPStormの設定を見ると”Settings > Version Control > VCSs > Mercurial”に”Run as “bash -c  <path to hg>”というオプションがあり、

Settings 300x169 WebStorm/PHPStormでMercurialプラグインを扱う

 

ここにチェックを入れれば.bashrcのHGENCODINGの値を取り込んでくれると期待して試したのですが、現行のPHPStormの場合文字化けが解消したように見えるもののペインが真っ白になったり全体の動作が遅くなるなど挙動不審になり使い物にならないのでこのオプションは使いません。その代わりにここ(IntelliJ+mercurialで日本語コミットログ | Ken’s evitation)にあるようにアプリをターミナルから起動するという方法を使います。ターミナルから

open /Applications/PhpStorm\ 2.1.2.app/

と実行して起動します。これで既存のコミットメッセージは文字化けせずに表示出来るようになる…のですが、新規のコミットメッセージに日本語が含まれていると怒られてコミットが失敗します。

trunk  codes chapter3 trunk ... application modules storefront controllers CartController.php JetBrains PhpStorm 2.1.2 1 300x176 WebStorm/PHPStormでMercurialプラグインを扱う

JVM起動オプションの設定

そこで第2のポイントの設定を行います。NetBeansの設定編でも書きましたが、OSX10.6のJDKはデフォルトがShift_JISなのでJVMを起動する際オプションとして明示的に文字コードをutf-8にする必要があります。OSX版のPHPStormの場合その設定は

/Applications/PhpStorm 2.1.2.app/Contents

の中にあるInfo.plistを編集して行います。(編集前に念のためオリジナルのplistはリネームするなどしてバックアップしておきましょう。)

Info.plistを開いて下線部で示した部分を追加します。このとき既存のオプションとの間に半角スペースが必要です。

Info.plist  300x53 WebStorm/PHPStormでMercurialプラグインを扱う

※OSX以外のプラットフォームを使用している場合はアプリケーション内のどこかに起動オプションを記述している.confファイルがあるはずのでそれを編集します。追加するオプションがNetBeansの場合とは微妙に違うので注意しましょう。

Info.plistの編集が終わったらターミナルから

open /Applications/PhpStorm\ 2.1.2.app/

としてPHPStormを起動します。以上で日本語のコミットメッセージの読み書きが正しく扱えるようになります。

Posted in 技術・開発ツール | Tagged , | Leave a comment

jQuery初心者がセレクタの記述でつまずきやすいことをまとめた

最近のweb開発には欠かせないjQueryですが、まずはセレクタの使い方を覚えないと話になりません。ところがこの記述ルールが初心者にとって非常に紛らわしく、しかもリファレンスを見てすぐにわかるものとは限りません。自分が学び始めた頃に悩んだ(そして今でもときどき間違えそうになる)まぎらわしいセレクタの記述方法についてまとめます。

$(".classA, .classB")     //... (1)
$(".classA .classB")      //... (2)
$(".classA + .classB")    //... (3)
$(".classA.classB")       //... (4)
$(".classA", ".classB")   //... (5)
$(".classA" + ".classB")  //... (6)
$(".classA" + " .classB") //... (7)

さてこれらのセレクタの意味がすぐにわかりますか?

説明

(1), (2), (3)

どのリファレンスでもわかりやすい場所に書いてあることなので簡単です。

(1)はOR条件でセレクタを複数選択します。.classAまたは.classBに一致する要素を選択します。(2)は子孫セレクタです。”.classA”と”.classB”の間には半角スペースが入ります。(3)は隣接選択です。リファレンスをどうぞ。

(4)

.classAと.classBの両方をもつ要素の選択です。(AND条件)。そしてこれは完全一致ではなくて部分一致であることに注意してください。つまり例えば次のようなブロックがあった場合に

<div class="classA classB">最初のdiv</div>
<div class="classA classB classC">次のdiv</div>

$(“.classA.classB”)というセレクタが指定されるとこれらのdiv要素を二つとも選択します。二番目のdiv要素にはクラスが3つ指定されていますがこれも選択対象になります。このパターン、実際には

$("div.classA.classB")

といった形でよく使われています。これはclassAとclassBというクラスを二つとも持つdiv要素という意味になります。

この記述法はとても重要で頻繁に使われるにもかかわらず、なぜかちゃんと説明しているサイトがあまり存在しません。自分が探した限りではjQuery本家の公式英語リファレンスだけでした。

http://api.jquery.com/class-selector/

(5)

第一引数はセレクタで第二引数はセレクタのコンテクストです。指定されたコンテクストの中でセレクタに合致するものが選択されます。(1)と似ているのでこんがらがりやすいです。

(6)と(7)

こういう記述も可能です。ここで使われている”+”はjQueryのセレクタとは関係なくてJavaScriptの文字連結演算子です。よって(6)は(4)とまったく同じであり、(7)は二つのクラスセレクタの間に半角スペースが入るので(2)と同じになります。非常にトリッキーなので現場ではこういう記述は避けるべきでしょう。

Posted in 技術・開発ツール | Tagged | Leave a comment

Webプログラマー/デザイナーは英語「を」学ぶのではなく英語「で」学ぼう

Web技術者の人で英語を身につけたいと思っている人は多いようです。でもわざわざ英語を勉強するだけのために本を読んだりビデオを見る時間は正直あまりないと思います。ここは発想を転換して普段の勉強・情報収集そのものを英語で行ってしまうのはどうでしょうか。

すでに基本的な文法・語彙を身につけた人であれば、その先の勉強は無味乾燥な英語教材ではなく実際に仕事に役に立つ内容で行う方が身につきやすいはずです。技術と英語の勉強が一度にできて時間的に一石二鳥なだけでなく、日本語の情報が少ない最新の話題にも触れることができるといううれしいおまけもあります。

自分が実際にこの1年ほど試して個人的に使えると思った教材・テクニックを挙げてみます。

本・電子書籍

books Webプログラマー/デザイナーは英語「を」学ぶのではなく英語「で」学ぼうiTunes Webプログラマー/デザイナーは英語「を」学ぶのではなく英語「で」学ぼう

オライリーは言うまでもありませんが他の3つもいずれも欧米の著名技術系出版社でありebookが豊富で上記サイトから直接購入できます。オライリー以外は日本語訳が出ていないので肝心の本の内容のレベルについて心配かと思いますが、米アマゾンのレビューを見て評価の高いものを選べばほぼ間違いはありません。実際非常に評価の高い素晴らしい本がたくさんあります。

最近では新刊が紙とPDF版の両方で出ています。PDF版であれば紙の本より若干安い上にクレジットカード決済ですぐに読み始めることができます。また電子辞書と組み合わせれば面倒な単語の辞書引きがだいぶ楽になります。さらに、最初からPDF版を買えば面倒な自炊は必要はありません。

上記電子書籍は元々紙の本より安いのでそれだけでお得なのですがさらに安く手に入れるためには各出版社のTwitterの公式アカウントをフォローしてセール情報を手に入れましょう。約半額になります。

http://twitter.com/OReillyMedia

http://twitter.com/Apress

http://twitter.com/ManningBooks

http://twitter.com/packtpub

動画・スクリーンキャスト

リスニングを鍛えるならデザイン/技術を扱った動画が良いでしょう。これまた英語圏には驚くほど豊富にコンテンツがあります。ナチュラルスピードの英語を聞くのは最初は抵抗があるかもしれませんが、意外と耳に入るものです。というのも話の内容がテクニカルなことなので、「何について話しているのか」が把握しやすいのです。これが普通の映画やドラマではこうはいきません。会話の背後のコンテクストを共有できているというのはとても有利な条件です。

iTunes U

iTunes1 Webプログラマー/デザイナーは英語「を」学ぶのではなく英語「で」学ぼう

完全無料でアクセスしやすいのはいいのですが、音声が悪かったり内容が数年前のものだったりではっきりいって玉石混淆です。内容が充実していて話題が新しいものはスタンフォード大学提供のiPhoneプログラミング講座が挙げられます。

Doctype.tv

DOCTYPE The Show For People Who Make Websites. Video Tips Tricks and Tutorials for Web Design and Web Development. Webプログラマー/デザイナーは英語「を」学ぶのではなく英語「で」学ぼう

毎週火曜更新。無料。毎週一つずつWebデザインとwebプログラミングのトピックを提供。扱っている話題はかなり新しいです。内容をテキスト化したshow notesがあるので後でじっくりと内容を確認することもできます。

Think Vitamin Membership

Learn Web Design HTML 5 CSS3 Video Tutorials Training Resource    Think Vitamin Membership 1 Webプログラマー/デザイナーは英語「を」学ぶのではなく英語「で」学ぼう

Doctype.tvの有料版ともいうべきWebデザイナー/Webプログラマ向けスクリーンキャスト。出演者はDoctype.tvと同じ。メニューを見てもらえばわかりますがNode.jsやMongoDBなど内容が非常に先鋭的です。

lynda.com

lynda.com software training tutorials latest releases Webプログラマー/デザイナーは英語「を」学ぶのではなく英語「で」学ぼう

技術/デザイン系のe-ラーニングでは老舗です。有料。内容は非常に多岐にわたっていて質も高い。特にAdobe系講座の充実度はすごい。CC(Closed Caption)表示があるコースは英語の字幕が表示できます。

サイトトップからなかなか見つけられないリンクなのですが、↓から申し込めばトライアルで7日間無料でコンテンツにアクセスできます。

http://www.lynda.com/promo/trial/Default.aspx?lpk35=197

ZendCasts

Free Zend Framework Screencasts Zendcasts Webプログラマー/デザイナーは英語「を」学ぶのではなく英語「で」学ぼう

PHP/ZendFrameworkの話題を扱うスクリーンキャスト。無料。すでに2年以上続いていてコンテンツは豊富です。ソースコードがgooglecodeからDLできるようになっています。

KillerPHP

PHP Video Tutorials For Web Designers KillerPHP.com 1 Webプログラマー/デザイナーは英語「を」学ぶのではなく英語「で」学ぼう

有料(一部無料)。ZendCastsの講師が出演している。

その他

電子書籍を読んでいて間違いを見つけたらサポートサイトに行って”Errata”(正誤表)に投稿しましょう。こうすれば「書く」能力も鍛えられます。

海外製のシェアウェアを使って不具合や要望がある場合どんどん文句を言いましょう。下手な英語であってもこちらは「お客様」なので丁重に扱ってもらえます。また、サポートサイトの英語のやりとりを読むのは非常に勉強になります。

普段使うソフトがもし表示を英語にできるのであればそうしてしまいましょう。たとえばEclipseやGmailなどは日本語化せずに英語のまま使うのはどうでしょうか。普段から英語の用語に慣れていれば英語のサポート情報やブログを見て情報収集がやりやすいという利点もあります。世界の技術情報の大半は英語で発信されているという事実を考えるとなかなか合理的です。

まとめ

英語のスクリーンキャストは最初かなり抵抗がありましたが、今ではごく普通に楽しめるようになりました。日本語ではこういう動画コンテンツが皆無に近いので本当に助かっています。

本については最近は購入する技術書がほとんど全部英語かつPDF版になりました。本棚でかさばらないという利点の他に、twitterの情報を利用してとにかく安く手に入れることができるので助かります。読み続けることで英語の技術書に対するハードルはだいぶ低くなりました。もちろん全部の情報が英語でOKというほど自分の英語力が高いわけではないので日本語の技術書も読みますが。

※それにしても日本の有名どころ技術系出版社が電子書籍化にまったくもって消極的なのは悲しいです。PDF版が充実しているオライリージャパンにしても本家のような電子書籍のセールをやってくれませんねえ。

Posted in その他 | Leave a comment

NetBeansのMercurialで文字化けを回避する

環境: Mac OSX 10.6.6, NetBeans 6.9.1

OSX上でNetBeansを使う場合、svnにしろhgにしろデフォルトの設定ではコミットメッセージが文字化けしてしまい読むことも書くこともできません。原因は

1. OSXのJDK6はデフォルトの文字コードが(なぜか)Shift_JISであること(Mac OSXの標準はutf-8)
2. mercurial用の環境変数であるHGENCODINGが正しく設定されていないこと

の2点です。

1.の回避方法としてシステムの環境変数をいじってJDKがutf-8で起動するようにする方法もありますが他に何か影響があるやもしれないので却下。NetBeansだけに変更範囲が及ぶようにします。方法は
/Applications/NetBeans/NetBeans 6.9.1.app/Contents/Resources/NetBeans/etc/netbeans.conf
を開いて、netbeans_default_options=… でオプションを列挙している部分に

-J-Dfile.encoding=UTF-8

を追加します。

2.を解決するには
/Applications/NetBeans/NetBeans 6.9.1.app/Contents/Resources/NetBeans/bin/netbeans
という名前のスクリプトを変更します。

netbeans 1 300x251 NetBeansのMercurialで文字化けを回避する

以上2点を行いNetBeansを再起動すればmercurialをutf-8で正しく扱うことができるようになります。

参考:
NetBeansのSVNで文字化けを回避する方法
MacにMercurialをインストールしてNetBeansから利用

Posted in 技術・開発ツール | Tagged , | 3 Comments