Zend Framework 2-介紹我們第一個“博客” Module

2018-09-28 20:19 更新

介紹我們第一個“博客” Module

現(xiàn)在我們已經(jīng)對 Zend Framework 2 骨架應(yīng)用程序有所了解,讓我們繼續(xù)來創(chuàng)建我們自己的模塊。我們會創(chuàng)建一個名為“博客”的模塊。這個模塊會顯示一個代表每個博客帖子的數(shù)據(jù)庫條目清單。每個帖子都有三個屬性:id,texttitle。我們會創(chuàng)建用于提交新帖子到數(shù)據(jù)庫中的表單,和修改現(xiàn)有帖子的表單。另外在我們整個快速開始指南中都會使用最佳實(shí)踐。

編寫一個新 Module

首先我們在 /module 目錄下創(chuàng)建一個新文件夾名為 blog

為了能讓其被 ModuleManager 認(rèn)作是模塊,我們只需要在目標(biāo)module 的名稱空間(Blog)中創(chuàng)建一個名為 Module 的 PHP 類。創(chuàng)建文件 /module/Blog/Module.php

 <?php
 // 文件名: /module/Blog/Module.php
 namespace Blog;

 class Module
 {
 }

現(xiàn)在我們擁有一個可以被 ZF2 的 ModuleManager 偵測到的 module 了。讓我們將這個 module 添加到我們應(yīng)用程序中。雖然這個 module 目前還不能干任何事情,但僅僅擁有 Module.php 類已經(jīng)能讓其被 ZF2 的 ModuleManager 載入。要實(shí)現(xiàn)這點(diǎn),在主應(yīng)用程序配置文件 /config/application.config.php 中內(nèi)的 module 數(shù)組中為 Blog 添加一個條目:

 <?php
 // 文件名: /config/application.config.php
 return array(
     'modules' => array(
         'Application',
         'Blog'
     ),

     // ...
 );

如果你刷新你的應(yīng)用程序你應(yīng)該看不見任何改變(也沒有任何錯誤)。

這個時候,我們有必要回頭討論一下 module 到底是做什么的。簡而言之,一個 module 是您的應(yīng)用程序的一個被封裝的功能集合。一個 module 可以為您的應(yīng)用程序添加可見功能,像我們的博客 module;一個 module 也可以為應(yīng)用程序內(nèi)的其他 module 提供背景功能,例如和第三方 API 進(jìn)行互動。

將您的代碼組織成 module 形式有利于讓您輕松地重用其他應(yīng)用程序中的功能,或者使用社區(qū)提供的 module。

配置 Module

我們要做的下一件事情就是為我們的應(yīng)用程序添加一個路徑,這樣就能通過 URL localhost:8080/blog 來訪問我們的 module。要實(shí)現(xiàn)這點(diǎn),需要為我們的 module 添加路由配置,但首先我們需要讓 ModuleManager 知道我們的 module 具有這些需要載入的配置表。

添加一個 getConfig() 函數(shù)到 Module 類中,并讓其返回配置。(這個函數(shù)是在 ConfigProviderInterface 中聲明的,盡管實(shí)際上是否要實(shí)現(xiàn)這個接口是可選的) 這個函數(shù)應(yīng)該能返回一個 array 或者一個 Traversable 對象。繼續(xù)編輯您的/module/Blog/Module.php:

<?php
 // 文件名: /module/Blog/Module.php
 namespace Blog;

 use Zend\ModuleManager\Feature\ConfigProviderInterface;

 class Module implements ConfigProviderInterface
 {
     public function getConfig()
     {
         return array();
     }
 }

做到這里我們的 Module 就可以被配置了。配置文件可能會變得十分大,此時將所有東西放在 getConfig() 中就不是最佳手段了。為了保持我們的工程的組織清晰,我們會將數(shù)組配置放在單獨(dú)的文件中。在此我們創(chuàng)建 /module/Blog/config/module.config.php

 <?php
 // 文件名: /module/Blog/config/module.config.php
 return array();

現(xiàn)在我們來重寫 getConfig() 函數(shù)來添加這個剛剛建立的新文件。

<?php
 // 文件名: /module/Blog/Module.php
 namespace Blog;

 use Zend\ModuleManager\Feature\ConfigProviderInterface;

 class Module implements ConfigProviderInterface
 {
     public function getConfig()
     {
         return include __DIR__ . '/config/module.config.php';
     }
 }

重新裝載您的應(yīng)用程序,這是你便會見到所有東西仍然和之前一樣,接下來我們給配置文件添加一個新路徑:

<?php
 // 文件名: /module/Blog/config/module.config.php
 return array(
     // 該行為 RouteManager 打開配置
     'router' => array(
         // 打開所有可能路徑的配置O
         'routes' => array(
             // 定義一個新路徑,稱為 "post"
             'post' => array(
                 // 定義一個路徑 "Zend\Mvc\Router\Http\Literal" , 基本上就是一個字符串
                 'type' => 'literal',
                 // 配置路徑本身
                 'options' => array(
                     // 監(jiān)聽 uri "/blog" 
                     'route'    => '/blog',
                     // 定義默認(rèn)控制器和當(dāng)這個路徑匹配時需要執(zhí)行的動作
                     'defaults' => array(
                         'controller' => 'Blog\Controller\List',
                         'action'     => 'index',
                     )
                 )
             )
         )
     )
 );

現(xiàn)在我們添加了一個叫做 blog 的路徑,該路徑負(fù)責(zé)監(jiān)聽 URL localhost:8080/blog。每當(dāng)有人訪問這個路徑時,Blog\Controller\List 類中的 indexAction() 函數(shù)就會被執(zhí)行。不過,這個控制器暫時還不存在,所以如果你重新裝載頁面你就會看見這個錯誤信息:

 A 404 error occurred
 Page not found.
 The requested controller could not be mapped to an existing controller class.

 Controller:
 Blog\Controller\List(resolves to invalid controller class or alias: Blog\Controller\List)
 No Exception available

現(xiàn)在我們需要告訴 module 要去哪里尋找這個叫做 Blog\Controller\List 的控制器。要做到這點(diǎn)我們必須將這個 key 添加到 controllers 配置 key,在 /module/Blog/config/module.config.php 內(nèi)。

 <?php
 // 文件名: /module/Blog/config/module.config.php
 return array(
     'controllers' => array(
         'invokables' => array(
             'Blog\Controller\List' => 'Blog\Controller\ListController'
         )
     ),
     'router' => array( /** Route Configuration */ )
 );

這個配置文件定義了 Blog\Controller\List 是在名稱空間 Blog\Controller 下的 ListController 的別名。重新裝載頁面應(yīng)該會看見以下信息:

( ! ) Fatal error: Class 'Blog\Controller\ListController' not found in {libPath}/Zend/ServiceManager/AbstractPluginManager.php on line {lineNumber}

這個錯誤告訴我們應(yīng)用程序知道要載入哪個類,但是并不知道在哪里能找到它。要修正這個問題,我們需要為我們的 Module 配置 autoloading。 Autoloading 是一個過程,讓 PHP 能自動根據(jù)需求載入類。至于我們的 Module,我們通過添加 getAutoloaderConfig() 函數(shù)到我們的 Module 類來實(shí)現(xiàn)這點(diǎn)。(這個函數(shù)是在 AutoloaderProviderInterface 中定義的,盡管實(shí)際上類是否要實(shí)現(xiàn)這個接口是可選的)

 <?php
 // 文件名: /module/Blog/Module.php
 namespace Blog;

 use Zend\ModuleManager\Feature\AutoloaderProviderInterface;
 use Zend\ModuleManager\Feature\ConfigProviderInterface;

 class Module implements
     AutoloaderProviderInterface,
     ConfigProviderInterface
 {
     /**
      * 返回一個 array 傳給 Zend\Loader\AutoloaderFactory.
      *
      * @return array
      */
     public function getAutoloaderConfig()
     {
         return array(
             'Zend\Loader\StandardAutoloader' => array(
                 'namespaces' => array(
                     // Autoload 所有類從名稱空間 'Blog' 來自于 '/module/Blog/src/Blog'
                     __NAMESPACE__ => __DIR__ . '/src/' . __NAMESPACE__,
                 )
             )
         );
     }

     /**
      * 返回配置來和應(yīng)用程序配置合并
      *
      * @return array|\Traversable
      */
     public function getConfig()
     {
         return include __DIR__ . '/config/module.config.php';
     }
 }

這看上去好像很多東西被改變了,不過不用害怕。我們已經(jīng)添加了一個 getAutoloaderConfig() 函數(shù)來提供Zend\Loader\StandardAutoloader 的配置。這個配置文件告訴應(yīng)用程序 __NAMESPACE__ (Blog) 中的類都能在 __DIR__.'/src/'.__NAMESPACE__中找到 (/module/Blog/src/Blog)。

Zend\Loader\StandardAutoloader 使用了 PHP 社區(qū)領(lǐng)導(dǎo)的標(biāo)準(zhǔn),稱為PSR-0https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md)。在其他東西之中,這個標(biāo)準(zhǔn)為 PHP 定義了一個方法來映射類名稱到文件系統(tǒng)。所以有了這個配置后,應(yīng)用程序就知道我們的 Blog\Controller\ListController 類應(yīng)該在 /module/Blog/src/Blog/Controller/ListController.php 中存在。

如果你現(xiàn)在刷新瀏覽器,你還是會見到同樣的錯誤,即使我們已經(jīng)配置了 autoloader,因?yàn)槲覀冞€需要創(chuàng)建控制器類。我們立刻創(chuàng)建這個文件:

 <?php
 // 文件名: /module/Blog/src/Blog/Controller/ListController.php
 namespace Blog\Controller;

 class ListController
 {
 }

再次重新載入頁面,現(xiàn)在我們終于看見不一樣的內(nèi)容了。新的錯誤信息(類似下文):

 A 404 error occurred
 Page not found.
 The requested controller was not dispatchable.

 Controller:
 Blog\Controller\List(resolves to invalid controller class or alias: Blog\Controller\List)

 Additional information:
 Zend\Mvc\Exception\InvalidControllerException

 File:
 {libraryPath}/Zend/Mvc/Controller/ControllerManager.php:{lineNumber}
 Message:
 Controller of type Blog\Controller\ListController is invalid; must implement Zend\Stdlib\DispatchableInterface

這是因?yàn)槲覀兊目刂破鞅仨殞?shí)現(xiàn) ZendStdlibDispatchableInterface 接口才能被 ZendFramework 的 MVC 層運(yùn)行。ZendFramework 提供了一些該接口的基礎(chǔ)控制器實(shí)現(xiàn),叫做 AbstractActionController,我們稍后會用。讓我們先修改我們的控制器:

 <?php
 // 文件名: /module/Blog/src/Blog/Controller/ListController.php
 namespace Blog\Controller;

 use Zend\Mvc\Controller\AbstractActionController;

 class ListController extends AbstractActionController
 {
 }

是時候再次刷新站點(diǎn)的頁面了,您應(yīng)該會看見有一個新的錯誤消息:

 An error occurred
 An error occurred during execution; please try again later.

 Additional information:
 Zend\View\Exception\RuntimeException

 File:
 {libraryPath}/library/Zend/View/Renderer/PhpRenderer.php:{lineNumber}
 Message:
 Zend\View\Renderer\PhpRenderer::render: Unable to render template "blog/list/index"; resolver could not resolve to a file

現(xiàn)在應(yīng)用程序告訴你一個視圖模板文件沒法被渲染,這也是可預(yù)見的,畢竟我們還沒有將其創(chuàng)建。應(yīng)用程序期望它在 /module/Blog/view/blog/list/index.phtml 這個位置。創(chuàng)建這個文件并且放置一些假內(nèi)容在上面:

 <!-- Filename: /module/Blog/view/blog/list/index.phtml -->
 <h1>Blog\ListController::indexAction()</h1>

在我們繼續(xù)之前,先讓我們快速的看一下我們將該文件放置在何處。請注意視圖文件是放置在 /view 子目錄下的,并不是在 /src 子目錄下,因?yàn)樗麄儾皇?PHP 類文件,而是用于渲染 HTML 的模板文件。下面的路徑需要一些解釋,不過也非常簡單。首先我們有全小寫的名稱空間,跟著一個小寫的控制器名稱(沒有后綴‘controller’),最后跟上我們正在訪問的動作的名稱(同樣地,沒有后綴‘a(chǎn)ction’)??偟膩砜聪襁@樣:/view/{namespace}/{controller}/{action}.phtml。這已經(jīng)成為了社區(qū)標(biāo)準(zhǔn),不過也有潛在的隨時被你改變的可能。不過光是創(chuàng)建這個文件是不夠的,這就帶出了這次快速開始指南的最后主題:我們需要讓應(yīng)用程序知道上哪去尋找視圖文件。通過修改我們的 module 配置文件 module.config.php 來實(shí)現(xiàn):

 <?php
 // 文件名: /module/Blog/config/module.config.php
 return array(
     'view_manager' => array(
         'template_path_stack' => array(
             __DIR__ . '/../view',
         ),
     ),
     'controllers' => array( /** Controller Configuration */),
     'router'      => array( /** Route Configuration */ )
 );

上面的配置告訴應(yīng)用程序目錄 /module/Blog/view 中擁有視圖文件來匹配上述默認(rèn)樣式。重要的是,你需要記住你不單能將視圖文件指定給您的 module,同時也能用于覆蓋其他 module 的視圖文件。

現(xiàn)在刷新您的站點(diǎn)。終于我們可以看見錯誤消息之外的內(nèi)容了。

恭喜!你不單止創(chuàng)建了一個簡單的“Hello World”風(fēng)格 module,還學(xué)會了許多錯誤消息和他們的起因。如果到現(xiàn)在你還沒被磨死,請繼續(xù)我們的快速開始指南,一起來創(chuàng)建一個能真正干點(diǎn)事情的 module。

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號