日本語のチュートリアルが無く、スタートアップに苦労したので
ソースコード付きの解説をエントリーします。
【日本語版】ZendFramework2(ZF2)チュートリアルをエントリーポイントからコントローラ、
ビューへの値渡しからモジュールの設定まで、初めに必要な事をソースコード付きで解説します
- 大きく変わったZendFramework2(ZF2)
- スケルトンプロジェクトを用意しよう!
- スケルトンプロジェクトからZendFramework2を使える様にする
- コントローラの定義と実装、ビューへの値渡し
- モジュールの情報を設定しよう
大きく変わったZendFramework2(ZF2)
ZendFrameworkは
2012年09月に大幅にモデルチェンジされ、
正式にZendFramework2(ZF2)としてリリースされました。
ZendFramework1の頃とは大幅に変わっている上に、
ZendFramework2の情報は、まだまだとても少なく、
導入に苦労している人も多いのでは無いでしょうか?
ZendFramework2ではネームスペースを使っている関係で、
推奨環境がPHP5.3.3 以上という事もあり、
最新のPHP仕様を追いかけていない人には、新たなコーディングの仕方にも苦労する事でしょう。
また、MVC的なWEBアプリのエントリーポイントから画面表示までの流れも大幅に変更されています。
ZendFramework1の頃ですと、Zend_Controller_Frontでエントリーし、
パラメータによってディスパッチされ、アクションが決定し、
処理された内容がviewへ当て込まれて返却される。
こういった流れでしたが、ZendFramework2では
そもそもZend_Controller_Frontなるものも存在しません。
今までZendFramework1を使っていた人は、今まで使ってきたメソッドやクラスが悉く無くなっていたり
変更されていたり、リネームされているので
初めもエントリーポイントの書き方から悩む事になります。
そんな、一番スタート的な書き方でさえ、まだまだ日本語ドキュメントが少ないので
調べる事さえ困難です。
今回はそんな、まだまだ日本語の情報が少ない
最新のZendFramework2について、導入方法をチュートリアルとして解説したいと思います
初めに躓かない様に、出来る限り噛み砕いて解説しますので、
ゆっくりと読んで頂ければ幸いです。
まず、チュートリアルとして、一番分かりやすいのが
動くコードを見ながらカスタマイズしていく事です。
今回は、ZendFramework2の扱い方をスケルトンプロジェクトを元に解説したいと思います。
スケルトンプロジェクトを用意しよう!
それでは、ZendFramework2に対応したスケルトンプロジェクトをダウンロードしましょう
ダウンロードは下記URLの遷移先であるgithubからダウンロードして下さい
私の場合は、ZIPで纏めてダウンロードしました。
ZendSkeletonApplication
https://github.com/zendframework/ZendSkeletonApplication
ディレクトリ構造は別ページに纏めましたので、
一覧として纏めて見たい方はそちらを参照してください
ZendSkeletonApplicationのディレクトリ構造とファイル構成
http://web-terminal.blogspot.jp/2013/02/zendframework2zendskeletonapplication.html
続いて、ZendFramework2自体を公式サイトよりダウンロードしましょう
『ZendFramework2公式サイト』
http://framework.zend.com/
ZendFramework2自体のディレクトリ構造も纏めたので
全体を見渡したい方は下記を参照下さい。
ZendFramework2のディレクトリ構造とファイル構成
http://web-terminal.blogspot.jp/2013/02/zendframework-206.html
ダウンロードした状態ですと、DEMOやサンプルなど、
実際の開発では使わないファイルやフォルダも混ざっています。
実際に開発に使うのは『library』配下だけで良いでしょう。
スケルトンプロジェクトからZendFramework2を使える様にする
ここからは先程ダウンロード致しましたスケルトンプロジェクトを元に
実際にZendFramework2を使う方法をチュートリアルとして解説して行きます。
まずはスケルトンプロジェクトの『public』が公開ディレクトリとなります。
これは『www』となっているかもしれませんし、『htdocs』となっているかも知れません。
公開ディレクトリ内のindex.phpが、サイトへのアクセスを全て集約する
エントリーポイントとなります。
全てはこのindex.phpファイルからスタートし、URIを判断して
適切な処理を行い、画面を表示させます。
そういった処理の流れにそって解説を続けたいと思います。
スケルトンプロジェクトのindex.phpを見ると、中身は下記の様になっているかと思います
/** * This makes our life easier when dealing with paths. Everything is relative * to the application root now. */ chdir(dirname(__DIR__)); // Setup autoloading require 'init_autoloader.php'; // Run the application! Zend\Mvc\Application::init(require 'config/application.config.php')->run();
簡単に内容を説明しますと、
カレントディレクトリを設定し、オートローダーを読み込み、
アプリの設定ファイルを読みつつ処理を起動する。
といった流れです。
しかし、このスケルトンプロジェクトは
このままでは動作しません。
必要なパスや環境設定を事前に行わなければなりません。
設定は、php.iniにて行っても良いですし、このindex.php内にて
PHPコードでその都度設定しても良いです。
私の場合はPHPコードに直接書いてしまいました。
設定するポイントは二つあります。
1.include_pathにZendFramework2のlibrary配下までのパスを設定する
2.環境変数として『ZF2_PATH』にlibrary配下までのパスを設定する
これらをPHPコードで記述すると下記の様になります
// include_pathに本体までのパスをセットする $paths = array( '/var/www/html/library/ZendFramework-2.0.6/library/', '.', ); set_include_path(implode(PATH_SEPARATOR, $paths)); // ライブラリ本体へのパスを指定 $path = realpath(dirname(__FILE__) . '/../../library/ZendFramework-2.0.6/library/'); // 環境変数を追加 putenv("ZF2_PATH=".$path);
パスはそれぞれの環境によって書き換えて下さい。
index.php内の他の処理の前に上記の様な設定コードを入れる事で、
ZendFramework2を認識出来る様になり、
アプリを起動する事が出来るようになります。
コントローラの定義と実装、ビューへの値渡し
エントリーポイントからアプリが起動し、URLを解析したら
処理はコントローラへ渡されます。
そのコントローラの設定は各モジュールの中のmodule.config.php内で行います
module\Application\config\module.config.php
// コントローラを定義する 'controllers' => array( 'invokables' => array( 'Application\Controller\Index' => 'Application\Controller\IndexController', // テストコントローラと言うのを新たに作成した 'Application\Controller\Test' => 'Application\Controller\TestController', ), ),
controllersというキーに対して連想配列で設定し、
実際のコントローラの定義はinvokablesに連想配列で指定します。
スケルトンプロジェクトには上記の様なコードが既に書かれていますので、
上記を参考に書き足してみて下さい。
今回は、新たにテストコントローラを作成してみました。
'Application\Controller\Test' => 'Application\Controller\TestController',
コントローラが増える毎に、こちらのファイルにて設定して下さい。
設定する事によってコントローラを読み込む事が出来る様になります。
それでは実際にコントローラを配置して見ましょう
コントローラの配置
module\Application\src\Application\Controller\TestController.php
namespace Application\Controller; use Zend\Mvc\Controller\AbstractActionController; use Zend\View\Model\ViewModel; class TestController extends AbstractActionController { public function indexAction() { return new ViewModel(); } }
コントローラ名は命名規則として頭文字を大文字とし、Controllerと付け足します。
そして、AbstractActionControllerを読み込み、継承してコントローラクラスを作成します。
コントローラクラスの全体像は、スケルトンプロジェクトのコントローラを参考にして下さい。
各コントローラまでのパスは
module\モジュール名\src\モジュール名\Controller\コントローラ名Controller.php
となります。
そして、コントローラ内のメソッド名は頭文字を小文字とし
Actionと続けて下さい。これがコントローラの実行動作となります。
ここまでの処理をリクエストするには、下記の様なリクエストになります。
URL ドメイン/モジュール/コントローラ/アクション domain.com/application/test/index
これでTestControllerのindexAction()がリクエストされます。
今回は
return new ViewModel();の様にビューを返却してあげる事で、
ビューファイルを読み込んでくれるようになります。
また、ビューに対して値を渡したい場合は
$view = new ViewModel( array( "key" => "val") ); return( $view );の様に、コンストラクタで値を連想配列として渡す事で
渡した値をビュー側でも参照出来るようになります。
ビュー側での値の使い方は
key; ?>の様に取り出す事が出来ます。
また、ビューへのパスは
module\モジュール名\view\モジュール名\コントローラ名\アクション名.phtml
です。
モジュールの情報を設定しよう
モジュールにはネームスペースが適用され、
モジュール内のディレクトリ構造やURLの規則等を設定する事が出来ます。
モジュールの設定ファイルは、先程コントローラ情報を追加した
module\Application\config\module.config.php
です。
これはモジュール毎に作成する必要がありますので、
パスは
module\モジュール名\config\module.config.php
となる事を念頭に置いて下さい。
'router' => array( 'routes' => array( // モジュール名の指定が無い場合の処理を設定 'home' => array( 'type' => 'Zend\Mvc\Router\Http\Literal', 'options' => array( 'route' => '/', 'defaults' => array( 'controller' => 'User\Controller\Index', 'action' => 'index', ), ), 'may_terminate' => true, 'child_routes' => array( 'default' => array( 'type' => 'Segment', 'options' => array( 'route' => '[:controller[/:action]]', 'constraints' => array( 'controller' => '[a-zA-Z][a-zA-Z0-9_-]*', 'action' => '[a-zA-Z][a-zA-Z0-9_-]*', ), 'defaults' => array( 'action' => 'index', '__NAMESPACE__' => 'User\Controller' ), ), ), ), // モジュール名が『application』と指定された時の処理を設定 'application' => array( 'type' => 'Literal', 'options' => array( 'route' => '/application', 'defaults' => array( '__NAMESPACE__' => 'Application\Controller', 'controller' => 'Index', 'action' => 'index', ), ), 'may_terminate' => true, 'child_routes' => array( 'default' => array( 'type' => 'Segment', 'options' => array( 'route' => '/[:controller[/:action]]', 'constraints' => array( 'controller' => '[a-zA-Z][a-zA-Z0-9_-]*', 'action' => '[a-zA-Z][a-zA-Z0-9_-]*', ), 'defaults' => array( ), ), ), ),
routesの中では、リクエストURLによる処理の振る舞いを設定します。
その中でも、モジュール名を入力する部分単位で設定できますので
通常ですとURLは
ドメイン/モジュール/コントローラ/アクション
となっていますが、
ここでは
ドメイン/モジュール/key
だった時の処理や
ドメイン/
の時の処理も設定出来ます。
パラメータのない時の処理は、モジュール名をhomeとして内容を設定すると
パラメータ無しのルートディレクトリとしての処理として設定されます。
後は単なるモジュール名のキーですので、お好きな名前で設定し、
振り分けの内容を記述して下さい。
主に、リクエストに対するコントローラやアクションの選別ルールの設定となります。
また、モジュールごとのディレクトリ設定として、ビューファイルへのパスの設定も
同じファイル内で行います
'view_manager' => array( 'display_not_found_reason' => true, 'display_exceptions' => true, 'doctype' => 'HTML5', 'not_found_template' => 'error/404', 'exception_template' => 'error/index', 'template_map' => array( 'layout/layout' => __DIR__ . '/../view/layout/layout.phtml', 'user/index/index' => __DIR__ . '/../view/user/index/index.phtml', 'error/404' => __DIR__ . '/../view/error/404.phtml', 'error/index' => __DIR__ . '/../view/error/index.phtml', ), 'template_path_stack' => array( __DIR__ . '/../view', ),
view_managerというのがビューを管理しますので、
ビューを識別する為のキーとパスを設定します。
特にアクション名の指定が無い場合のビューの選択も、
routesの設定と一致させる事でビューの指定も出来る様になります。
ココまで設定すれば、リクエストに対してコントローラとアクションとビューの切り分けが出来る様になりましたので、
後はコントローラ内やビューの実装に取り掛かれます。
また、実装して行く上でモジュールを追加したい場合があります。
モジュールの追加定義は
// This should be an array of module namespaces used in the application. 'modules' => array( 'Application', 'NewModule' ),
上記の様に、modulesに対してモジュール名を配列で渡してあげます
これでアプリがモジュールを認識出来る用になりましたので、
スケルトンファイルのモジュールをコピーして
モジュール名をリネームするなりして開発準備を行って下さい。
気をつけなければいけない点が、ネームスペースがかなり厳しく設定sれていますので、
それぞれのコントローラやModule.phpの中のネームスペース設定を変える必要があり、
各ディレクトリ名もモジュール名に書き換え、頭文字が大文字が基本ですが
ビューのフォルダは頭文字が小文字だとか、
そういった細かい点もありますので慣れて来るまでは慎重に作業して下さい。
モジュール毎に設定を行う
module\モジュール名\config\module.config.php
ですが、このファイルはそれぞれのモジュール設定をマージして
アプリの設定と認識しますので、
もし同じキーを設定していたりすると、最後に読み込まれたモジュールの内容だけが
適用されてしまいますので、注意が必要です。
良く、パラメータ無しのデフォルト設定として『home』の設定を複数のモジュールで行ってしますと
予期せぬ動作となってしまいます。
気をつけましょう。
後はどんどん実装を開始し、各APIやライブラリを活用して行く作業に入ると思います。
その辺りはチュートリアルというよりはリファレンスとなりますので、
各機能についての説明は別の機会に解説したいと思います。
駄文・乱文でのチュートリアルでしたが、
ココまでお読み下さいまして有難う御座います。
今後とも当ブログを宜しくお願い致します。
はじめまして、いつも勉強させてもらっています。
返信削除濱田さんのサイトを確認していて、ZendFramework2に
興味をもちまして、色々試しているのですがうまくいかない点があるので質問させていただいてもよろしいでしょうか
ご迷惑であれば勝手ながらスルーしていただければと思います。
質問は、viewのlayoutなのですが、公式ページのチュートリアルをこなしていくと
layout.phtmlのtitleに$this->headTitle()というものを使用しているのですが
とくにタイトルが表示されている形跡はありません。またどのように設定したらよいのかも追えていません。
これほどのフレームワークであれば、このあたりは良きに計らってくれそうな気もするのですが、どのようにlayoutのtitleをページ毎に追加していけばよいかご存知でしょうか?a
お世話になっております。
削除この度はコメント頂きまして、誠に有難うございます。
ページ毎のタイトルの設定方法ですが、
タイトルの設定にはViewHelperのheadTitleを使用します。
具体的には下記の様にタイトルを設定可能です。
$this->headTitle()->set('title');
他にも、下記の様なメソッドが用意されています。
// タイトルを設定する
・ set($title);
// タイトルの末尾に追加する
・ append($appendTitle);
// タイトルの先頭に追加する
・ prepend($prependTitle);
// タイトルのセパレータを設定する
・ setSeparator($separator);
上記メソッドの記述箇所ですが、ビュー内であれば
何処でも構いません。レイアウト内でも、
アクション毎のビューファイル内でも問題ありません。
アクションによって出力されるビュー毎に
上記設定を行えば、ビュー毎に個別のタイトルが設定可能かと思われます。
他にも、何かご不明な点やご要望、ご相談等御座いましたら
お気軽にコメント下さい。
今後ともよろしくお願いいたします。
URL
返信削除ドメイン/モジュール/コントローラ/アクション
誤 domain.com/Application/test/index
正 domain.com/application/test/index
でした。
ご指摘ありがとう御座います。
削除早速ですが、該当箇所を修正させて頂きました。
他にも、何か不備が御座いましたら
お手数お掛けしますがご報告頂ければ幸いです。
今後とも、何卒よろしくお願いいたします。
こんにちわ
返信削除現在本を購入してzend framework2を勉強中なのですが、テンプレートのところがよくわからないので教えていただけないでしょうか。
p76に『content/article/view』内で子ビューに当て込むと記載してありますが、
content/article/にviewというファイルをcode 3-71の内容でファイルを作成(修飾子なし?)するということでよろしいのでしょうか?
何回かチャレンジしましたがここだけうまくいきません。
content/article/viewをconfigで登録したりはなくても大丈夫なのでしょうか?
コバヤシ 様
削除この度は本をご購入いただき、誠に有難う御座います。
『content/article/view』というのは、
『module/controller/action』というパスの一例ですので、
その場所にあるファイルにp76の内容が記載されていれば問題ありません。
その他のパスも同様に置き換えていただければ幸いです。
因みに、『setTemplate()』にてviewを指定する際には拡張子を省略する事が出来ます。
ですので、『application/index/index』と『application/index/index.phtml』は同じファイルを指すことになります。
指定する為に、特にコンフィグにて設定する必要はありません。
他にも、何かご不明な点が御座いましたら
お気軽にご連絡下さい。
今後とも宜しくお願い致します。
ご返事ありがとうございました。
返信削除教えていただいたことを参考に修正しましたら動作いたしました。
年末なのにありがとうございました
Yosuke Kobayashi 様
削除この度はお返事頂きまして、誠に有難う御座います。
無事に動作した様で何よりです。
他にも、何かご不明な点が御座いましたらお気軽にご連絡下さい。
今後とも宜しくお願い致します。
書籍を購入した者です。この度、質問があり連絡させていただきました。
返信削除P.58まで書籍記載された通りに設定を行い、
「http://localhost/ZendSkeleton/」にアクセスして、
スケルトンプロジェクト導入完了画面の表示まで確認出来ました。
しかし、
P.58の「デフォルト設定による省略なしのURL」での
「http://localhost/ZendSkeleton/application/index/index」へアクセス、
P.59の「Controllerを作成して、実行処理を切り分けよう!」での
「http://localhost/ZendSkeleton/application/user/add」へアクセスを試みましたが、
どちらも
「Object not found!
要求された URL は本サーバでは見つかりませんでした。
もし手入力で URL を入力した場合は、綴りを確認して再度お試し下さい。
サーバーの障害と思われる場合は、ウェブ管理者までご連絡ください。
Error 404」画面が表示されてしまいます。
プロジェクトの
「C:\xampp\htdocs\ZendSkeleton\.htaccess」
Apacheの
「C:\xampp\apache\conf\httpd.conf」
Windowsの
「C:\Windows\System32\drivers\etc\hosts」
などの設定はデフォルトのままです。
何か追加で設定する必要があるのでしょうか?
ご返事お待ちしております。
この度は書籍のご購入、誠に有難う御座います。
削除ご報告頂きました内容は、こちらの環境では再現しませんでした。
ただ、エラーメッセージを見る限りZF2の問題ではなく、環境の問題に見えます。
疑わしい点として、「mod_rewrite」の設定は有効になっていますでしょうか?
ご利用のxamppのバージョンは分かりませんが、
バージョンによってデフォルト設定が異なるのかも知れません。
「C:\xampp\apache\conf\httpd.conf」内の
「LoadModule rewrite_module modules/mod_rewrite.so」
がコメントアウトされていないかご確認頂ければ幸いです。
他にも、何かご不明な点が御座いましたら
お気軽にご連絡下さい。
今後とも宜しくお願い致します。
『Zend Framework 2徹底解説』を購入して勉強しています。
返信削除スケルトンプロジェクトをダウンロードして、モジュールを3つつくりました。
Application1
Application2
Application3
Application1はテーブルtest1
Application2はテーブルtest2
をそれぞれ操作します。
Application3モジュールでは
index.phtmlで
テーブルtest1の集計と
テーブルtest2の集計を表示させようとおもいます。
Application1のindexAction()の中の変数$test1Arrayと
Application2のindexAction()の中の変数$test2Arrayを
Application3に渡せば
簡単に表示できると思うのですが、やり方がわかりません。
モジュールをまたいで変数のやり取りをしたいのです。
どうかご教授ください。
寺内ひかる 様
削除お世話になります。
この度は『Zend Framework 2徹底解説』のご購入、誠に有難うございます。
ZF2ではリクエスト毎に、処理するモジュールを判別し、
実行するアクションを決定します。
例えば
domain.com/application3/コントローラ/index
でリクエストを行った場合、処理されるのは
モジュール「Application3」のアクション「indexAction()」ですので、
Application1のindexAction()も、
Application2のindexAction()も実行されません。
ですので、それぞれの中身で作成された変数を
Application3で扱うことは出来ません。
もし、的外れな回答でしたら
お手数お掛けしますが再度コメント頂ければ幸いです。
今後ともよろしくお願いいたします。
返信ありがとうございました。
削除冷静に考えてみれば、まったくご指摘のとおりですね。
的はずれなことを考えていました。
今後ともよろしくお願いします。
寺内ひかる 様
削除お世話になります。
この度はコメント頂きまして、誠に有難う御座います。
他にも、何か御座いましたらお気軽にコメント下さい。
今後とも宜しくお願いします。
はじめまして。
返信削除ZendFramework2の書籍を購入して勉強しているのですが、ここで質問をしてもよろしいでしょうか。
フレームワークとしてではなく、ライブラリとしてZendNavigationを利用したく導入しているのですが、
以下のエラーが出てしまい解決できていません。
>Fatal error: Uncaught exception 'Zend\ServiceManager\Exception\ServiceNotFoundException' with message 'Zend\View\HelperPluginManager::get was unable to fetch or create an instance for menu' in /var/www/html/kincone/vendor/zendframework/zend-servicemanager/Zend/ServiceManager/ServiceManager.php:529
518P Zend/Viewのページで必要なヘルパーはライブラリ利用の場合はインスタンス化が必要とありましたが、PhpRendererをインスタンス化しておくとheadTitle等を含めてHelperとして利用できると認識していましたが違うようです。。
この辺りや、ZF2のサービスマネージャー等の仕組みがいまいち理解できていない状況です。
以下の様なコードで試してみました。
コントローラーで記述
※最終的にはビュー側で利用を想定
-----------
use Zend\View\Renderer\PhpRenderer;
$renderer = new PhpRenderer();
echo $renderer->escapeHtmlAttr('in'); // escapeHtmlは利用可能
echo $renderer->doctype('XHTML1_STRICT'); // doctypeも利用可能
// 以下の様な書き方だと上記エラーが出ていまいます。
// containerはページ情報を含んだNavigationクラスです
echo $renderer->menu($container);
echo $renderer->menu()->renderMenu($container);
--------
お手数をお掛けしますが教えていただければ幸いです。
KITAMURA 様
削除お世話になります。
この度は『Zend Framework 2徹底解説』のご購入、誠に有難うございます。
「menu()」メソッドは、Navigationが持つメソッドですので、
PhpRendererのインスタンスから扱う際には
Navigationのインスタンスを得る「navigation()」を使用すると良いかもしれません。
echo $renderer->navigation()->menu()->renderMenu($container);
もしくは
echo $renderer->navigation($container)->menu()->renderMenu();
の様にすると如何でしょうか?
書籍で言いますと、P434ページ辺りからが該当するかと思います。
もし、動作しない場合は
お手数お掛けしますが再度ご連絡頂ければ幸いです。
何卒、よろしくお願いいたします。
返信有難うございます。
削除navigationからにすると、以下の様なエラーとなりました。
Zend\View\Helper\Navigation\PluginManager::get was unable to fetch or create an instance for navigation'
以下の様なコードで検証しておりますが、
間違いありましたらご指摘頂けないでしょうか。
$pages = array(
array(
'module' => 'default',
'controller' => 'index',
'action' => 'links',
'title' => 'title',
'label' => 'Page1',
'pages' => array(
array(
'uri' => 'http://www.google.co.jp/',
'title' => 'ぐーぐる',
'label' => 'Google',
'target' => '_blank',
),
),
),
);
$renderer->setHelperPluginManager(new Zend\View\Helper\Navigation\PluginManager);
$navigation = new Navigation();
$navigation->addPages($pages);
$container = $navigation->findOneBy('label', 'Page1');
echo $renderer->navigation()->menu()->renderMenu($container);
最終的にはviewで利用したいので、viewから利用する場合は
$this->navigation()->から記述していけばよいのでしょうか?
よろしくお願いいたします。
KITAMURA 様
削除お世話になります。
この度はコメント頂き、誠に有難う御座います。
少し調べた所、こちらの環境で動作を確認出来ましたので、
ご連絡差し上げます。
まず、通常通りZF2をフレームワークとして使用した場合を想定し、
Viewにてレンダリング処理を行う場合は、コントローラ側でコンテナを準備し、
Viewにてヘルパーを使用してレンダリングします。
ヘルパーは、Viewへ制御が移る際に自動的にセットアップされますので、
コントローラの時点では使用することが出来ません。
(サービスを設定すれば可能ですが、あくまでもViewのヘルパーですのでオススメしません)
下記コントローラ内でコンテナをセットアップしている処理です。
use Zend\Navigation\Navigation;
$navigation = new Navigation();
$navigation->addPages($pages);
$container = $navigation->findOneBy('label', 'Page1');
$view = new ViewModel();
// viewへコンテナを渡す
$view->container = $container;
return $view;
そして、View側では下記の様にレンダリングすることが出来ます。
navigation()->menu()->renderMenu($container); ?>
また、今回はライブラリとしての利用をお考えとの事で、
コントローラ内でecho出来るよう実装してみました。
内容と致しましては、レンダリングを行うMenuクラスを直接インスタンス化し、
「renderMenu()」メソッドを使用しています。
気を付ける点として、レンダリングを行うにはレンダラが必要ですので、
今回の例ではPhpRendererをレンダラとして「setView()」メソッドにて登録しています。
具体的な処理内容は下記をご確認下さい。
use Zend\View\Renderer\PhpRenderer;
use Zend\Navigation\Navigation;
use Zend\View\Helper\Navigation\Menu;
$navigation = new Navigation();
$navigation->addPages($pages);
$container = $navigation->findOneBy('label', 'Page1');
$menu = new Menu();
$menu->setView( new PhpRenderer() );
echo $menu->renderMenu($container);
他にも、何か御座いましたらお気軽にご連絡頂ければ幸いです。
今後とも宜しくお願いいたします。
何度も丁寧に回答頂きありがとうございます!
削除頂いたコードだと以下のエラーとなってしまいました。
Fatal error: Call to a member function attach() on a non-object in /vendor/zendframework/zend-view/Zend/View/Helper/Navigation/AbstractHelper.php on line 939
頂いたのを参考に以下のようにすると描画されました。
※コントローラー内
$navigation = new Navigation();
$navigation->addPages($pages);
$container = $navigation->findOneBy('label', 'Page1');
$menu = new Menu();
$renderer = new PhpRenderer();
$renderer->menu()->setUseAcl(false);
echo $renderer->menu()->renderMenu($container);
---
加えて、Zend/View/HelperPluginManager.phpのinvokableClassesに以下を追加しました。
'menu' => 'Zend\View\Helper\Navigation\Menu',
調べていくなかで、以下のようにプラグインマネージャーを設定するとmenuメソッドが利用できるようになるのがわかりました。
ただ、こうするとhtmlexcapeなどのこれまで利用できたヘルパー関係が利用できなくなる弊害もあり、上記のように一緒に記述するのはどうかなと考えた次第です。
どうすれば両方同時に利用できるのか他にスマートな方法が思いつかない状況ですが、この変更方法は他に弊害をもたらすのかわからない状況です。
この変更方法がZFとして問題がなければこの方法で進めたいと思っております。
$renderer->setHelperPluginManager(new Zend\View\Helper\Navigation\PluginManager);
ACLがデフォルトでゆうこうになっているのでビュー側では設定を変更して利用しないと使えないようですが。
本当に何度も回答を頂いて感謝しています。よろしくお願いいたします。
KITAMURA 様
削除お世話になります。
この度はコメント頂きまして、誠に有難うございます。
尚、先ほどの上記コメントにて、PHPタグが消されて一部誤りがありました。
View側の記述で、PHPタグ内は下記の通りです。
$this->navigation()->menu()->renderMenu($container);
ちなみに、お使いのZF2のバージョンはいくつでしょうか?
動作内容に相違がありますので、何かしら仕様が変わっているのかも知れません。
また、出来るだけZF2自体を直接触る事は、
今後扱うのプロジェクト全体にかかわりますし、
あまりお勧めしません。
せめて継承して、独自のヘルパーを作成された方が良いかと思います。
こちらでも、ご報告頂いたエラーの発生原因を調査したいと思いますので、
今しばらくお待ちくださいます様、よろしくお願いいたします。
何度もありがとうございます。
削除試している中でうまく描画できるようになりました。
仰るとおり、コアな部分を触るのはよくないので、継承したクラスを作成してためしました。
継承すると問題なくできましたが、濱田様に教えていただいたsetViewメソッド利用することでスマートに出来るようになりましたので、本件に関しては解決しました。
本当に助かりました。
navigationとaclを関係付けて行く予定ですので、また質問するかもしれませんが、よろしくお願い致します。
一点忘れておりました。
削除aclと関係づける前に、navigation描画の際、以下のようにして、
aclを利用しないようにoffにしておりました。
menu()->setUseAcl(false);
これは有効にしていると以下の様なエラーが表示されるため、
オフにして描画していました。
Fatal error: Call to a member function attach() on a non-object in /vendor/zendframework/zend-view/Zend/View/Helper/Navigation/AbstractHelper.php on line 939
このエラーですが、有効にした場合はACLのロール等の設定をしていない状態ですので
該当ページの権限がなく、メニューが表示されない状態を期待しておりました。
ですが、有効時はエラーとなるので必要な設定自体が不足しているようです。
これらの設定を有効にした上でメニューを表示する方法を調べているところですが、何か原因がわかりましたら返信いただけますと幸いです。
よろしくお願いいたします。
KITAMURA 様
削除お世話になります。
この度はコメント頂き、誠に有難う御座います。
setViewにて描画できたとの事で、何よりです。
なお、ACLとの連携ですが、有効時にはエラーとなってしまうのは
流石に仕様的に違和感がありますので、何か回避策が有るはずです。
エラー内容を確認する為に、こちらのソースで該当箇所を確認した所、
Zend/View/Helper/Navigation/AbstractHelper.php
は929行しかなく、エラーメッセージにあります939行目が存在しません。
既にソースレベルで差分がありますので、zf2のバージョンを教えて頂ければ幸いです。
何卒、宜しくお願い致します。
いつもありがとうございます。
削除Version2.3を使用しています。
該当行は以下になります。
どうやらsharedManagerの結果が取得できないようです。
この辺りのEventManagerは概念自体は理解したのですが、
ライブラリとしてそのまま利用する際には特に設定等を意識する必要はないと思っています。
※違っていたらご指摘下さい
930 /**
931 * Attaches default ACL listeners, if ACLs are in use
932 */
933 protected function setDefaultListeners()
934 {
935 if (!$this->getUseAcl()) {
936 return;
937 }
938
939 $this->getEventManager()->getSharedManager()->attach(
940 'Zend\View\Helper\Navigation\AbstractHelper',
941 'isAllowed',
942 array('Zend\View\Helper\Navigation\Listener\AclListener', 'accept')
943 );
944 }
濱田様のお陰で前進出来ており非常に感謝しております。
よろしくお願いいたします。
合わせて私のコードの該当部分を記載しておきます。
返信削除濱田様に教えていただいたmenuインスタンスの取得をZend\View\Helper\Navigationより行うように変えています。
教えていただいたようにmenuクラスを直接インスタンスしていた場合でも同じエラーとなります。
--------
// ライブラリの読み込み
use Zend\View\Renderer\PhpRenderer;
use Zend\Navigation\Navigation;
use Zend\View\Helper\Navigation\Menu;
use Zend\View\Helper\Navigation as Helper_Navigation;
// 以下navigation利用部分
$navigation = new Navigation();
$navigation->addPages($pages);
$container = $navigation->findOneBy('label', 'Page1');
$renderer = new PhpRenderer();
$this->_helper_navigation = new Helper_Navigation();
$this->_helper_navigation->setView($renderer);
// $this->_helper_navigation->menu()->setUseAcl(false); // この部分でACLを利用しないようにするとメニューが表示されます。
echo $this->_helper_navigation->menu()->renderMenu($container);
// エラー内容
Fatal error: Call to a member function attach() on a non-object in /vendor/zendframework/zend-view/Zend/View/Helper/Navigation/AbstractHelper.php
意図的にaclをfalseにしないと表示できず、aclと関係付けて利用したいので有効にしたいと思っております。
よろしくお願い致します。
KITAMURA 様
削除お世話になります。
この度はコメント頂き、誠に有難う御座います。
お調べした所、
私の環境にて、KITAMURA 様の状態を再現することは現状出来ていません。
ですが、あまり良い方法とは言えませんが、無いと言われているSharedManagerを
登録しておくのは如何でしょうか?
例えば下記の様に、レンダリング前にメニューを通してSharedManagerを新しく登録します。
$this->_helper_navigation->menu()->getEventManager()->setSharedManager( new SharedEventManager() );
主にSharedManagerを作成しているのは、フレームワーク使用時に使われるmvcモジュールですので、
ライブラリからの利用では独自にセットする必要があるのかも知れません。
宜しければ、今後のためにも動作報告を頂ければ幸いです。
何卒、宜しくお願い致します。
ありがとうございます。
削除色々と感謝してます。
Zend\View\Helper\Navigation as Helper_Navigationをインスタンス化する際に前述したエラーとなるため、教えていただいた方法を試すことが出来ない状況ではあります。
use Zend\View\Helper\Navigation as Helper_Navigation;
$this->_helper_navigation = new Helper_Navigation();
プログラムをお渡しすることもできますので、もしもう少しお力を貸していただけるのでしたら送り先を教えていただければと思います。
私の方で引続き検証しますので、解決しましたらご連絡させていただきます。
以下のようにして実装すると上手く出来ました。
返信削除$event = new EventManager();
$event->setSharedManager(new SharedEventManager());
$this->_helper_navigation->menu()->setEventManager($event);
>Zend\View\Helper\Navigation as Helper_Navigationをインスタンス化する際に前述したエラーとなるため、教えていただいた方法を試すことが出来ない状況ではあります。
上記のように書きましたが、私の勘違いのようでした。
とりあえずはライブラリに手を付けず対応できましたので、今回の件はとりあえずは解決しました!
何度も回答頂いて本当に助かりました。
もっとzendについて勉強します。
KITAMURA 様
削除お世話になります。
この度はご報告頂き、誠に有難うございます。
動作した様で何よりです。
zend frame workはライブラリで使用できますが、
仕組みを知っていないと使いこなすのが難しいですね。
そういった難しい所を吸収してくれるのが
フレームワークとしての利用といった所でしょうか。
他にも、何かご不明な点が御座いましたら
お気軽にご連絡下さい。
今後ともよろしくお願いいたします。
こんにちは。
返信削除書籍を購入し、ZendFramework2を勉強させて頂いております。
Chapter4のエラーメッセージの日本語化について質問させてください。
書籍にある通りにサービスからtranslatorを取得し、翻訳ファイルをaddTranslationFileメソッドを使用して設定しましたがエラーメッセージが日本語に変換されてくれません。
取得したtranslatorのtranslateメソッドを直接実行すると日本語に変換されたエラーメッセージが返ってくることは確認しております。
他に何か設定が必要なのでしょうか。
環境と各バージョンは以下の通りです。
OS:Windows7 Professional 64bit
Webサーバ:Apache 2.4.9
PHP:5.5.14
ZendFramework:2.3.1
お忙しいこととは思いますが、どうかよろしくお願い致します。
Naoki Aida 様
削除お世話になります。
この度は書籍のご購入、誠に有難う御座います。
ご質問いただきましたメッセージの翻訳に付きましてですが、
こちらで色々と試しましたが再現させることが出来ませんでした。
もしかすると、新しいZF2では翻訳関係の処理に修正が加わっているようですので、
その辺りが影響しているのかな?っと想像します。
可能な限りで良いので、実際のコードの開示、
もしくは、もう少しソースレベルの詳しい情報を教えて頂ければ幸いです。
何卒、宜しくお願い致します。
濱田様
削除お世話になっております、Naoki Aidaです。
このたびは返信が非常に遅くなってしまい、本当に申し訳ありません。
Gmailのアカウントでコメントさせて頂きましたが、Gmal自体に使い慣れておらず、返信コメントを頂いたことを今知りまして、慌てて返信を書いている次第であります。
質問当時は書籍にあるサンプルコードを直接打って作成したサンプルプロジェクトで、
書籍の説明にある以外の改造は行っておりませんでした。
現在、当方の事情によりZendFramework2に触れる時間が取れておりません。
再度時間が取れましたら、改めて再現したかしないかといった報告をさせて頂きたいと思います。
この度はご迷惑をお掛け致しました。
今後ともよろしくお願い致します。
濱田様
返信削除前回はありがとうございました。
コメントしたつもりが投稿できてなかったみたいなので再度投稿します。
※二重投稿になってましたら申し訳ありません。
今回Aclを利用して、ページの制限をかけているのですが、
Aclで設定してリソースのアクセス権限を判定する際に、
アクセスしているリソース自体の取得はどのように行うのが良いのでしょうか?
各コントローラーでリソースの設定を行うのは毎回必要になるので面倒だと思います。
何か、zend_navigationを使用しているのでその辺りと絡めてうまく出来ないかなとは思っているのですが。
zendで実装する場合のセオリーがある場合は教えていただけたら幸いです。
※navigationのリンクはuriで設定しています。
※controller等はzendのroute等の設定が必要そうなので
よろしくお願いいたします。
KITAMURA 様
削除お世話になります。
この度はコメント頂きまして、誠にありがとう御座います。
navigationに対してAclの設定を追加したいという事でよろしいでしょうか?
echo $this->navigation('Navigation')->setAcl($this->acl)->setRole('guest');
もしかすると、下記の記事が参考になるかもしれません。
http://www.ivangospodinow.com/zend-framework-2-navigation-with-acl/
>アクセスしているリソース自体の取得
「アクセスしているリソース自体」というのが、少し分からないのですが、
Aclがもつ「getResource($resource)」と、リソース自体が持つ「getResourceId()」を使用して
リソースを取得することが出来ます。
もし、的外れな回答でしたら、お手数おかけしますが
再度ご連絡頂ければ幸いです。
今後ともよろしくお願い致します。
濱田様
削除返信有難うございます。
例えばですが、以下のメニューとNavigation,及びAclでリソースの設定をしているとします。
・ユーザー管理(リソース名 user)
・記事編集(リソース名 article)
・設定(リソース名 setting)
記事編集ページにアクセス時は、ユーザーのロールを取得し、リソースarticleの権限の有無をチェックするかと思います。
その際に実際にarticleリソースにアクセスしていることをどのように判断するのがセオリーになるのかなと思っております。
コントローラファイルでリソースを設定するのか、
navigationに渡すpage情報とURLから自動で取得できるのか、
どの方法がよいか悩んでいるという状況です。
よろしくお願いいたします。
失礼しました。 自己解決いたしました。
返信削除C:\xampp\ZendSkeleton\templates_c
にキャッシュが残っていたようです。 (初歩の初歩でした。)
古いキャッシュを削除することで、解決できました。
使いこなせるようになるまで、まだまだ前途多難ですが、今後ともどうぞよろしくお願い致します。
YOSHIHARA様
返信削除お世話になります。
この度は書籍のご購入、及びコメント頂きまして
誠にありがとうございます。
また、お返事遅くなり大変申し訳ございません。
解決報告もご丁寧にありがとうございます。
他にも、何かご不明な点が御座いましたら
お気軽にコメント頂ければ幸いです。
今後ともよろしくお願いいたします。
お世話になります。 連日の投稿で申し訳ございません。
返信削除まだ、本書の意図をくみとれず、苦慮しております。
p74-p76にあります、(code 3-70)(code 3-71)の扱いについて質問させてください。
同コードの設置場所とファイル名をご示唆いただけませんでしょうか。
module.config.php ファイル内'controllers' に
'controllers' => array(
'invokables' => array(
'Application\Controller\Index' => 'Application\Controller\IndexController',
'Application\Controller\User' => 'Application\Controller\UserController',
'Application\Controller\Article' => 'Application\Controller\ArticleController',
),
),
と追記し
(code 3-70)記載したArticleController.phpを
\module\Application\src\Application\Controller内に格納
C:\xampp\ZendSkeleton\module\Application\view\application\article
の中に
(code 3-71)のコードを記載したarticle.phtmlを格納
しましたが、
画面に変化があらわれません。((code 3-70)の画面が白く変化した状態です)
当方の設定ミスでしょうか?
YOSHIHARA様
返信削除お世話になります。
この度はコメント頂き、誠に有難う御座います。
viewの中にviewを含める箇所についてのご質問かと思いますが、
article.phtml内に含めたい他のviewはcontroller側で指定した
パスに配置していますでしょうか?
ArticleController内では、
テンプレートとして出力するarticle.phtmlに対して
他のビューファイルを追加する様に指定しているはずですので、
念のために配置したビューファイルのパスをご確認頂ければ幸いです。
他にも、何かご不明な点が御座いましたら
お気軽にコメント頂ければ幸いです。
今後とも宜しくお願い致します。
濱田様
返信削除お世話になります。
「ZendFramework2 徹底解説」、なんとか4章まできましたが、再び躓いてしまいました。
P144)「きちんと値をいれて投稿すれば問題なくデータベースへレコードが追加されます。」
とありますが、次ページ(http://localhost/ZendSkeleton/application)へ画面は遷移するものの、
データベース(zend_db/user)に値を渡すことができないでいます。
第3章から何度も何度も繰り返し設定しなおしても、得られる結果は同じです。
各ファイルに、ダウンロードしたSampleデータをコピーペーストしても同様の結果です。
第3章の設定まででは、ちゃんと値はデータベースに格納されます。
また、同ページの「図4-3:エラーメッセージ」についてすが、
入力欄の下に英語のエラーメッセージが表示されるのではなく、
「@に続く文字列を入力してください。「XXX@」は完全なメールアドレスではありません」
と日本語で表示されまます。
またキーワードは空欄のままでもエラーメッセージは表示されず、
空欄まま次ページへと遷移します。
上記をふまえ、どうすれば、貴書のような動作が実現するのか、
P144までの設定漏れ等ございましたら、ご教示いただけませんでしょうか。
どうぞよろしくお願いいたします。
※ 開発環境はWin7prpにて
xampp-win32-1.8.2-6
ZendFramework-2.3.3
を使用しております。
YOSHIHARA 様
削除お世話になります。
この度はコメント頂きまして、誠に有難う御座います。
>P144)「きちんと値をいれて投稿すれば問題なくデータベースへレコードが追加されます。」
>とありますが、次ページ(http://localhost/ZendSkeleton/application)へ画面は遷移するものの、
>データベース(zend_db/user)に値を渡すことができないでいます。
P144はログイン認証周りの解説で、「きちんと値をいれて投稿すれば問題なくデータベースへレコードが追加されます。」の記述が見当たらないのですが、ページ番号は正しいでしょうか?
また、値を渡すことが出来ないというのは、DBに値が保存されていないのに遷移してしまうという事でしょうか?
関係があるかわかりませんが、サンプルソースに一部誤りがありました。
もし、最新の状態になっていない場合は、下記の内容をご確認頂ければ幸いです。
http://web-terminal.blogspot.jp/2013/11/zendframework2zend-framework-2.html?showComment=1403669102419#c1261076197487629081
>また、同ページの「図4-3:エラーメッセージ」についてすが、
>入力欄の下に英語のエラーメッセージが表示されるのではなく、
>「@に続く文字列を入力してください。「XXX@」は完全なメールアドレスではありません」
>と日本語で表示されまます。
>
>またキーワードは空欄のままでもエラーメッセージは表示されず、
>空欄まま次ページへと遷移します。
上記の「@に続く文字列を入力してください。「XXX@」は完全なメールアドレスではありません」
は、html5の<input type="email">によるエラーメッセージかと思います。
こちらの文言は変更することが出来ませんので、任意のメッセージのみを適用させたい場合は
inputをtextにします。(html5の検証は値の送信前に行われますので、たとえemailでhtml5の検証を行ったとしても、偽装送信に耐える為にも送信後にもチェックすべきです。)
空欄に関しては、Formにて空欄チェックを行う必要があるかと思います。
単純に必須項目としたい場合は、フィルタのrequiredにtrueをセットします。
こちらで解答となりましたでしょうか?
他にも、何かご不明な点が御座いましたら
お気軽にコメント下さい。
今後とも、何卒宜しくお願い致します。
濱田様
返信削除お忙しいところご説明いただきありがとうございます。
また、記載したページ番号に誤りがあり、大変失礼致しました。
「きちんと値をいれて投稿すれば問題なくデータベースへレコードが追加されます。」の記載は
P144 ではなく、P114でした。
下記、インラインで失礼いたします。
>値を渡すことが出来ないというのは、DBに値が保存されていないのに遷移してしまうという事でしょうか?
はい。おっしゃるとおり、の状況でした。
>空欄に関しては、Formにて空欄チェックを行う必要があるかと思います。
>単純に必須項目としたい場合は、フィルタのrequiredにtrueをセットします。
ありがとうございます。了解いたしました。
いろいろお聞きしているなか、恐縮なのですが。
昨夜、より根本的なところからZendを理解しなおそうと考え、
従来のXamppをいったんアンインストールし、
Zend1.8 / Xampp1.7 でインストールして勉強を開始しました。
ある程度、上記の流れをつかんだのち、
改めて貴書で学習しなおしたいと思います。
もし勉強会等開催されることがありましたら、是非とも参加させていただきたい所存です。
YOSHIHARA 様
削除お世話になります。この度はコメント頂きまして、誠に有難う御座います。
P114の内容で、値が保存されずに遷移してしまう事を考えると、
バリデーションは通過し、処理は問題なく通っているが、何処かしらで空の値となってしまうとすれば、
exchangeArray()内で正しく値を受け取れているか?正しくフォームからユーザーオブジェクトへ変換出来ているか?をログ等で確認してみて下さい。
次に疑うべき箇所は、ちゃんと狙ったキーでポストされてきているか?
こちらもログで吐くなり、リクエストのヘッダー情報などで確認してみて下さい。
ビュー側で指定したキーと、フォーム側、もしくはexchangeArray()内で指定しているキーと異なる場合があります。
他にも何か御座いましたら
お気軽にコメント下さい。
今後とも宜しくお願い致します。
濱田様
返信削除書籍を購入して勉強を始めました。
スケルトンプロジェクトの導入で1点よく分からなかったので、コメントさせて頂きました。
このページでは、index.phpにinclude_pathの設定と環境変数ZF2_PATHの設定を追加していますが、書籍の対応する部分では、環境変数の設定のみが追加されています。
実際、私の環境でも、include_pathの設定を削っても動作しているように見えますが、include_pathの設定は不要なのでしょうか。
ご教示頂けますと幸いです。
よろしくお願いいたします。