フロントエンドアプリケーションは求職者と仕事の提供者が十分に利用できます。バックエンドアプリケーションを少し話すことにします。今日は、symfonyのadminジェネレーターのおかげで、Jobeet用の完全なバックエンドインターフェイスを1時間で開発します。最初のステップはbackendアプリケーションを作ることです。backendバックエンドアプリケーションを使うのがJobeetの管理者だけであっても、symfonyのすべての組み込み機能を有効にしました。backendprod環境ではhttp://jobeet.localhost/backend.php/、dev環境ではhttp://jobeet.localhost/backend_dev.php/を通してバックエンドアプリケーションを利用できます。noteフロントエンドアプリケーションを作成したとき、運用環境のフロントコントローラーの名前はindex.phpでした。ディレクトリごとに1つのindex.phpファイルだけ用意できるので、symfonyは初期の運用環境のフロントコントローラーであるindex.phpファイルを作り名前をアプリケーションからつけます。propel:data-loadタスクでデータフィクスチャをリロードしようとしても、動作しません。JobeetJob::save()メソッドがfrontendアプリケーションからapp.yml設定ファイルにアクセスする権限が必要だからです。2つのアプリケーションを用意したので、symfonyは最初に見つかるアプリケーション、今はbackendアプリケーションを使います。8日目でみたように、コンフィギュレーションは異なるレベルで設定できます。apps/frontend/config/app.ymlファイルの内容をconfig/app.ymlに移動させることで、すべてのアプリケーションの間で設定は共有され問題は修正されます。adminジェネレーターでモデルクラスを広範囲で使うので、今変更をします。バックエンドアプリケーションのapp.ymlで定義される変数が必要になります。tippropel:data-loadタスクは--applicationオプションも受け取ります。--application=frontendバックエンドモジュールフロントエンドアプリケーションに関して、モデルクラスに基づいた基本的なCRUDモジュールをブートストラップするためにpropel:generate-moduleタスクが使われてきました。--module=categoryこれら2つのコマンドはJobeetJobとJobeetCategoryモデルクラスに対してそれぞれjobとcategoryモジュールを作成します。--moduleオプションを追加するとタスクによってデフォルトで生成されるmoduleの名前がオーバーライドされます(そうでなければJobeetJobクラスに対してjobeet_jobになります)。trueインターフェイスのメインゴールはモデルオブジェクトのライフサイクルの管理なので、adminジェネレーターによって使われるルートクラスがsfPropelRouteCollectionであるのは驚くことではありません。生成されるルートのプレフィックスのパスを定義する(たとえば、編集ページは/job/1/editのようになる)。adminインターフェイスは古典的なCRUDオペレーション以上の機能を持ち、このオプションによってルートを編集せずに、オブジェクトとコレクションアクションを定義できます。新しいタスクを使う前にヘルプを読むのはよい考えです。propel:generate-adminこのコマンドによって古典的な使い方の例と同じようにタスクのすべての引数とオプションが表示されます。生成されたモジュールは直ちに利用できます:http://jobeet.localhost/backend_dev.php/jobhttp://jobeet.localhost/backend_dev.php/categoryadminモジュールは以前に生成したシンプルなモジュールよりも多くの機能を持ちます。PHPを一行も書くことなく、それぞれのモジュールはこれらのすばらしい機能を提供します:オブジェクトのリストはページ分割されるリストはソート可能であるリストはフィルタリング可能であるオブジェクトは作成、編集と削除が可能である選択されたオブジェクトはバッチで削除可能であるフォームのバリデーションが有効であるflashメッセージによってユーザーに即座のフィードバックが行われるさらに多くの機能があるadminジェネレーターはパッケージを設定するシンプルなバックエンドインターフェイスを作成するために必要なすべての機能を提供します。ユーザーエクスペリエンスを少し改善するために、デフォルトのバックエンドをカスタマイズする必要があります。異なるモジュールの間を渡り歩くのを楽にするためにシンプルなメニューを追加します。</body></html>レイアウトはadmin.cssスタイルシートを使います。4日目の間にこれは他のスタイルシートと一緒にインストールしたので、このファイルはweb/css/の中に存在しなければなりません。}symfonyのキャッシュ好奇心旺盛であれば、apps/backend/modules/ディレクトリの下でタスクによって生成されたファイルをすでに開いているかもしれません。なければ、今ファイルを開いてください。見てみると、jobActionsクラスがautoJobActionsを継承することに気がつきます。autoJobActionsクラスは存在しなければsymfonyによって自動的に生成されます。...adminジェネレーターの動作は既知のふるまいを思い出させてくれます。実際、これはモデルとフォームクラスに関してすでに学んだこととよく似ています。モデルスキーマの定義に基づいて、symfonyはモデルとフォームクラスを生成します。~generator.ymlファイルを更新するたびに、symfonyはキャッシュを再生成します。今日見たように、adminジェネレーターで生成したモジュールのカスタマイズは簡単で、速く、面白いです。noteキャッシュファイルの自動再生成は開発環境のみで行われます。運用環境では、cache:clearタスクを使ってキャッシュを手動でクリアする必要があります。バックエンドのコンフィギュレーションadminモジュールはgenerator.ymlファイルのconfigキーを編集することでカスタマイズできます。新しいページ固有のコンフィギュレーションカスタマイズを始めましょう。%%で囲まれるすべての文字列は対応するオブジェクトのカラムの値で置き換えられます。Creationフィールドのコンフィギュレーション異なるビュー(list、newとedit)はフィールドで構成されます。フィールドはモデルクラスのカラムもしくは後で見るバーチャルカラムになります。}fieldsセクションはすべてのビュー用のフィールドコンフィギュレーションをオーバーライドします。このことはis_activatedフィールド用のラベルがlist、editとnewビュー用に変更されることを意味します。adminジェネレーターのコンフィギュレーションはコンフィギュレーションカスケードの原則に基づきます。}メインのfieldsセクションの下でセットされるコンフィギュレーションはビュー固有のコンフィギュレーションによってオーバーライドされます。オーバーライドのルールは次の通りです:newとeditはformを継承し、formはfieldsを継承するlistはfieldsを継承するfilterはfieldsを継承するnoteフォームセクション(form、editとnew)に関しては、labelとhelpオプションはフォームクラスで定義されるものをオーバーライドします。listビューのコンフィギュレーションdisplayデフォルトでは、listビューのカラムはすべてモデルのカラムです。スキーマファイルの順序で並べられています。slug]nameカラムの前の=記号は文字列をリンクに変換するための慣習です。email]layoutlistは異なるレイアウトで表示されます。デフォルトでは、レイアウトは~tabular|テーブルレイアウト~です。このことはそれぞれのカラムの値が独自のテーブルカラムの中にあることを意味します。jobモジュールに関しては、stackedレイアウトを使うほうがよいです。(%%location%%)stackedレイアウトにおいて、それぞれのオブジェクトは単独の文字列で表され、paramsオプションによって定義されます。notedisplayオプションはこれはユーザーによってソートできるカラムを定義するのでまだ必要です。"バーチャル"カラムこの設定によって、%%category_id%%セグメントはカテゴリの主キーによって置き換えられます。カテゴリの名前を表示するほうがより意味があります。%%の表記を使うときは、変数はデータベーススキーマの実際にカラムに対応する必要はありません。adminジェネレーターはモデルクラスの関連ゲッターを見つけることだけが必要です。カテゴリの名前を表示するには、JobeetJobモデルクラスのgetCategoryName()メソッドを定義し%%category_id%%を%%category_name%%に置き換えます。JobeetJobクラスはすでに関連カテゴリオブジェクトを返すgetJobeetCategory()メソッドを持ちます。%%jobeet_category%%を使う場合、JobeetCategoryクラスはオブジェクトを文字列に変換する__toString()マジックメソッドを持つので、この表記は動作します。(%%location%%)sort管理者として、投稿された最新の求人を見ることにご興味があるでしょう。desc]max_per_pageデフォルトでは、リストはパジネートされそれぞれのページは20のアイテムを含みます。10batch_actionsリストにおいて、アクションはいくつかのオブジェクトで実行できます。categoryモジュールに対してこれらのバッチは必要ありません。{}batch_actionsオプションはバッチアクションのリストを定義します。空の配列によって機能の削除ができます。~_で始まるアクションはフレームワークによって提供される組み込みのアクションです。}}選択された主キーはidsリクエストパラメーターに保存されます。それぞれの選択された求人に関して、期限切れのチェックをするために追加の引数でJobeetJob::extend()メソッドが呼び出されます。...}すべての求人期間が延長された後で、ユーザーはjobモジュールのホームページにリダイレクトされます。object_actionslistにおいて、単独のオブジェクトで実行できるアクション用の追加カラムがあります。~バッチアクションに関しては、_deleteと_editアクションはフレームワークによって定義されます。...}actionsオブジェクトのリストもしくは単独のオブジェクトにアクションをリンクする方法をすでに見てきました。新しいオブジェクトを作るように、actionsオプションはオブジェクトを全く受け取らないアクションを定義します。}これまで、定義したすべてのアクションは~を持ちました。これはsymfonyがアクションを自動的に設定することを意味します。それぞれのアクションはパラメーターの配列を定義することでカスタマイズできます。labelオプションはsymfonyによって生成されたデフォルトのラベルをオーバーライドします。デフォルトでは、リンクをクリックするときに実行されるアクションはlistをプレフィックスとするアクションの名前です。...}昨日定義したJobeetJobPeer::cleanup()メソッドを再利用しました。これはMVCパターンによって提供される再利用性の別のすばらしい例です。}peer_method求人リストのページを表示するために必要なデータベースへのリクエスト回数は14回で、Webデバッグツールバーによって表示されます。doSelectJoinJobeetCategorydoSelectJoinJobeetCategory()メソッドはjobとcategoryテーブルの間にJOINを追加しそれぞれの求人に関連するカテゴリオブジェクトを自動的に作成します。form、editとnewで構成されます。これらすべては同じ設定機能を持ちformセクションはeditとnewセクション用のフォールバックとしてのみ存在します。displayリストに関して、displayオプションで表示されるフィールドの順序を変更できます。表示されるフォームはクラスによって定義されるので、予期しないバリデーションエラーにつながるのでフィールドを削除しようとしないでください。expires_at]上記のコンフィギュレーションでは2つのグループ(ContentとAdmin)が定義され、それぞれはフォームフィールドのサブセットを含みます。noteAdminグループのカラムはまだブラウザーには表示されません。これらは求人フォームの定義に設定されていないからです。adminアプリケーション用にカスタムの求人フォームクラスを定義するときにこれらはわずかなセクションに現れます。adminジェネレーターは多対多のリレーション用の組み込み機能をサポートします。カテゴリフォームにおいて、名前の入力、スラッグの入力、関連するアフィリエイト用のドロップダウンボックスがあります。}}"バーチャル"カラム求人フォームのdisplayオプションにおいて、_generated_tokenフィールドはアンダースコア(_)で始まります。このフィールドのレンダリングは_generated_token.phpという名前のカスタムパーシャルで処理されることを意味します。?></div>パーシャルにおいて、現在のフォーム($form)にアクセス可能で関連オブジェクトはgetObject()メソッドを通してアクセスできます。noteチルダ(~)をフィールドの名前のプレフィックスにすることでレンダリングをコンポーネントにデリゲートすることもできます。class管理者によって使われるフォームに関して、ユーザーの求人フォームよりも多くの情報を表示してきました。今では、JobeetJobFormクラスでこれらを削除したので、これらの中にはフォームに表示されないものがあります。フロントエンドとバックエンドで異なるフォームを用意するには、2つのフォームクラスを作る必要があります。JobeetJobFormクラスを継承するBackendJobeetJobFormクラスを作りましょう。BackendJobeetJobFormnote新しいクラスを作成したので、キャッシュをクリアすることを忘れないでください。editフォームは小さな問題をかかえています。現在のアップロードされたロゴはどこにも表示されないので現在のものを削除できません。ウィジェットをレンダリングするために使うテンプレートtip生成されたテンプレートはたくさんのclassとid属性を定義するので、adminジェネレーターの見た目はとても簡単に調整できます。ロゴフィールドはsf_admin_form_field_logoクラスを使ってカスタマイズできます。それぞれのフィールドはsf_admin_textもしくはsf_admin_booleanのようなフィールドタイプに決まるクラスも持ちます。edit_modeオプションはsfPropel::isNew()メソッドを使います。これはフォームのモデルオブジェクトが新しい場合はtrueを返し、そうでなければfalseを返します。埋め込みオブジェクトのステータスによって異なるウィジェットもしくはバリデーターを用意する必要がある場合にこれはとても役立ちます。フィルターのコンフィギュレーションフィルターの設定方法はフォームビューの設定方法とまったく同じです。実際、フィルターは単なるフォームです。フォームに関しては、クラスはpropel:build-allタスクで生成されました。propel:build-filtersタスクでこれらを再生成することもできます。フォームフィルタークラスはlib/filter/ディレクトリの下に設置されそれぞれのモデルクラスは関連フィルターフォームクラスを持ちます(JobeetJobFormに対してJobeetJobFormFilter)。expires_at]フィルターは常にオプションなので、フィールドが表示されるように設定するために、フィルターフォームクラスをオーバーライドする必要はありません。アクションのカスタマイズ設定が十分ではないとき、これまでの機能の拡張方法で見てきたように新しいメソッドをアクションクラスに追加できます。現在のソートカラムを設定するそれぞれの生成メソッドは1つのことしか行わないので、たくさんのコードをコピー&ペーストしなくてもふるまいを変更するのは簡単です。テンプレートのカスタマイズadminジェネレーターによってHTMLコードに追加されるclassとid属性のおかげで生成されたテンプレートをカスタマイズする方法を見てきました。クラスに関して、オリジナルのテンプレートをオーバーライドすることもできます。Categoryこれら2つの設定ファイルだけで、Jobeet用のすばらしいバックエンドインターフェイスを短時間で開発しました。tip何かがYAMLファイルで設定可能であるとき、プレーンなPHPコードを使うことができるのはご存じのとおりです。adminジェネレーターに関して、apps/backend/modules/job/lib/jobGeneratorConfiguration.class.phpファイルを編集できます。これによってYAMLファイルと同じオプションがPHPで帝京されます。メソッドの名前を学ぶには、cache/backend/dev/modules/autoJob/lib/BaseJobGeneratorConfiguration.class.phpの生成された基底クラスを見てください。一時間で、Jobeetプロジェクト用に十分な機能を持つバックエンドインターフェイスを開発しました。全体で、50行に満たないPHPコードしか書きませんでした。こんなに多くの機能があって悪くないです!明日は、ユーザー名とパスワードでバックエンドアプリケーションをセキュアにする方法を見ることになります。symfonyのユーザークラスに関して話す機会もあります。