Zend Frameworkの概要(続き)

Zend Frameworkのストーリーを継続します。 記事の最初の部分では、MVCソフトウェアアーキテクチャの概念について説明し、Zend Frameworkに基づく典型的なWebアプリケーションの構造を調べ、コントローラーのデモ実装とそれに基づくビューを作成しました。 2番目の部分では、モデルのトピックを明らかにし、データベースとアプリケーションの相互作用の例を示します。

投稿者: Rob Allen、 akrabat.com
オリジナル: akrabat.com/zend-framework-tutorial
翻訳:アレクサンダー・ムサエフ、 musayev.com

データベース


アプリケーションの制御部分と視覚化コードが分離されたので、今度はモデルに取り組みます。 モデルは、その基本機能を実装するアプリケーションの基本部分であることに注意してください。 したがって、この場合、モデルはデータベースを使用して作業を実行します。 データベーステーブルのレコードを検索、挿入、更新、削除するために設計されたZend FrameworkクラスZend_Db_Tableを使用します。

カスタマイズ


Zend_Db_Tableを使用するには、どのデータベース、どのユーザー名、どのパスワードでアクセスするかを彼に伝える必要があります。 この情報をコードに打ち込まないことが望ましいことを考慮して、構成ファイルを使用して保存します。

Zend Frameworkは、この目的のためにZend_Configクラスを提供しZend_Config 。これにより、INIおよびXML形式の構成ファイルへの柔軟なオブジェクト指向アクセスが提供されます。 INIファイルで停止しましょう:

zf-tutorial/application/config.ini:

 [general] db.adapter = PDO_MYSQL db.config.host = localhost db.config.username = rob db.config.password = 123456 db.config.dbname = zftest 

(もちろん、例に示されているものではなく、独自のデータベースアクセスパラメータを使用する必要があります。)

Zend_Configは非常に簡単です:

 $config = new Zend_Config_Ini('config.ini', 'section'); 

この場合、 Zend_Config_IniはINIファイルから1つのセクションを読み込みます(必要に応じて他のセクションを読み込むこともできます)。 セクションに名前を付ける機能が実装されているため、不必要なデータが不必要にロードされることはありません。 Zend_Config_Iniは、パラメーター名にピリオドを階層的な区切り記号として使用するため、関連するパラメーターをグループ化できます。 config.iniファイルでは、パラメーターhostusernamepassword 、およびdbname$config->db->configオブジェクトにグループ化されます。

ブートストラップファイル( index.php )から構成ファイルをロードします。

zf-tutorial/index.php:

 ... Zend_Loader::loadClass('Zend_Controller_Front'); Zend_Loader::loadClass('Zend_Config_Ini'); Zend_Loader::loadClass('Zend_Registry'); // load configuration $config = new Zend_Config_Ini('./application/config.ini', 'general'); $registry = Zend_Registry::getInstance(); $registry->set('config', $config); // setup controller ... 

操作に必要なクラス( Zend_Config_IniおよびZend_Registry )を読み込んだ後、 general呼ばれる設定ファイルapplication/config.iniセクションが$configオブジェクトに読み込まれます。 次に、レジストリに$configオブジェクトが含まれます。これにより、アプリケーション全体からアクセスできます。

注:この例では、 $configをレジストリに保存する必要はありません。 これは、「実際の」アプリケーションの動作の例として行われます。その設定ファイルには、おそらくデータベースアクセスパラメータ以外のものを保存する必要があります。 レジストリを使用する場合、レジストリ内のデータはグローバルレベルでアクセス可能であり、不注意に使用すると、アプリケーション内で競合が発生する可能性があることに注意してください。

Zend_Db_Tableを使用する

Zend_Db_Tableクラスを使用するには、ロードされたばかりのデータベースアクセスパラメータを渡す必要があります。 これを行うには、 Zend_Dbオブジェクトを作成し、 Zend_Db_Table::setDefaultAdapter()関数で登録します。 以下は、ブートストラップファイル内の対応するコードスニペットです。

zf-tutorial/index.php:

 ... Zend_Loader::loadClass('Zend_Controller_Front'); Zend_Loader::loadClass('Zend_Config_Ini'); Zend_Loader::loadClass('Zend_Registry'); <b>Zend_Loader::loadClass('Zend_Db'); Zend_Loader::loadClass('Zend_Db_Table');</b> // load configuration $config = new Zend_Config_Ini('./application/config.ini', 'general'); $registry = Zend_Registry::getInstance(); $registry->set('config', $config); <b>// setup database $db = Zend_Db::factory($config->db->adapter, $config->db->config->toArray()); Zend_Db_Table::setDefaultAdapter($db);</b> // setup controller ... 

テーブル作成

MySQLデータベースを使用するため、テーブルを作成するSQLクエリは次のようになります。

 CREATE TABLE album ( id int(11) NOT NULL auto_increment, artist varchar(100) NOT NULL, title varchar(100) NOT NULL, PRIMARY KEY (id) ); 

このクエリは、phpMyAdminや標準コンソールユーティリティなど、MySQLクライアントを介して実行できます。

テストレコードの追加

テーブルにいくつかのテストエントリを追加して、後で表示されるメインページの機能を確認します。

 INSERT INTO album (artist, title) VALUES ('James Morrison', 'Undiscovered'), ('Snow Patrol', 'Eyes Open'); 

モデル


Zend_Db_Tableは抽象クラスであるため、それに基づいて、タスクに特化した継承クラスを作成する必要があります。 新しいクラスの名前は重要ではありませんが、そのようなクラスは、対応するデータベーステーブルと同じ方法で呼び出す必要があります(これにより、コードの自己文書化のレベルが向上します)。 したがって、 albumテーブルのクラス名はAlbumます。

管理するテーブルの名前をZend_Db_Tableに渡すには、この値をクラス$_name保護されたプロパティに割り当てる必要があります。 Zend_Db_Tableクラスは、デフォルトでidという名前のテーブルのキー自動インクリメントフィールドを常に使用することに注意してください。 必要に応じて、このフィールドの名前の値も変更できます。

Albumクラスはモデルディレクトリに保存されます。

zf-tutorial/application/models/Album.php:

 <?php class Album extends Zend_Db_Table { protected $_name = 'album'; } 

複雑なことはありませんか? この場合のニーズは非常に小さいことを考えると、 Zend_Db_Tableの基本機能はそれらを完全に満たすのに十分です。 タスク内でデータベースと対話するより複雑な操作を実装する必要がある場合、モデルクラスは、対応するコードを配置する場所になります。

アルバムリスト


データベースの構成が完了したので、アプリケーションのメインタスクの実行を開始し、いくつかのエントリを表示できます。 これは、 IndexControllerクラスに実装する必要があります。 IndexController内の各アクション関数は、 Albumクラスを介してAlbumテーブルとやり取りします。 したがって、コントローラーをinit()関数内で初期化するときにロードすることは理にかなっています。

zf-tutorial/application/controllers/IndexController.php:

 ... function init() { $this->view->baseUrl = $this->_request->getBaseUrl(); Zend_Loader::loadClass('Album'); } ... 

注:このコードスニペットは、 Zend_Loader::loadClass()メソッドを使用して非標準クラスをロードする例を示しています。 これは、モデルディレクトリ(ロードされたクラスAlbumsが格納されている)がinclude_pathに追加されたために機能しinclude_path

indexAction()を使用して、データベースからアルバムのリストを作成します。

zf-tutorial/application/controllers/IndexController.php:

 ... function indexAction() { $this->view->title = "My Albums"; $album = new Album(); $this->view->albums = $album->fetchAll(); } ... 

fetchAll()関数はZend_Db_Table_Rowsetオブジェクトを返します。これにより、次の形式のテンプレートファイル内のすべてのエントリのリストを作成できます。
zf-tutorial/application/views/scripts/index/index.phtml:

 <?php echo $this->render('header.phtml'); ?> <h1><?php echo $this->escape($this->title); ?></h1> <p><a href="<?php echo $this->baseUrl; ?>/index/add">Add new album</a></p> <table> <tr> <th>Title</th> <th>Artist</th> <th> </th> </tr> <?php foreach($this->albums as $album) : ?> <tr> <td><?php echo $this->escape($album->title);?></td> <td><?php echo $this->escape($album->artist);?></td> <td> <a href="<?php echo $this->baseUrl; ?>/index/edit/id/<?php echo $album->id;?>">Edit</a> <a href="<?php echo $this->baseUrl; ?>/index/delete/id/<?php echo $album->id;?>">Delete</a> </td> </tr> <?php endforeach; ?> </table> <?php echo $this->render('footer.phtml'); ?> 

localhost/zf-tutorial localhost/zf-tutorial 2つのアルバムのリストが表示されます。

新しいアルバムを追加する


それでは、データベースに新しいディスクを追加する機能に移りましょう。 このタスクは2つの部分で構成されます。

addAction() function-actionに上記の操作を実装します。

zf-tutorial/application/controllers/IndexController.php:

 ... function addAction() { $this->view->title = "Add New Album"; if ($this->_request->isPost()) { Zend_Loader::loadClass('Zend_Filter_StripTags'); $filter = new Zend_Filter_StripTags(); $artist = $filter->filter($this->_request->getPost('artist')); $artist = trim($artist); $title = trim($filter->filter($this->_request->getPost('title'))); if ($artist != '' && $title != '') { $data = array( 'artist' => $artist, 'title' => $title, ); $album = new Album(); $album->insert($data); $this->_ redirect('/'); return; } } // set up an "empty" album $this->view->album = new stdClass(); $this->view->album->id = null; $this->view->album->artist = ''; $this->view->album->title = ''; // additional view fields required by form $this->view->action = 'add'; $this->view->buttonText = 'Add';</b> } ... 

関数の開始時に、フォームのデータの転送があったかどうかがどのように判断されたかに注目してください。 フォームからデータが送信された場合、 artisttitle値を抽出し、 Zend_Filter_StripTagsタグのHTMLフィルターで処理します。 さらに、行に空でない値がある場合、 Album()クラスを使用してデータベーステーブルに新しいレコードを追加します。 アルバムを追加した後、ユーザーはコントローラーメソッド_redirect()を使用してメインページにリダイレクトされます。

最後に行うことは、ビューテンプレート用のHTMLフォームを準備することです。 先を見ると、レコード編集フォームはそれらを追加するためのフォームと同じように見えることに注意できます。 したがって、 add.phtmlおよびedit.phtml使用される共通のテンプレートファイル( _form.html )を使用します。

新しいアルバムページテンプレートを追加:

zf-tutorial/application/views/scripts/index/add.phtml:

 <?php echo $this->render('header.phtml'); ?> <h1><?php echo $this->escape($this->title); ?></h1> <?php echo $this->render('index/_form.phtml'); ?> <?php echo $this->render('footer.phtml'); ?> 

zf-tutorial/application/views/scripts/index/_form.phtml:

 <form action="<?php echo $this->baseUrl ?>/index/<?php echo $this->action; ?>" method="post"> <div> <label for="artist">Artist</label> <input type="text" name="artist" value="<?php echo $this->escape(trim($this->album->artist));?>"/> </div> <div> <label for="title">Title</label> <input type="text" name="title" value="<?php echo $this->escape($this->album->title);?>"/> </div> <div id="formbutton"> <input type="hidden" name="id" value="<?php echo $this->album->id; ?>" /> <input type="submit" name="add" value="<?php echo $this->escape($this->buttonText); ?>" /> </div> </form> 

結果は、かなり単純なコードです。 レコードの編集時にも_form.phtmlを使用する場合、必要なアクションの名前をハード設定する代わりに、変数$this->actionを使用します。 同様に、変数を介して、フォームからデータを送信するためのボタンの碑文が設定されます。

アルバム編集


アルバムの編集は、多くの点で新しいレコードの追加と同じであるため、コードは似ています。

zf-tutorial/application/controllers/IndexController.php:

 ... function editAction() { $this->view->title = "Edit Album"; $album = new Album(); if ($this->_request->isPost()) { Zend_Loader::loadClass('Zend_Filter_StripTags'); $filter = new Zend_Filter_StripTags(); $id = (int)$this->_request->getPost('id'); $artist = $filter->filter($this->_request->getPost('artist')); $artist = trim($artist); $title = trim($filter->filter($this->_request->getPost('title'))); if ($id !== false) { if ($artist != '' && $title != '') { $data = array( 'artist' => $artist, 'title' => $title, ); $where = 'id = ' . $id; $album->update($data, $where); $this->_redirect('/'); return; } else { $this->view->album = $album->fetchRow('id='.$id); } } } else { // album id should be $params['id'] $id = (int)$this->_request->getParam('id', 0); if ($id > 0) { $this->view->album = $album->fetchRow('id='.$id); } } // additional view fields required by form $this->view->action = 'edit'; $this->view->buttonText = 'Update'; } ... 

データがフォームからスクリプトに転送されなかった場合、 getParam()メソッドを使用してRequestオブジェクトのparamsプロパティからidパラメーターを取得できることに注意してください。

テンプレートコードを以下に示します。

zf-tutorial/application/views/scripts/index/edit.phtml:

 <?php echo $this->render('header.phtml'); ?> <h1><?php echo $this->escape($this->title); ?></h1> <?php echo $this->render('index/_form.phtml'); ?> <?php echo $this->render('footer.phtml'); ?> 

リファクタリング


もちろん、 addAction()editAction()非常によく似ており、レコードを追加および編集するためのテンプレートが一般的に同じであることに注意する必要はありません。 コードのリファクタリングの必要性を想定するのは理にかなっています。 追加の実践的な演習として、この問題を自分で解決します。

アルバムを削除


アプリケーションの開発を完了するには、レコードを削除する機能を追加する必要があります。 リスト内の各アイテムの反対側のアルバムを削除するためのリンクを提供しました。 頭に浮かぶ最初の解決策は、これらのリンクのいずれかをクリックするとすぐにエントリを削除することです。 しかし、これは間違ったアプローチです。 HTTP仕様に従って、GETメソッドを使用して元に戻せないアクションを実行しないでください。 このような場合、POSTを使用することをお勧めします。 この例は、Google Acceleratorの成果です。

レコードを削除する前に確認を要求し、受信後にのみ削除する必要があります。 これらのアクションを実装するコードは、アプリケーションに既に存在するアクション関数に多少似ています:

zf-tutorial/application/controllers/IndexController.php:

 ... function deleteAction() { $this->view->title = "Delete Album"; $album = new Album(); if ($this->_request->isPost()) { Zend_Loader::loadClass('Zend_Filter_Alpha'); $filter = new Zend_Filter_Alpha(); $id = (int)$this->_request->getPost('id'); $del = $filter->filter($this->_request->getPost('del')); if ($del == 'Yes' && $id > 0) { $where = 'id = ' . $id; $rows_affected = $album->delete($where); } } else { $id = (int)$this->_request->getParam('id'); if ($id > 0) { // only render if we have an id and can find the album. $this->view->album = $album->fetchRow('id='.$id); if ($this->view->album->id > 0) { // render template automatically return; } } } // redirect back to the album list unless we have rendered the view $this->_redirect('/'); } ... 

同じ方法を使用して、スクリプトにアクセスし、必要な操作を選択する方法を決定しました(レコードの削除または確認フォームの発行)。 追加および編集の場合と同じ方法で、 delete()メソッドによってZend_Db_Tableを介して削除が実行されます。 関数の最後に、ユーザーはアルバムリストページにリダイレクトされます。 したがって、パラメータ_redirect()チェックの1つが失敗した場合、関数内で_redirect()を繰り返し呼び出すことなく、元のページに戻ります。

テンプレートはシンプルなフォームです:
zf-tutorial/application/views/scripts/index/delete.phtml:

 <?php echo $this->render('header.phtml'); ?> <h1><?php echo $this->escape($this->title); ?></h1> <b><?php if ($this->album) :?> <form action="<?php echo $this->baseUrl ?>/index/delete" method="post"> <p>Are you sure that you want to delete '<?php echo $this->escape($this->album->title); ?>' by '<?php echo $this->escape($this->album->artist); ?>'? </p> <div> <input type="hidden" name="id" value="<?php echo $this->album->id; ?>" /> <input type="submit" name="del" value="Yes" /> <input type="submit" name="del" value="No" /> </div> </form> <?php else: ?> <p>Cannot find album.</p> <?php endif;?></b> <?php echo $this->render('footer.phtml'); ?> 

トラブルシューティング


index / index以外のアクションにアクセスするときに問題が発生する場合、最も可能性が高いのは、ルータークラスがWebサイトがどのディレクトリにあるかを正しく判断できないことです。 この状況は、サイトのURLが、ネットワークからアクセスするために開いているルートディレクトリを基準としたディレクトリへのパスと一致しない場合に発生する可能性があります。
上記のコードがケースに一致しない場合は、 $baseURL変数をサーバーの正しい値に設定する必要があります。

zf-tutorial/index.php:

 ... // setup controller $frontController = Zend_Controller_Front::getInstance(); $frontController->throwExceptions(true); $frontController->setBaseUrl('/mysubdir/zf-tutorial'); $frontController->setControllerDirectory('./application/controllers'); ... 

/mysubdir/zf-tutorial/は、 index.phpファイルへの実際のパスに置き換える必要があります。 たとえば、 index.phpへのURLが次のようになっている場合 localhost/~ralle/zf-tutorial/index.php localhost/~ralle/zf-tutorial/index.phpの場合、 $baseUrl変数の正しい値は/~ralle/zf-tutorial/です。

おわりに


これについては、シンプルだが完全に機能するMVCアプリケーションの構築が完了したと見なすことができます。 このレビューがあなたにとって有益で有益であることを願っています。 元のテキストに関するコメントは、rob @ akrabat.comで記事の著者に送信できます。 ロシア語の翻訳に関するコメントは、musayev @ yandex.ruに送信してください。

この記事では、Zend Frameworkの表面的な概要のみを提供します。ここには、ここに挙げたクラス以外にも非常に多くのクラスがあります。 それらの詳細なレビューについては、適切なリソースを参照する必要があります。

この翻訳では、無料の百科事典Wikipedia.orgの資料を使用しました。

Source: https://habr.com/ru/post/J31173/


All Articles