攻略って書いてるけど、攻略しきれていない部分もたくさん・・・
お許しください、、、。
phalconチュートリアル-Basic-
phalconのチュートリアルを学習してみます。
こちらを元に勉強しました。
phalconチュートリアル-Basic編-
macでxamppの上に置いてやっています
ファイル構造
xamppと一緒に使いたいので、htdocsの中にファイルを置いています。
┗ tutorial
┣ app
┇ ┣ controllers
┇ ┇ ┣ IndexController.php
┇ ┇ ┗ SignupController.php
┇ ┣ models
┇ ┇ ┗ Users.php
┇ ┗ views
┗ public
┣ css
┣ img
┣ js
┗ index.php
チュートリアルのコードの意味を徹底解明! ~「Hello」を出力するまで~
まずはindex.php
一度全体を見せたあと少しずつ解剖していきます。
<?php
use Phalcon\Loader; //①オートローダー使うよ!って宣言
use Phalcon\Mvc\View; //ビューを使用するために必要な宣言
use Phalcon\Mvc\Application; //MVCの煩雑な処理はこれが行なっているらしい
use Phalcon\Di\FactoryDefault; //Phalconに付属しているコンポーネントのほとんどを登録するための宣言
use Phalcon\Mvc\Url as UrlProvider; //URLを作成するために必要な宣言
// Define some absolute path constants to aid in locating resources
define('BASE_PATH', dirname(__DIR__)); //
define('APP_PATH', BASE_PATH . '/app');
// Register an autoloader
$loader = new Loader();
$loader->registerDirs(
[
APP_PATH . '/controllers/',
APP_PATH . '/models/',
]
);
$loader->register();
// Create a DI
$di = new FactoryDefault();
// Setup the view component
$di->set(
'view',
function () {
$view = new View();
$view->setViewsDir(APP_PATH . '/views/');
return $view;
}
);
// Setup a base URI
$di->set(
'url',
function () {
$url = new UrlProvider();
$url->setBaseUri('/');
return $url;
}
);
$application = new Application($di);
try {
// Handle the request
$response = $application->handle();
$response->send();
} catch (\Exception $e) {
echo 'Exception: ', $e->getMessage();
}
解剖します
<?php
use Phalcon\Loader; //オートローダー使うよ!って宣言
use Phalcon\Mvc\View; //ビューを使用するために必要な宣言
use Phalcon\Mvc\Application; //MVCの煩雑な処理はこれが行なっているらしい
use Phalcon\Di\FactoryDefault; //Phalconに付属しているコンポーネントのほとんどを登録するための宣言
use Phalcon\Mvc\Url as UrlProvider; //URLを作成するために必要な宣言
オートローダーってなんぞや?
Phalcon\Loader とは、PSR-4 に準拠したオートロードの機能を提供するためのクラスです。
これを利用することによって、Phalcon は Composer に依存しないオートロードを実装することが出来ます。
だそうです。
このサイトが分かりやすい
What about Phalcon\Loader
あとは、宣言なので、ふーんっていう感じでいいのかな?
// Define some absolute path constants to aid in locating resources
define('BASE_PATH', dirname(__DIR__)); //
define('APP_PATH', BASE_PATH . '/app');
define('A', 'B'); で、AをBと定義するという用法ですね。
dirname(_DIR_)は、そのファイルが存在するディレクトリなので、
この場合は、BASE_PATH = そのファイルが存在するディレクトリ と定義したということですね。
同様にAPP_PATHもパスを定義しています。
参考:自動的に定義される定数
// Register an autoloader
$loader = new Loader(); //オートローダーを作る
$loader->registerDirs(
[
APP_PATH . '/controllers/',
APP_PATH . '/models/',
]
);
$loader->register(); //上で定義したオートローダーを登録
これは、オートローダーを作って、ディレクトリを登録しておきます。
ここでは、controllersとmodelsを登録します。
// Create a DI
$di = new FactoryDefault();
DIを作ります。
DIは、phlconの特徴の一つでもあるので、知っておきましょう!!
猿でも分かる! Dependency Injection: 依存性の注入
// Setup the view component
$di->set(
'view',
function () {
$view = new View(); //新しいviewを作る
$view->setViewsDir(APP_PATH . '/views/'); //パスを「/views/」に指定する
return $view; //変数viewを返します
}
);
Viewの部分を作っていきます。htmlとかがある場所ですね。
viewをセットして、第二引数の関数の中に実行したいことを記します。
// Setup a base URI
$di->set(
'url',
function () {
$url = new UrlProvider();
$url->setBaseUri('/');
return $url;
}
);
ベースとなるURIを作ります。
URLとURIは何が違うの? どちらが正しい呼び方?
urlをセットして、第二引数に実行したいことを記します。
変数urlに、新しいUrlProviderを作って、パスは現在置で良いので、「/」としているのでしょう。
変数urlを返します。
$application = new Application($di);
try {
// Handle the request
$response = $application->handle();
$response->send();
} catch (\Exception $e) {
echo 'Exception: ', $e->getMessage();
}
applicationの存在意義がわからない・・・そこで調べてみると、このようなことが書かれていました。難しい。
PhalconでのMVCの操作をオーケストレーションする背後にあるすべてのハードワークは、通常、Phalcon \ Mvc \ Applicationによって行われます。このコンポーネントは、必要なすべての複雑なオペレーションをバックグラウンドでカプセル化し、必要なすべてのコンポーネントをインスタンス化し、MVCパターンを必要に応じて動作させるためにプロジェクトと統合します。
applicationに一度放り込んで、複雑な処理をするということかな?
tryは例外処理を記述する場所です。
まずは、何か実行することを記します。
何かを行うときは、handleを使うそうで、この場合、responseを使いますよっていうことかな?
applicationを代入しているので、resoponseを返すということは、applicationを実行するっていうことかな。
例外が発生したら、エラーのメッセージを返すようになっていますね。
ちなみに
例外処理の記述はこう書くそうです
try {
// 例外が発生する可能性のあるコード
} catch (Exception $e) {
// 例外が発生した場合に行う処理
}
次に、コントローラーを見ていきます。
<?php
use Phalcon\Mvc\Controller; //コントローラーを使うために必要なやつ
class IndexController extends Controller
{
public function indexAction()
{
}
}
Controllerを継承して、IndexControllerというクラスを作ります。
indexActionは、「index」というのviewを参照するので、index.phtmlという名前にしておきます。
ちなみに、indexControllerは、indexフォルダを参照しますので、indexフォルダのindex.htmlを参照するということになります。
indexというフォルダの中に、index.phtmlを作りましょう。
index/phtmlを作る
<?php echo "<h1>Hello!</h1>";
コントローラーから、viewが参照されたので、helloを出力するプログラムを書きます。
そうすると、xamppでローカルホストに行くと、Hello!と表示されるでしょう。
サインアップフォームの設計の部分
index.phtmlを書き換える
サインアップフォームの場合は、Hello!の下にsign up here!という文字を作ってみましょう!
<?php
echo "<h1>Hello!</h1>";
echo PHP_EOL; //改行
echo PHP_EOL; //改行
echo $this->tag->linkTo(
"signup",
"Sign Up Here!"
);
tag->linkTO でリンクを生成します。
signupに行くリンクを生成します(ブラウザには、「」Sign Up Here!)と表示される。
つまり、通常のhtmlなら、こんな感じになっているということです。
<h1>Hello!</h1>
<a href="/signup">Sign Up Here!</a>
SignupControllerを作る
<?php
use Phalcon\Mvc\Controller;
class SignupController extends Controller
{
public function indexAction()
{
}
}
SignupControllerは、signupフォルダを参照します。
Controllerを継承して、SignupControllerというクラスを作り、
indexActionでindex.phtmlを参照します。
signup用のindex.phtmlを作る
<h2>Sign up using this form</h2>
<?php echo $this->tag->form("signup/register"); ?> //formタグを作って、signupコントローラーのregisterActionに飛ぶように設定
<p>
<label for="name">Name</label> //「Name」と表示されるラベルを作る
<?php echo $this->tag->textField("name"); ?> //テキストを書くフィールドを作る
</p>
<p>
<label for="email">E-Mail</label> //「E-Mail」と表示されるラベルを作る
<?php echo $this->tag->textField("email"); ?> //テキストを書くフィールドを作る
</p>
<p>
<?php echo $this->tag->submitButton("Register"); ?> //Registerボタンを作る
</p>
</form>
モデルを作る
まずデータベースの設定から
ターミナルで以下のコマンドを打ちます。これで、ターミナルからxamppのphpmyadminに入れます。
この後パスワードを入力してください。
(ここは、チュートリアルにはありません。)
/Applications/XAMPP/xamppfiles/bin/mysql -u root -p
データベースを作ります。ここでは、phalcon_testという名前のデータベースを作ってみました。
ターミナルで下記のコマンドを打ってください。
(ここはチュートリアルにありません。)
create database phalcon_test;
このデータベースを使うことを宣言します。
use phalcon_test;
次にテーブルを作ります。
これはチュートリアルのやつですね。
ターミナルに打ち込みます。
CREATE TABLE `users` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(70) NOT NULL,
`email` varchar(70) NOT NULL,
PRIMARY KEY (`id`)
);
モデルを作ります
<?php
use Phalcon\Mvc\Model; //モデルを使います!という宣言
class Users extends Model //Modelクラスを継承して、Usersというクラスを作成(Usersテーブルを参照という意味になります)
{
public $id;
public $name;
public $email;
}
モデルの働きを確認すると、、、
モデルは、主に、対応するデータベーステーブルとの相互作用のルールを管理するために使用されます。
なるほど。
データベーステーブルの情報を書いていけばいいんですね。
ちなみに、publicを使うと、どこからでも読み取り・変更できるようになるらしい・・・。publicがいまいち分からんな。。。
データベースとの接続
チュートリアルにもある以下のコードをindex.phpに追記します。
use Phalcon\Db\Adapter\Pdo\Mysql as DbAdapter;
// Setup the database service
$di->set(
'db', //DIにdbをセット
function () {
return new DbAdapter(
[
'host' => 'localhost', //xamppでやっているのでローカルホストを指定
'username' => 'root', //phpmyadminにログインするときのユーザー名
'password' => 'secret', //phpmyadminにログインするときのパスワード
'dbname' => 'phalcon_test', //他のデータベース名にした人は、そのデータベース名を指定
]
);
}
);
モデルを使用したデータの保存
<?php
use Phalcon\Mvc\Controller; //コントローラを使います!
class SignupController extends Controller //Controllerを継承して、 SignuoControllerクラスを作成(signupフォルダを参照するようになります)
{
public function indexAction() //index.phtmlを実行
{
}
public function registerAction() register //register.phtmlがあれば、それを実行するが、ないので、以下のコードを実行
{
$user = new Users(); //usersを作成
// Store and check for errors
$success = $user->save( //saveはレコードの作成、更新ができる
$this->request->getPost(), //requestを$_POST[$name]と$_POST[$email]で返す
[
"name",
"email",
]
);
if ($success) { //もし$successがあれば(さっきのがうまくいったら)
echo "Thanks for registering!"; //Thanks for registering!と表示
} else { //もし$successがなければ(さっきのがうまくいかなかったら)
echo "Sorry, the following problems were generated: "; //Sorry, the following problems were generated:と表示
$messages = $user->getMessages(); //生成されたメッセージは、getMessages()メソッドで取得できる、それを$messagesに代入
foreach ($messages as $message) {
echo $message->getMessage(), "<br/>"; //データを表示
}
}
$this->view->disable(); //register.phtmlがあれば、それを表示しちゃうので、viewの機能を遮断しました。
}
}
中に全部書いてしまった笑
終わりです。
phalconチュートリアル-REST-
phalconのチュートリアル「REST」を解剖しながらみていきます。
macでXAMPPの上で動かしています。
チュートリアル-Creating a Simple REST API編-
全てを解剖した上で、知っておくべき知識がやっとわかったので、
以下の内容をコンプリートしてから先に進みましょう笑笑
でも、まだよくわからないことだらけなので、わからない部分はごめんなさい、笑
Phalconモデルまとめ(1)データ取得の基本
よく見るHTTPステータスコード一覧とその意味を理解する
HTTPについて
クラスPhalcon \ Http \ Response ⇦レスポンスの部分
PhalconのHTTPリクエスト
ファイル構造
ファイル構造はこんな感じです。チュートリアルと一緒
my-rest-api/
models/
Robots.php
index.php
.htaccess
.htaccessを作る
これは良く分からんので、コピペで。
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^((?s).*)$ index.php?_url=/$1 [QSA,L]
</IfModule>
index.phpを作る
分解していきます。
<?php
use Phalcon\Loader; //オートローダー使うよ!って宣言
use Phalcon\Mvc\Micro; //マイクロフレームワークのようなアプリケーションを作成する
use Phalcon\Di\FactoryDefault; //Phalconに付属しているコンポーネントのほとんどを登録するための宣言
use Phalcon\Db\Adapter\Pdo\Mysql as PdoMysql; //mysqlを使う
// Use Loader() to autoload our model
$loader = new Loader(); //オートローダーを作る
$loader->registerNamespaces( //名前空間を定義する
[
'Store\Toys' => __DIR__ . '/models/', //store\Toysを定義。「/models/」以下のディレクトリをロードする
]
);
$loader->register(); //上で定義したオートローダーを登録
$di = new FactoryDefault(); //DIを作る
// Set up the database service
$di->set(
'db', //データベースを定義
function () {
return new PdoMysql(
[
'host' => 'localhost', //XAMPPならlocalhost
'username' => 'root', //使用するデータベースの名前を記す
'password' => 'secret', //使用するデータベースのパスワードを記す
'dbname' => 'robotics', //使用するデータベースの名前を記す
]
);
}
);
// Create and bind the DI to the application
$app = new Micro($di); //appというマイクロを作って??DIと結びつける
// Retrieves all robots
//データの検索の定義
$app->get(
'/api/robots', //検索する際は「/api/robots」を使う!
function () use ($app) {
$phql = 'SELECT * FROM Store\Toys\Robots ORDER BY name'; //Store\Toys\Robotsから、全ての情報を取り出す(名前順に)という作業を変数phqlに代入
$robots = $app->modelsManager->executeQuery($phql); //さっきのphqlを実行します。
$data = []; //空のdataを作ります。
foreach ($robots as $robot) {
$data[] = [
'id' => $robot->id, //全てのrobotのidとnameをdataに格納します
'name' => $robot->name,
];
}
echo json_encode($data); //dataをjson形式にして表示
}
);
JSON形式ってなんやったっけ・・・
要するに「JavaScriptの中でオブジェクトを記述する書式」のことです。
JSONというのは「データを表現するための記法(≒文法)」です。
らしいです。笑
// Searches for robots with $name in their name
$app->get(
'/api/robots/search/{name}', 「名前」で検索するのは「/api/robots/serch/{name}」
function ($name) use ($app) {
$phql = 'SELECT * FROM Store\Toys\Robots WHERE name LIKE :name: ORDER BY name'; //Store\Toys\Robotsから、全ての情報を取り出す(名前順に)という作業を変数phqlに代入
$robots = $app->modelsManager->executeQuery( //先ほどのphqlを実行
$phql,
[
'name' => '%' . $name . '%' //なんじゃこりゃ??
]
);
$data = []; //空のデータを作成
foreach ($robots as $robot) {
$data[] = [
'id' => $robot->id, //さっき抽出したやつのidとnameをdataに格納します
'name' => $robot->name,
];
}
echo json_encode($data); //dataをjson形式にして表示
}
);
use Phalcon\Http\Response;
// Retrieves robots based on primary key
$app->get(
'/api/robots/{id:[0-9]+}', //主キーで検索するのは「/api/robots/{id:[0-9]+}」を使う
function ($id) use ($app) {
$phql = 'SELECT * FROM Store\Toys\Robots WHERE id = :id:'; //「Store\Toys\Robots」から全てのIDを取り出す。
$robot = $app->modelsManager->executeQuery( //先ほどのphqlを実行
$phql,
[
'id' => $id, //idを表示?代入?
]
)->getFirst(); //最初のレコードを取得
// Create a response
$response = new Response(); responseを作る
if ($robot === false) { //もし変数robotがなかったら
$response->setJsonContent(
[
'status' => 'NOT-FOUND' //ステータスを404 NOT FOUNDにする
]
);
} else {
$response->setJsonContent(
[
'status' => 'FOUND',
'data' => [
'id' => $robot->id, //dataにidとnameを格納
'name' => $robot->name
]
]
);
}
return $response; responseを返す
}
);
// Adds a new robot 新しいのを入れる
$app->post(
'/api/robots', POSTには「/api/robots」を使う
function () use ($app) {
$robot = $app->request->getJsonRawBody(); //POSTのbodyを取得する機能を$robotに持たせます
$phql = 'INSERT INTO Store\Toys\Robots (name, type, year) VALUES (:name:, :type:, :year:)'; //phqlは、「Store\Toys\Robots」に「name」「type」「year」を追加
$status = $app->modelsManager->executeQuery(
$phql,
[
'name' => $robot->name, //phqlを実行し、nameに名前をtypeにタイプを、yearに年を代入
'type' => $robot->type,
'year' => $robot->year,
]
);
// Create a response
$response = new Response(); //responseを作る
// Check if the insertion was successful
if ($status->success() === true) { //successはフラッシュメッセージ
// Change the HTTP status
$response->setStatusCode(201, 'Created'); //ステータスのコード設定 404のNOTFOUNDみたいな感じで、201のCreatedを設定しているのだろう。
$robot->id = $status->getModel()->id; //$robotに先ほどのstatusの現在のモデル状況からidを参照します。
$response->setJsonContent( //HTTPレスポンスの本文を作成する
[
'status' => 'OK', //statusがokの場合はリクエストがなんの問題もなく受理されます
'data' => $robot, //dataに先ほどのrobotを代入
]
);
} else {
// Change the HTTP status
$response->setStatusCode(409, 'Conflict'); //ステータスコードを409のConflictに設定
// Send errors to the client
$errors = []; //エラーメッセージを入れるようの空箱を用意
foreach ($status->getMessages() as $message) { //ステータスのエラーメッセージを取得
$errors[] = $message->getMessage(); // errorsに格納
}
$response->setJsonContent( //HTTPレスポンスの本文を作成する
[
'status' => 'ERROR',//ステータスをエラーにして
'messages' => $errors, //エラーメッセージをmessagesに代入
]
);
}
return $response; responseを返す
}
);
// Updates robots based on primary key アップデート
$app->put(
'/api/robots/{id:[0-9]+}',
function ($id) use ($app) {
$robot = $app->request->getJsonRawBody(); //POSTのbodyを取得する機能を$robotに持たせます
$phql = 'UPDATE Store\Toys\Robots SET name = :name:, type = :type:, year = :year: WHERE id = :id:'; //それぞれアップデート
$status = $app->modelsManager->executeQuery( //先ほどのphqlを実行
$phql,
[
'id' => $id, //それぞれ代入
'name' => $robot->name,
'type' => $robot->type,
'year' => $robot->year,
]
);
// Create a response
$response = new Response(); //レスポンスを作成
// Check if the insertion was successful
if ($status->success() === true) {
$response->setJsonContent( //ステータスがうまくいったら
[
'status' => 'OK' //ステータスをOKにする
]
);
} else {
// Change the HTTP status
$response->setStatusCode(409, 'Conflict'); //うまくいかなければ、409のConflictにする
$errors = []; //エラーを格納する空箱を用意
foreach ($status->getMessages() as $message) { //エラーメッセージを取得して、
$errors[] = $message->getMessage(); //errorsに代入
}
$response->setJsonContent( //HTTPレスポンスの本文を作成する
[
'status' => 'ERROR', //ステータスをエラーにして
'messages' => $errors, //エラーメッセージを表示?
]
);
}
return $response; //レスポンスを返す
}
);
// Deletes robots based on primary key 削除
$app->delete(
'/api/robots/{id:[0-9]+}',
function ($id) use ($app) {
$phql = 'DELETE FROM Store\Toys\Robots WHERE id = :id:'; //削除なので、DELETEがありますね
$status = $app->modelsManager->executeQuery( //先ほどのphqlを実行
$phql,
[
'id' => $id, //idを表示??
]
);
// Create a response
$response = new Response();
if ($status->success() === true) { //うまくいったら
$response->setJsonContent( //HTTPレスポンスの本文を作成する
[
'status' => 'OK' //ステータスをOKにする
]
);
} else { //うまくいかなければ
// Change the HTTP status
$response->setStatusCode(409, 'Conflict'); //ステータスを409のConflictにする
$errors = []; //エラーを格納する空箱を作って
foreach ($status->getMessages() as $message) { //エラーメッセージを取得し
$errors[] = $message->getMessage(); //errorsに代入
}
$response->setJsonContent( //HTTPレスポンスの本文を作成する
[
'status' => 'ERROR', //ステータスをERRORにして
'messages' => $errors, //エラーメッセージを表示?
]
);
}
return $response; //responseを返す
}
);
phalconチュートリアル-Vokuro-
phalconのチュートリアルを学習してみます。
こちらを元に勉強しました。
macでxamppの上に置いてやっています
githubからクローンする
ターミナルでhtdocsがあるところまでいってください。そしてクローンします。
僕は、macでxamppの上に置きたいので、このようなコードになります
cd /Applications/XAMPP/xamppfiles/htdocs
git clone https://github.com/phalcon/vokuro.git
すると、テンプレが出来上がりました。
次にvokuroに移動して、composerをインストールします
そのあとに、composer installをすればいいらしい
cd vokuro
curl -sS -k https://getcomposer.org/installer | php
composer install
チュートリアル通りにするとエラーに・・・解決策見つけた!!
チュートリアルでは、これにアクセスせよと書かれていますが・・・
http://localhost/vokuro
エラーが出ました。
Warning: Phalcon\Mvc\View\Engine\Volt\Compiler::compileFile
でも、解決策見つけましたよ。
エラーに、index.php on line 41がどうのこうの書いてましたけど、そんなん関係ない!!!
cacheフォルダにアクセス権がないためにエラーが発生しているらしいです。
解決策はこれ
ターミナルで以下のコマンドを打ってください
chmod -R 777のあとは、cacheまでのパスを書いてくださいね。
chmod -R 777 /Applications/XAMPP/xamppfiles/htdocs/vokuro/cache
これで、cacheのアクセス権限はクリア!
もう一度見てみると、いけてました!よかった!
あとはカリキュラム通り
Vökuróは、Swiftという言語を使って、登録ユーザーのサインアップを確認するための電子メールを送信しているそう。
sends emails to confirm the sign up of registered users using Swift
composer.jsonはこうなるそうです。
実際に見たら、若干違うけど、ほとんど同じ。
{
"require" : {
"php" : ">=5.5.0",
"ext-phalcon" : ">=3.0.0",
"swiftmailer/swiftmailer" : "^5.4",
"amazonwebservices/aws-sdk-for-php" : "~1.0"
}
}
app / config / loader.phpには、最後に自動読み込み用の設定があるそう。
うん、確かにあった。
<?php
// ...
// Use composer autoloader to load vendor classes
require_once BASE_PATH . "/vendor/autoload.php";
VökuróはINVOとは違って、コントローラとモデルに名前空間を使っているそう。
ちょっと初心者の僕には理解できない・・・どういうことなんだろう、どういう違いがあるんだろう。
<?php
use Phalcon\Loader;
$loader = new Loader();
$loader->registerNamespaces(
[
"Vokuro\\Models" => $config->application->modelsDir,
"Vokuro\\Controllers" => $config->application->controllersDir,
"Vokuro\\Forms" => $config->application->formsDir,
"Vokuro" => $config->application->libraryDir,
]
);
$loader->register();
// ...
registerDirectories()を使う代わりに、registerNamespaces()を使うらしい
全ての名前空間?はapp / config / config.phpで定義されたディレクトリを指すらしい。
例えば、Vokuro\Controllersはapp/controllersを指すらしい。
でも、config.phpにそんな記述ないぞ・・・?
まあいっか、
<?php
namespace Vokuro\Controllers;
class AboutController extends ControllerBase
{
// ...
}
create an accountをクリックしたら、エラーが出ました。
(未解決ですが一旦終わります・・・)
phalconチュートリアル-Performance-
phalconのチュートリアルを学習してみます。
こちらを元に勉強しました。
phalconチュートリアル学習記録 -Performance編-
MacでXAMPPを使用しています。
このチュートリアルでは、パフォーマンスの向上について述べられています。
xdebugを入れる
1.インストールする
ターミナルで以下を入力
brew install homebrew/php/php70-xdebug
そしたら、こんなのが出てきました
/usr/local/Cellar/php70-xdebug/2.6.0: 4 files, 225.6KB
これ、どこなん笑
cd /usr/local/Cellar/
これで行ったら、無事にありました。
/usr/local/Cellar/php70-xdebug/2.6.0の中に、xdebung.soがあるのを確認してください。
- php.iniを編集
php.iniの最後の方に以下のコードを付け足します。
[xdebug]
zend_extension=/usr/local/Cellar/php70-xdebug/2.6.0/xdebug.so //xdebug.soまでのパス
xdebug.remote_enable=1
xdebug.profiler_enable = On
xdebug.profiler_output_dir = /tmp
xdebug.trace_output_dir = /tmp
- phpinfoをみる
apacheを再起動して、phpinfo()を覗いてください。
Command+Fで検索かけて、「xdebug」が見つかったらオッケーです。
webgrindを入れる
インストールしてから3時間くらい経過してこの記事を書いているんですが、
どうやって、インストールしたっけ・・・笑
多分、このサイトからかな?
まあ、このサイトでインストールできるみたいなので、ここからしましょう
webgrind
これをXAMPPのhtdocs上にインストールしました。
そして、localhost/webgrindにアクセスしすると・・・
できたっ!!
phalconチュートリアル-Invo-
phalconのチュートリアルを学習してみます。
こちらを元に勉強しました。
phalconチュートリアル-Invo-
macでxamppの上に置いてやっています
ターミナルで以下のようにコマンドを打つ
XAMPPの上におきたいからファイル移動しただけなので、好きなところにクローンしてください。
cd /Applications/XAMPP/xamppfiles/htdocs
git clone https://github.com/phalcon/invo.git
すると、テンプレ的なフォルダたちが出てきます。
http://localhost/invo
これにアクセスすると・・・
エラー出ました。。
-Vökuró編-の時と同じ対処法をやってみます。
cacheまでのパスを書いてください
chmod -R 777 /Applications/XAMPP/xamppfiles/htdocs/invo/cache
できた、、、けど、cssが適用されていない、笑
まあ良いか、、、あとで考えよう笑
構成からみていきます
<?php
use Phalcon\Config\Adapter\Ini as ConfigIni;
// ...
// Read the configuration
$config = new ConfigIni(
APP_PATH . 'app/config/config.ini' //設定ファイルを読み込みます
);
configでは、データベースやアプリケーションの登録をしているらしいです。
[database]
host = localhost //XAMPPならローカルホストで
username = root //自分のユーザーネームを入れます。「root」の人はそのままで
password = secret //自分のパスワードを入れます
name = invo //phpmyadminでinvoというデータベースを作っておきましょう
[application]
controllersDir = app/controllers/
modelsDir = app/models/
viewsDir = app/views/
pluginsDir = app/plugins/
formsDir = app/forms/
libraryDir = app/library/
baseUri = /invo/
オートローダーの部分を書いていきます
<?php
/**
* Auto-loader configuration
*/
require APP_PATH . 'app/config/loader.php';
$loader = new Phalcon\Loader(); //オートローダー使うよって宣言します
// We're a registering a set of directories taken from the configuration file
$loader->registerDirs(
[
APP_PATH . $config->application->controllersDir, //設定ファイルで定義されたディレクトリを登録
APP_PATH . $config->application->pluginsDir,
APP_PATH . $config->application->libraryDir,
APP_PATH . $config->application->modelsDir,
APP_PATH . $config->application->formsDir,
]
);
$loader->register(); //登録します
これから、サービスの登録に入っていきます。
<?php
/**
* Load application services
*/
require APP_PATH . 'app/config/services.php'; //パスを設定します
use Phalcon\Mvc\Url as UrlProvider; //urlを使う
// ...
/**
* The URL component is used to generate all kind of URLs in the application
*/
$di->set(
'url', //urlのDIをセットします
function () use ($config) {
$url = new UrlProvider(); //新しく作成
$url->setBaseUri(
$config->application->baseUri //vonfigフォルダのアプリケーションの部分のbaseUriを参照
);
return $url; //urlを返す
}
);
これから、リクエストの処理についてやります
これは、index.phpの最後まで行ったら、Phalcon\Mvc\Applicationが実行されて、アプリケーションが実行されるっていう意味らしい・・・
<?php
use Phalcon\Mvc\Application;
// ...
$application = new Application($di); //アプリケーションでDIを使う
$response = $application->handle(); //$applicationを操作します
$response->send(); //
セッションを使いたい場合
<?php
use Phalcon\Session\Adapter\Files as Session;
// ...
// Start the session the first time a component requests the session service
$di->set(
'session',
function () {
$session = new Session(); //新しいsessionを作って
$session->start(); //セッション開始
return $session; //セッション終了
}
);
セッションを使用する前に、データベースに接続する必要があります。
<?php
use Phalcon\Db\Adapter\Pdo\Mysql as DbAdapter;
// ...
// Database connection is created based on parameters defined in the configuration file
$di->set(
'db',
function () use ($config) {
return new DbAdapter(
[
'host' => $config->database->localhost, //XAMPPなたlocalhost
'username' => $config->database->username, //ユーザー名
'password' => $config->database->password, //パスワード
'dbname' => $config->database->invo, //データベース名
]
);
}
);
app/views/session/index.voltはログイン情報を要求します。
{{ form('session/start') }}
<fieldset>
<div>
<label for='email'>
Username/Email // 「Username/Email」というラベルを用意
</label>
<div>
{{ text_field('email') }} //emailを打つスペースを用意
</div>
</div>
<div>
<label for='password'> //「password」というラベルを表示
Password
</label>
<div>
{{ password_field('password') }} //passwordを打つスペースを用意
</div>
</div>
<div>
{{ submit_button('Login') }} //「Login」というボタンを用意し、ボタンを押したらsubmit
</div>
</fieldset>
{{ endForm() }}
app/controllers/SessionController.phpの「SessionController」の中の「startAction」は、データベースに有効なユーザーのチェックなど、フォームに入力されたデータを検証する作業を記すことができる
わかりやすくするためにsha1を使用してデータベースにパスワードハッシュを格納しましたが、このアルゴリズムは実際のアプリケーションではお勧めできません。代わりにbcryptを使用してください。
ちなみに、bindはPhalconモデルまとめ(1)データ取得の基本に書いてあります。
ちなみに、flashには「success」「error」「notice」「warning」があるそう
参考サイトはこちら→ Phalconのフラッシュメッセージに書いてあります。
<?php
class SessionController extends ControllerBase //ControllerBAseを継承して、SessionControllerを作る
{
// ...
private function _registerSession($user)
{
$this->session->set(
'auth',
[
'id' => $user->id, //sessionを使って、idとnameを変数に格納
'name' => $user->name,
]
);
}
/**
* This action authenticate and logs a user into the application
* ユーザー認証をして、ログインする
*/
public function startAction()
{
if ($this->request->isPost()) { //POSTでデータを送る
// Get the data from the user
$email = $this->request->getPost('email'); //emailを取得
$password = $this->request->getPost('password'); //passwordを取得
// Find the user in the database
$user = Users::findFirst(
[
"(email = :email: OR username = :email:) AND password = :password: AND active = 'Y'", //データベースに同じemail or username 、passwordがあるか、activeかを調べる。
'bind' => [ //bindはこのコードの上のリンクをご覧ください。
'email' => $email,
'password' => sha1($password), //これではsha1の方が伝えやすいから使っているが、bcryptを推奨しているらしい
]
]
);
if ($user !== false) { //データベースにユーザーが存在しなかったら・・・
$this->_registerSession($user); //フォームが表示されているアクションにユーザーを再度戻す
$this->flash->success( //うまくいったら... (フラッシュについてはこのコードのを参考に)
'Welcome ' . $user->name
);
// 'invoices' controller if the user is valid ユーザーが有効ならinvoicesコントローラーにいく
return $this->dispatcher->forward( //転送
[
'controller' => 'invoices', //invoicesコントローラーの
'action' => 'index', //indexActionに
]
);
}
$this->flash->error( //エラーをだす
'Wrong email/password'
);
}
// Forward to the login form again もう一回ログインフォームへ
return $this->dispatcher->forward( //転送
[
'controller' => 'session', //sessionコントローラーの
'action' => 'index', //indexActionに
]
);
}
}
バックエンドのセキュリティ
バックエンドは、登録ユーザーのみがアクセスできるプライベートエリアです。したがって、登録されたユーザーだけがこれらのコントローラにアクセスできることを確認する必要があります。
Dispatcherというコンポーネントを使用し、次に、適切なコントローラをロードし、対応するアクションメソッドを実行します。
<?php
use Phalcon\Mvc\Dispatcher;
// ...
/**
* MVC dispatcher
*/
$di->set(
'dispatcher',
function () {
// ...
$dispatcher = new Dispatcher(); //新しいdispatcherを生成する
return $dispatcher; //返す
}
);
EventsManagerという新しいコンポーネントを使用して、イベント管理をする
イベントについてのまとめ記事は参考になります⇨Phalcon アクション周りのイベントとかメモ
<?php
use Phalcon\Mvc\Dispatcher;
use Phalcon\Events\Manager as EventsManager;
$di->set(
'dispatcher',
function () {
// Create an events manager
$eventsManager = new EventsManager(); //イベントマネージャーを生成
// Listen for events produced in the dispatcher using the Security plugin セキュリティー・プラグインを使用してディスパッチャーで生成されたイベントをリッスンします。
$eventsManager->attach( //プラグインはattachで処理を埋め込むように使うらしい
'dispatch:beforeExecuteRoute', //ディスパッチループが回るごとに一回でアクションがあったら実行
new SecurityPlugin()
);
// Handle exceptions and not-found exceptions using NotFoundPlugin
NotFoundPluginを使用して例外や未発見の例外を処理する
$eventsManager->attach(
'dispatch:beforeException', //例外が投げられると、beforeExceptionが投げられ実行される
new NotFoundPlugin()
);
$dispatcher = new Dispatcher(); //dispatcherを生成する
// Assign the events manager to the dispatcher イベントマネージャをディスパッチャに割り当てます。
$dispatcher->setEventsManager($eventsManager);
return $dispatcher;
}
);
ちなみに、SecurityPluginは、app/plugins/SecurityPlugin.phpにあります。
ACLについてはこちら ⇨ Phalconのアクセス制御リストACL
<?php
use Phalcon\Acl;
use Phalcon\Events\Event;
use Phalcon\Mvc\User\Plugin;
use Phalcon\Mvc\Dispatcher;
class SecurityPlugin extends Plugin
{
// ...
public function beforeExecuteRoute(Event $event, Dispatcher $dispatcher)
{
// Check whether the 'auth' variable exists in session to define the active role アクティブな役割を定義するために 'auth'変数がセッションに存在するかどうかを確認します
$auth = $this->session->get('auth');
if (!$auth) {
$role = 'Guests'; //$authがなければ変数roleに、「Guest」を代入する
} else {
$role = 'Users'; //$authがあれば変数roleに、「Users」を代入する
}
// Take the active controller/action from the dispatcher ディスパッチャからアクティブコントローラ/アクションを取得する
$controller = $dispatcher->getControllerName();//コントローラ名を取得して代入
$action = $dispatcher->getActionName(); //アクション名を取得して代入
// Obtain the ACL list ACLリストを取得する
$acl = $this->getAcl(); //ACL生成
// Check if the Role have access to the controller (resource) 役割($role)がコントローラ(リソース)にアクセスできるかどうかを確認する
$allowed = $acl->isAllowed($role, $controller, $action);
if (!$allowed) {
// If he doesn't have access forward him to the index controller インデックスコントローラーにアクセスする権利がなかったら
$this->flash->error( //エラーメッセージを出す
"You don't have access to this module"
);
$dispatcher->forward( //転送
[
'controller' => 'index', //indexコントローラーの
'action' => 'index', //indexActionに
]
);
// Returning 'false' we tell to the dispatcher to stop the current operation 「false」を返すと、現在の操作を停止するようにディスパッチャに指示します。
return false;
}
}
}
ACLリストの取得
$this->getAcl()でACLを取得
<?php
use Phalcon\Acl;
use Phalcon\Acl\Role;
use Phalcon\Acl\Adapter\Memory as AclList;
// Create the ACL
$acl = new AclList(); //acl生成
// The default action is DENY access デフォルトのアクションはDENYアクセスです
$acl->setDefaultAction(
Acl::DENY
);
// Register two roles, Users is registered users 2つの役割を登録します。ユーザーは登録済みのユーザーです
// and guests are users without a defined identity ゲストは特定のIDがないユーザーです
$roles = [
'users' => new Role('Users'),
'guests' => new Role('Guests'),
];
foreach ($roles as $role) {
$acl->addRole($role);
}
各領域のリソースをそれぞれ定義します。コントローラ名はリソースであり、そのアクションはリソースへのアクセスです。各領域のリソースをそれぞれ定義します。コントローラ名はリソースであり、そのアクションはリソースへのアクセスです。
<?php
use Phalcon\Acl\Resource;
// ...
// Private area resources (backend) プライベートエリアリソース(バックエンド)
$privateResources = [
'companies' => ['index', 'search', 'new', 'edit', 'save', 'create', 'delete'],
'products' => ['index', 'search', 'new', 'edit', 'save', 'create', 'delete'],
'producttypes' => ['index', 'search', 'new', 'edit', 'save', 'create', 'delete'],
'invoices' => ['index', 'profile'],
];
foreach ($privateResources as $resourceName => $actions) {
$acl->addResource(
new Resource($resourceName), //resourceNameを追加
$actions
);
}
// Public area resources (frontend) 公共エリアのリソース(フロントエンド)
$publicResources = [
'index' => ['index'],
'about' => ['index'],
'register' => ['index'],
'errors' => ['show404', 'show500'],
'session' => ['index', 'register', 'start', 'end'],
'contact' => ['index', 'send'],
];
foreach ($publicResources as $resourceName => $actions) {
$acl->addResource(
new Resource($resourceName), //resourceNameを追加
$actions
);
}
ACLは現在、既存のコントローラとその関連するアクションについて認識しています。ロールUsersは、フロントエンドとバックエンドの両方のすべてのリソースにアクセスできます。役割Guestsは公共エリアへのアクセスのみを持っています:
<?php
// Grant access to public areas to both users and guests ユーザーとゲストの両方にパブリックエリアへのアクセスを許可する
foreach ($roles as $role) {
foreach ($publicResources as $resource => $actions) {
$acl->allow( //アクセスを許可する
$role->getName(), //名前を取得
$resource,
'*'
);
}
}
// Grant access to private area only to role Users 役割のUserのみにプライベートエリアへのアクセスを許可する
foreach ($privateResources as $resource => $actions) {
foreach ($actions as $action) {
$acl->allow(
'Users',
$resource,
$action
);
}
}
CRUDの操作
これは、Phalconがフォーム、バリデーション、ページネーターなどを使用して簡単に行える非常に一般的なタスクです。
INVO(企業、製品、製品の種類)のデータを操作するほとんどのオプションは、基本的で共通のCRUD(作成、読み取り、更新、削除)を使用して開発されました。各CRUDには、次のファイルが含まれています。
invo/
app/
controllers/
ProductsController.php
models/
Products.php
forms/
ProductsForm.php
views/
products/
edit.volt
index.volt
new.volt
search.volt
検索フォーム
すべてのCRUDは検索フォームから始まります。このフォームは、テーブルにある各フィールド(製品)を表示し、ユーザーが任意のフィールドの検索条件を作成できるようにします。
<?php
/**
* The start action, it shows the 'search' view
*/
public function indexAction()
{
$this->persistent->searchParams = null; //searchparamsをnullにする
$this->view->form = new ProductsForm(); //新しいformを作る
}
ProductsFormのインスタンスがビューに渡されます。
次に扱うフォームについての前提知識として、これは知っておいた方がいいかもしれません
フロントエンド:フォーム Phalconフレームワーク
あとで出てくるPhalconのバリデーションについてはこちら
Phalconモデルまとめ(4) バリデーションとイベント
バリデーションのNumericalityについて詳しい内容はこちら
Class Phalcon\Validation\Validator\Numericality
<?php
use Phalcon\Forms\Form;
use Phalcon\Forms\Element\Text;
use Phalcon\Forms\Element\Hidden;
use Phalcon\Forms\Element\Select;
use Phalcon\Validation\Validator\Email;
use Phalcon\Validation\Validator\PresenceOf;
use Phalcon\Validation\Validator\Numericality;
class ProductsForm extends Form //Formを継承して、ProductsFromクラスを作成
{
/**
* Initialize the products form 初期化
*/
public function initialize($entity = null, $options = []) //initializeという関数を作成($entituy=null, $options=[]は初期値)
{
if (!isset($options['edit'])) { //変数optionsにeditが入っていなければ
$element = new Text('id'); //変数elementに'id'という1行のテキストを入れるボックス
$element->setLabel('Id'); //変数elementに'Id'というラベルを代入
$this->add($element); // で、実際に追加
} else { //もし変数optionsにeditが入っていれば
$this->add(new Hidden('id')); //表示はしないが、データを送りたいからhiddenで追加
}
$name = new Text('name'); //変数nameに'name'という1行のテキストボックスを代入
$name->setLabel('Name'); //変数nameに'Name'というラベルを代入
$name->setFilters( //データを検証する前にフィルターをかける
[
'striptags', //HTMLタグも残しておく (『<p>あ</p>』を普通に表示すると『あ』になるが、これを設定るすと『<p>あ</p>』で出力する)
'string', //文字列として出力?
]
);
$name->addValidators( //バリデーションを付け足す
[
new PresenceOf( //フィールドにNOT NULL制約が付与されているときに、null値をINSERT/UPDATEしようとした際に発生
[
'message' => 'Name is required', //メッセージを表示
]
)
]
);
$this->add($name); //$nameを表示
$type = new Select( //セレクトタグを生成??
'profilesId',
ProductTypes::find(), //'product_typesからのデータを格納
[
'using' => [
'id',
'name',
],
'useEmpty' => true,
'emptyText' => '...',
'emptyValue' => '',
]
);
$this->add($type); //変数typeを表示
$price = new Text('price'); //変数priceに1行のテキストボックスを代入
$price->setLabel('Price'); //変数priceに'Price'というラベルを追加
$price->setFilters(
[
'float', //float型にするってことかな?
]
);
$price->addValidators( //バリデーションをつける
[
new PresenceOf( //フィールドにNOT NULL制約が付与されているときに、null値をINSERT/UPDATEしようとした際に発生
[
'message' => 'Price is required', //メッセージを表示
]
),
new Numericality( //有効な数字を確認する
[
'message' => 'Price is required', //メッセージを表示
]
),
]
);
$this->add($price);//$priceを追加
}
}
フォームはだいたいこの構造らしいです
知っといた方がいいやつですね
<?php
// Create the element
$name = new Text('name');
// Set its label
$name->setLabel('Name');
// Before validating the element apply these filters
$name->setFilters(
[
'striptags',
'string',
]
);
// Apply this validators
$name->addValidators(
[
new PresenceOf(
[
'message' => 'Name is required',
]
)
]
);
// Add the element to the form
$this->add($name);
検索の実行
searchアクションは、2つの動作があります。POST経由でアクセスすると、フォームから送信されたデータに基づいて検索が実行されますが、GET経由でアクセスすると、現在のページがページネーターに移動します。HTTPメソッドを区別するために、Requestコンポーネントを使用してチェックします。
<?php
/**
* Execute the 'search' based on the criteria sent from the 'index' 「インデックス」から送信された基準に基づいて「検索」を実行します。
* Returning a paginator for the results 結果のページ数を返す
*/
public function searchAction() //search.voltを実行
{
if ($this->request->isPost()) { //requestがpostだったら
// Create the query conditions クエリ条件を作成する
} else {
// Paginate using the existing conditions 既存の条件を使用して改ページする
}
// ...
}
Phalcon \ Mvc \ Model \ Criteriaの助けを借りて、フォームから送信されたデータ型と値に基づいて、検索条件をインテリジェントに作成できます
以下で使う、criteriaについてはこちら
Class Phalcon\Mvc\Model\Criteria
<?php
$query = Criteria::fromInput( //_POSTのような入力配列に基づいてPhalcon\Mvc\Model\Criteriaを構築する
$this->di, //diを参照
'Products',
$this->request->getPost() //POSTのデータを返す
);
生成されたパラメータをコントローラのセッションバッグに格納します。
セッションバッグは、セッションサービスを使用する要求の間に持続するコントローラ内の特殊な属性です。アクセスされると、この属性は各コントローラーで独立したPhalcon \ Session \ Bagインスタンスを挿入します。
セッションバッグは、セッションのデータを名前空間で分別するのに役立つ
Class Phalcon\Session\Bag
$this->persistent->searchParams = $query->getParams();
次に、構築されたパラメータに基づいてクエリを実行します。
<?php
$products = Products::find($parameters); //Productsの「$parameters」を照会しているのかな?
if (count($products) === 0) { //$productsが0だったら
$this->flash->notice( //メッセージを表示
'The search did not found any products'
);
return $this->dispatcher->forward( //forwardは「転送」的な感じ、
[
'controller' => 'products', //productsコントローラーの
'action' => 'index', //indexActionに
]
);
}
検索で商品が返されない場合は、ユーザーを再度インデックス操作に転送します。返された検索結果をふりかえってみましょう。その後、それらを簡単にナビゲートするためにページ設定を作成します。
Paginationについても見ておきましょう。
Pagination
<?php
use Phalcon\Paginator\Adapter\Model as Paginator;
// ...
$paginator = new Paginator( //Paginatorを生成(表示する情報量を制限するときに使う)
[
'data' => $products, //
'limit' => 5, // 5ページまで
'page' => $numberPage, // アクティブページ
]
);
// Get active page in the paginator
$page = $paginator->getPaginate(); //アクティブページを代入
最後に、返されたページを渡して表示します:
<?php
$this->view->page = $page;
app/models/Products.phpを見てみる
belongsToがかかれてあるやつ
Phalconモデルまとめ(2)リレーション
reusableがかかれている
ORMでのキャッシュ
<?php
use Phalcon\Mvc\Model;
/**
* Products
*/
class Products extends Model //Modelを継承して、Productsクラスを作る
{
// ...
/**
* Products initializer
*/
public function initialize() //リクエストごとに一回呼び出され、ORMを使って初期化
{
$this->belongsTo( //belongsToは多対1のときに使う 関連するレコードのモデルを返す
'product_types_id',
'ProductTypes',
'id',
[
'reusable' => true, //同じデータが何回も照会されるのを防ぐ
]
);
}
// ...
}
Productsにある「product_types_id」というローカル属性は、「ProductTypes」モデルに対して、1対多の関係性を持つ
この関係を定義することによって、以下を使用して製品タイプの名前にアクセスできます。
<td>{{ product.productTypes.name }}</td>
<td>{{ '%.2f'|format(product.price) }}</td>
普通のphpだと
<?php echo sprintf('%.2f', $product->price) ?>
レコードの作成と更新
「new」と「edit」のビューから、「create」,[save]アクションにデータが送られる
作成のケースでは、送信されたデータを回復し、新しいProductsインスタンスに割り当てます。
<?php
/**
* Creates a product based on the data entered in the 'new' action 「new」アクションで入力されたデータに基づいて製品を作成します。
*/
public function createAction()
{
if (!$this->request->isPost()) { //もしPOSTされていなかったら
return $this->dispatcher->forward( //転送
[
'controller' => 'products', //productsコントローラーの
'action' => 'index', //indexActionに
]
);
}
$form = new ProductsForm(); //formを生成
$product = new Products(); //新しいproductsインスタンスを生成
$product->id = $this->request->getPost('id', 'int'); //それぞれ取得して代入
$product->product_types_id = $this->request->getPost('product_types_id', 'int');
$product->name = $this->request->getPost('name', 'striptags');
$product->price = $this->request->getPost('price', 'double');
$product->active = $this->request->getPost('active');
// ...
}
データが代入される前に、(プロダクトフォームで定義したフィルター「以下のフォーム」)フィルタリングされる
<?php
// ...
$name = new Text('name');
$name->setLabel('Name');
// Filters for name
$name->setFilters(
[
'striptags',
'string',
]
);
// Validators for name
$name->addValidators(
[
new PresenceOf(
[
'message' => 'Name is required',
]
)
]
);
$this->add($name);
最後に、フォームから検証メッセージが返されない場合は、製品インスタンスを保存できます。
<?php
// ...
if ($product->save() === false) { //saveがミスったら
$messages = $product->getMessages(); //メッセージを取得して
foreach ($messages as $message) {
$this->flash->error($message); //エラーを表示
}
return $this->dispatcher->forward( //転送
[
'controller' => 'products', //productsコントローラーの
'action' => 'new', //newActionに
]
);
}
$form->clear(); //フォームをクリアする
$this->flash->success( //成功のメッセージを出す
'Product was created successfully'
);
return $this->dispatcher->forward( //転送
[
'controller' => 'products', //productsコントローラーの
'action' => 'index', //indexActionに
]
);
さて、製品を更新する場合は、まず、編集されたレコードに現在あるデータをユーザーに提示する必要があります。
<?php
/**
* Edits a product based on its id
*/
public function editAction($id)
{
if (!$this->request->isPost()) { //POSTされなかったら
$product = Products::findFirstById($id); //最初のID
if (!$product) { //productsが入っていなければ
$this->flash->error( //エラーを出す
'Product was not found'
);
return $this->dispatcher->forward( //転送
[
'controller' => 'products', //productsコントローラーの
'action' => 'index', //indexActionに
]
);
}
$this->view->form = new ProductsForm( //新しいフォームを作って
$product,
[
'edit' => true,
]
);
}
}
見つかったデータは、最初のパラメータとしてモデルを渡すことによってフォームにバインドされます。これにより、ユーザーは任意の値を変更してから、saveアクションを実行してデータベースに戻すことができます。
以下出現するバリデーション「isValid()」について
Phalcon でモデルにフォームの内容を保存する
<?php
/**
* Updates a product based on the data entered in the 'edit' action
*/
public function saveAction()
{
if (!$this->request->isPost()) { //POSTされなかったら
return $this->dispatcher->forward( //転送
[
'controller' => 'products', //productsコントローラーの
'action' => 'index', //indexActionに
]
);
}
$id = $this->request->getPost('id', 'int'); //idをint型で取得?
$product = Products::findFirstById($id); //$idの最初のやつを検索
if (!$product) { //$productsがなければ
$this->flash->error( //エラーを出す
'Product does not exist'
);
return $this->dispatcher->forward( //転送
[
'controller' => 'products', //productsコントローラーの
'action' => 'index', //indexActionに
]
);
}
$form = new ProductsForm(); //新しいフォームを作る
$data = $this->request->getPost(); //データを受け取る
if (!$form->isValid($data, $product)) { //バリデーションを使う
$messages = $form->getMessages(); //メッセージを代入
foreach ($messages as $message) {
$this->flash->error($message); //エラーメッセージを出力
}
return $this->dispatcher->forward( //転送
[
'controller' => 'products', //productsコントローラーの
'action' => 'new', //newActionに
]
);
}
if ($product->save() === false) { //saveがミスったら
$messages = $product->getMessages(); //メッセージを受け取る
foreach ($messages as $message) {
$this->flash->error($message); //エラーメッセージを表示
}
return $this->dispatcher->forward( //転送
[
'controller' => 'products', //productsコントローラーの
'action' => 'new', //newActionに
]
);
}
$form->clear(); //フォームをクリアして
$this->flash->success( //成功のメッセージを表示
'Product was updated successfully'
);
return $this->dispatcher->forward( //転送
[
'controller' => 'products', //productsコントローラーの
'action' => 'index', //newActionに
]
);
}
ユーザーコンポーネント
アプリケーションのすべてのUI要素とビジュアルスタイルは、主にBootstrapを通じて実現されています。アプリケーションの状態に応じてナビゲーションバーなどの一部の要素が変更されます。たとえば、右上のコーナーでは、ユーザーがアプリケーションにログインしている場合にリンクLog in/Sign UpがLog outに変更されます。
コンポーネントはこうやって書いていくよっていう紹介なのかな?
<?php
use Phalcon\Mvc\User\Component; //コンポーネントを使う
class Elements extends Component //コンポーネントクラスを拡張して、Elementsクラスを作る
{
public function getMenu()
{
// Register a user component ユーザーの登録のコンポーネント
$di->set(
'elements',
function () {
return new Elements();
}
);
}
public function getTabs()
{
// ...
}
}
ビュー内のコントローラ、プラグイン、またはコンポーネントとして、このコンポーネントは、コンテナに登録されているサービスにアクセスし、以前に登録したサービスと同じ名前の属性にアクセスするだけでアクセスできます。
<div class='navbar navbar-fixed-top'>
<div class='navbar-inner'>
<div class='container'>
<a class='btn btn-navbar' data-toggle='collapse' data-target='.nav-collapse'>
<span class='icon-bar'></span>
<span class='icon-bar'></span>
<span class='icon-bar'></span>
</a>
<a class='brand' href='#'>INVO</a>
{{ elements.getMenu() }} //⇦この部分
</div>
</div>
</div>
<div class='container'>
{{ content() }}
<hr>
<footer>
<p>© Company 2017</p>
</footer>
</div>
動的にタイトルを変更する
あるオプションと別のオプションを参照すると、現在作業している場所を示すタイトルが動的に変更されます。これは、各コントローラーのイニシャライザーで実現されます。
<?php
class ProductsController extends ControllerBase //ControllerBaseクラスを継承して、ProductsControllerクラスを作る
{
public function initialize()
{
// Set the document title
$this->tag->setTitle( //titleをセット
'Manage your product types'
);
parent::initialize(); //これが実行されると、タイトルに「Manage your product types」が追加
}
// ...
}
終わった・・・・。