トップ 差分 一覧 ソース 検索 ヘルプ PDF RSS ログイン

Zend Framework2

はじめに

ZF1に比べてZF2は初回起動?が激しく遅くなった(汗)。
パフォーマンス比較サイトによると、4倍ぐらい遅くなったらしい。

ま、それはさておき、zf2ではサービスやらイベントを登録するタイプになった。
それによりプログラミングの自由度が上がった...気がするが、単に難解になっただけのような気もする(汗)。

とりあえずポータルサイトを作るのに「新技術先取り!」的な感じではじめてみたが、ぶっちゃけzf1のほうが簡単だし応答も早い気がするのは言わないことにしよう。

download

とりあえずZF2でMVCを構築するなら、スケルトンをダウンロードしていじったほうが早い?

ZendSkeleton
https://github.com/zendframework/ZendSkeletonApplication

スケルトンのダウンロード(取得)方法はcurlとgitの方法が紹介されている。
まずはskeletonのzipをダウンロード。

適切な場所に解凍したら、コマンドプロンプトよりそのフォルダに入って

php composer.phar self-update
php composer.phar install

でZF2のライブラリをvenderにダウンロードできる。

ここではcomposerを使わずにZendFramework-minimal-2.*.*.zipをダウンロードし、vender/ZF2にlibraryを配置することにする。

ZF2
http://framework.zend.com/downloads/latest

こんな感じ(vender/ZF2にlibraryを配置する場合)。

├config
├data
├public
├module
└vender
  └ZF2
    └library
      └Zend
        ├Authentication
        :

publicをドキュメントルートに設定すれば、動作を確認できる。

で、この時点でトップページの表示が激遅w
トランスレータ(言語切り替え)が遅いのかと思って外してみたが、大差なかった。

Reference Guide of ZF2

Programmer’s Reference Guide of Zend Framework 2
http://zf2.readthedocs.org/en/latest/

MVCの流れ

publicをドキュメントルートにすることで

public/.htaccess

が読み込まれ、mod_rewriteの設定によって

index.php

にリクエストが集約される。
リクエストされたファイルが実在している場合はそちらが優先なのはZF1と一緒。

require 'init_autoloader.php';
Zend\Mvc\Application::init(require 'config/application.config.php')->run();

init_autoloader.phpではZF2のlibraryへのパスを設定、config/application.config.phpの設定でMVCが実行される。
モジュールを追加した場合はconfig/application.config.phpをいじることになる。

config/application.config.phpでいじるようなところはmodulesぐらい?
初期モジュールはApplicationで

return array(
    'modules' => array(
        'Application',
        'Foo',
        'Bar',
        'Baz',
    ),

のように、モジュールを追加した場合に増やしていく。

ここで読み込まれる設定になっているconfig/autoload/global.phpとlocal.phpのあたりで、DB接続を設定する模様。

ZF2 database and modules
http://framework.zend.com/manual/2.0/en/user-guide/database-and-models.html

 複数DB接続

configure multiple databases in zf2
http://stackoverflow.com/questions/14003187/configure-multiple-databases-in-zf2

 event

MvcEvent::EVENT_BOOTSTRAP
MvcEvent::EVENT_DISPATCH
MvcEvent::EVENT_DISPATCH_ERROR
MvcEvent::EVENT_FINISH
MvcEvent::EVENT_RENDER
MvcEvent::EVENT_ROUTE

Model

コントローラ内でdbAdapterを取得し、TableGatewayを使ってMyModelを作る方法。

コントローラ

use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
use Zend\Db\TableGateway\TableGateway;
use MyModule\Model\MyModel;

class IndexController extends AbstractActionController
{

    public function testAction()
    {
        $dbAdapter = $this->getServiceLocator()->get('Zend\Db\Adapter\Adapter');
        $tableGateway = new TableGateway('table_name', $dbAdapter);
        $myModel = new MyModel($tableGateway);

        return new ViewModel(array(
            'myModel' => $myModel->fetchAll(),
        ));
    }
    :

モデル

namespace MyModule\Model;

use Zend\Db\TableGateway\TableGateway;

class MyModel
{
    protected $tableGateway;

    public function __construct(TableGateway $tableGateway)
    {
        $this->tableGateway = $tableGateway;
    }

    public function fetchAll()
    {
        $resultSet = $this->tableGateway->select();
        return $resultSet;
    }
    :

router

Sampleモジュールを用意したとき

/sample/:controller/:action/:id

でアクセスさせる場合、
module\Sample\config\module.config.phpで

'router' => array(
    'routes' => array(
        'sample' => array(
            'type'    => 'segment',
            'options' => array(
                'route'    => '/sample[/:controller][/:action][/:id]',
                'constraints' => array(
                    'controller' => '[a-zA-Z][a-zA-Z0-9_-]*',
                    'action'     => '[a-zA-Z][a-zA-Z0-9_-]*',
                    'id'         => '[0-9]+',
                ),
                'defaults' => array(
                    'controller' => 'Sample\Controller\Sample',
                    'action'     => 'index',
                ),
            ),
        ),
    ),
),

とすると、

/sample/:controller

の時点ですでにアクセスできない。
defaultsをnamespaceとcontrollerに分けると有効になる模様。

'router' => array(
    'routes' => array(
        'sample' => array(
            'type'    => 'segment',
            'options' => array(
                'route'    => '/sample[/:controller][/:action][/:id]',
                'constraints' => array(
                    'controller' => '[a-zA-Z][a-zA-Z0-9_-]*',
                    'action'     => '[a-zA-Z][a-zA-Z0-9_-]*',
                    'id'         => '[0-9]+',
                ),
                'defaults' => array(
                    '__NAMESPACE__' => 'Sample\Controller',
                    'controller' => 'Sample',
                    'action'     => 'index',
                ),
            ),
        ),
    ),
),

アクションなら

'route'    => '/sample[/:action][/:id]',
:
'defaults' => array(
    'controller' => 'Sample\Controller\Sample',
    :

コントローラー/アクションなら

'route'    => '/sample[/:controller][/:action][/:id]',
:
'defaults' => array(
    '__NAMESPACE__' => 'Sample\Controller',
    'controller' => 'Sample',
    :

layout

content内で任意のheaderやfooterファイルを組み込む例。

application/view/layout.phtml

<html>
<head>
<meta ... />
</head>

<body>
<div id="header"><?php echo $this->header ?></div><!-- #header -->
<div id="content"><?php echo $this->content ?></div><!-- #content -->
<div id="footer"><?php echo $this->footer ?></div><!-- #footer -->
</body>
</html>

foo/view/bar/bar/header.phtml
foo/view/bar/bar/foober.phtml

foo/view/bar/bar/index.phtml

<?php
$title = 'サンプル';
$this->headTitle($title);

$this->layout()->header = $this->partial('bar/bar/header.phtml');
$this->layout()->footer = $this->partial('bar/bar/footer.phtml');
?>
<h1><?php echo $this->escapeHtml($title) ?></h1>
<p>ただいま試作中</p>

View

http://framework.zend.com/manual/2.0/en/modules/zend.view.helpers.html

<?php echo $this->doctype() ?>
<?php echo $this->headTitle() ?>
<?php echo $this->headMeta()->appendName('foo', 'bar') ?>
<?php echo $this->headLink(array('rel' => '', 'type' => '', 'href' => $this->basePath() . '')
    ->prependStylesheet($this->basePath() . 'css/foo.css')
    ->prependStylesheet($this->basePath() . 'css/bar.css') ?>
<?php echo $this->url('home') ?>
<?php echo $this->translate('Hello World') ?>
<?php echo $this->content ?>
<?php echo $this->inlineScript() ?>

 Layoutを無効にする

class IndexController extends ActionController
{
    public function indexAction()
    {
        $viewModel = new ViewModel();
        $viewModel->setTerminal(true);
        return $viewModel;
    }
}
evan.pro - ZF2 Training at PHPNW12
http://blog.evan.pro/tag/zend-framework

Controller

パラメータを取得する

$routeMatch = $this->getEvent()->getRouteMatch();
$id = $routeMatch->getParam('id', 0);
$this->params()->fromPost('paramname');   // From POST
$this->params()->fromQuery('paramname');  // From GET
$this->params()->fromRoute('paramname');  // From RouteMatch
$this->params()->fromHeader('paramname'); // From header
$this->params()->fromFiles('paramname');  // From file being uploaded
How to access route, post, get etc. parameters in Zend Framework 2
http://stackoverflow.com/questions/12077126/how-to-access-route-post-get-etc-parameters-in-zend-framework-2

モジュール名を取得する

$moduleName = $this->getEvent()->getRouteMatch()->getMatchedRouteName();
// or
$moduleName = strtolower(__NAMESPACE__);

コントローラ名を取得する

$param = strtolower($this->getEvent()->getRouteMatch()->getParam('controller', 'NA'));
$param = explode('\\', $param);
$moduleName = $param[0];
$controllerName = $param[2];

アクション名を取得する

$actionName = $this->getEvent()->getRouteMatch()->getParam('action', 'NA');

サービスを取得する

$foo = $this->getServiceLocator()->get('サービス名');

コントローラ内で共通の処理を記述する(ZF1ではinit()だった)

public function __construct()
{
    // 共通の処理
    // (この時点ではroutematchされていない)
}

ZF1のpreDispatch()と同等の処理をZF2に追加する

Module.php、もしくはcontrollerのsetEventManager()で

$events->attach('dispatch', function($e) use ($controller) {
    if(method_exists($controller, 'preDispatch')) {
        $controller->preDispatch();
    }
}, 100);

のような感じでZF1のpreDispatch()を再現できる。
actionのpriorityが1なので、それ以上ならpreDispatch()、それ以下ならpostDispatch()
とか。

レイアウトを無効にする

public function fooAction()
{
    $viewModel = new ViewModel();
    $viewModel->setTerminal(true);
    return $viewModel;
}

テンプレート出力自体を行わない

public function fooAction()
{
    return $this->getResponse();
    // or
    return $this->getResponse()->setStatusCode(200)->setContent('fooAction');
}

validatorでlocaleエラーがでる(XAMPP

php.ini

php_intl.dll
php_openssl.dll

phpにあるicu??46.dllをapache/binにコピーし、xamppを再起動。

ZendSkeletonでvender/ZF2/libraryが読めなくなった

なんでそういうことすんの?

Remove the submodule option as the ZF2 repository is now a meta package
https://github.com/zendframework/ZendSkeletonApplication/commit/86cebded6587006e4d2639d7d8ed1e82785e3143

/module/Application/config/module.config.phpでsyntax error

新しいスケルトンでなんかsyntax errorなんですけど? と調べたら

Application config with PHP 5.5 ::class style
https://github.com/zendframework/ZendSkeletonApplication/commit/2c9e759f873b7763c4437c019d45b780dbc6fefb

PHP 5.5 ::class style」じゃねーよヴォケがw
本家でPHP 5.3+だって言ってんだろ。

Overview - Introduction to Zend Framework 2
http://framework.zend.com/manual/current/en/ref/overview.html

と思ったら、こういう流れなの?

Fixes zf2-documentation/#1516
https://github.com/samsonasik/zf-web/commit/2b9fc83db2998d12e5dc72e574109658f3c448f2