Symfony-advanced-concepts
Symfony-高度なコンセプト
この章では、Symfonyフレームワークのいくつかの高度な概念について学びます。
HTTPキャッシュ
Webアプリケーションでキャッシュすると、パフォーマンスが向上します。 たとえば、ショッピングカートWebアプリケーションのホットな製品は、限られた時間だけキャッシュできるため、データベースにアクセスすることなく迅速に顧客に提示できます。 以下は、キャッシュのいくつかの基本的なコンポーネントです。
キャッシュアイテム
キャッシュアイテムは、キー/値のペアとして保存される情報の単一ユニットです。 key は文字列で、 value は任意のPHPオブジェクトにすることができます。 PHPオブジェクトは、シリアル化によって文字列として保存され、アイテムの読み取り中にオブジェクトに変換されます。
キャッシュアダプター
キャッシュアダプターは、アイテムをストアに格納する実際のメカニズムです。 ストアは、メモリ、ファイルシステム、データベース、redisなどです。 キャッシュコンポーネントは、アダプターがキャッシュアイテムをバックエンドストアに保存できる AdapterInterface を提供します。 多くの組み込みキャッシュアダプターが利用可能です。 それらのいくつかは次のとおりです-
- 配列キャッシュアダプター-キャッシュアイテムはPHP配列に格納されます。
- ファイルシステムキャッシュアダプター-キャッシュアイテムはファイルに保存されます。
- PHPファイルキャッシュアダプター-キャッシュアイテムはphpファイルとして保存されます。
- APCuキャッシュアダプター-キャッシュアイテムは、PHP APCu拡張を使用して共有メモリに保存されます。
- Redis Cache Adapter-キャッシュアイテムはRedisサーバーに保存されます。
- PDOおよびDoctrine DBALキャッシュアダプター-キャッシュアイテムはデータベースに保存されます。
- チェーンキャッシュアダプター-レプリケーションのために複数のキャッシュアダプターを組み合わせます。
- プロキシキャッシュアダプター-キャッシュアイテムは、CacheItemPoolInterfaceを実装するサードパーティのアダプターを使用して保存されます。
キャッシュプール
キャッシュプールは、キャッシュアイテムの論理リポジトリです。 キャッシュプールは、キャッシュアダプターによって実装されます。
シンプルなアプリケーション
キャッシュの概念を理解するための簡単なアプリケーションを作成しましょう。
ステップ1 *-新しいアプリケーション *cache-example を作成します。
cd/path/to/app
mkdir cache-example
cd cache-example
- ステップ2 *-キャッシュコンポーネントをインストールします。
composer require symfony/cache
- ステップ3 *-ファイルシステムアダプターを作成します。
require __DIR__ . '/vendor/autoload.php';
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
$cache = new FilesystemAdapter();
ステップ4 *-アダプタの *getItem および set メソッドを使用してキャッシュアイテムを作成します。 getItemは、キーを使用してキャッシュアイテムを取得します。 キーが永続的でない場合、新しいアイテムが作成されます。 setメソッドは実際のデータを保存します。
$usercache = $cache->getitem('item.users');
$usercache->set(['jon', 'peter']);
$cache->save($usercache);
ステップ5 *- *getItem、isHit 、および get メソッドを使用してキャッシュアイテムにアクセスします。 isHitはキャッシュアイテムの可用性を通知し、getメソッドは実際のデータを提供します。
$userCache = $cache->getItem('item.users');
if(!$userCache->isHit()) {
echo "item.users is not available";
} else {
$users = $userCache->get();
var_dump($users);
}
ステップ6 *- *deleteItem メソッドを使用してキャッシュアイテムを削除します。
$cache->deleteItem('item.users');
完全なコードリストは次のとおりです。
<?php
require __DIR__ . '/vendor/autoload.php';
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
$cache = new FilesystemAdapter();
$usercache = $cache->getitem('item.users');
$usercache->set(['jon', 'peter']);
$cache->save($usercache);
$userCache = $cache->getItem('item.users');
if(!$userCache->isHit()) {
echo "item.users is not available";
} else {
$users = $userCache->get();
var_dump($users);
}
$cache->deleteItem('item.users');
?>
結果
array(2) {
[0]=>
string(3) "jon"
[1]=>
string(5) "peter"
}
デバッグ
デバッグは、アプリケーションの開発中に最も頻繁に行われるアクティビティの1つです。 symfonyは、デバッグのプロセスを容易にするための別個のコンポーネントを提供します。 Debugクラスの enable メソッドを呼び出すだけでSymfonyデバッグツールを有効にできます。
use Symfony\Component\Debug\Debug
Debug::enable()
symfonyは、デバッグ用に ErrorHandler と ExceptionHandler の2つのクラスを提供します。 ErrorHandlerはPHPエラーをキャッチして例外、ErrorExceptionまたはFatalErrorExceptionに変換しますが、ExceptionHandlerはキャッチされなかったPHP例外をキャッチし、有用なPHP応答に変換します。 ErrorHandlerとExceptionHandlerはデフォルトで無効になっています。 registerメソッドを使用して有効にすることができます。
use Symfony\Component\Debug\ErrorHandler;
use Symfony\Component\Debug\ExceptionHandler;
ErrorHandler::register();
ExceptionHandler::register();
Symfony Webアプリケーションでは、デバッグ環境*はDebugBundleによって提供されます。 AppKernelの *registerBundles メソッドでバンドルを登録して有効にします。
if (in_array($this->getEnvironment(), ['dev', 'test'], true)) {
$bundles[] = new Symfony\Bundle\DebugBundle\DebugBundle();
}
プロファイラ
アプリケーションの開発には、世界クラスのプロファイリングツールが必要です。 プロファイリングツールは、実行時間、個々のモジュールの実行時間、データベースアクティビティにかかった時間、メモリ使用量など、アプリケーションに関するすべての実行時情報を収集します。 Webアプリケーションには、要求の時間、応答の作成にかかる時間など、はるかに多くの情報が必要です。 上記の指標に加えて。
symfonyは、デフォルトでWebアプリケーションでそのようなすべての情報を有効にします。 symfonyは WebProfilerBundle と呼ばれるWebプロファイリング用の個別のバンドルを提供します。 AppKernelのregisterBundlesメソッドでバンドルを登録することにより、WebアプリケーションでWebプロファイラーバンドルを有効にできます。
if (in_array($this->getEnvironment(), ['dev', 'test'], true)) {
$bundles[] = new Symfony\Bundle\WebProfilerBundle\WebProfilerBundle();
}
Webプロファイルコンポーネントは、アプリケーション構成ファイル app/config/config.xml の* web_profileセクション*で構成できます。
web_profiler:
toolbar: false
position: bottom
symfonyアプリケーションは、ページの下部にプロファイルされたデータを個別のセクションとして表示します。
symfonyは、* DataCollectorInterfaceインターフェース*とtwigテンプレートを使用して、プロファイルデータにページに関するカスタム詳細を追加する簡単な方法も提供します。 要するに、Symfonyを使用すると、優れたプロファイリングフレームワークを比較的簡単に提供することにより、Web開発者は世界クラスのアプリケーションを作成できます。
セキュリティ
前述したように、Symfonyはセキュリティコンポーネントを通じて堅牢なセキュリティフレームワークを提供します。 セキュリティコンポーネントは、次の4つのサブコンポーネントに分かれています。
- symfony/security-core-コアセキュリティ機能。
- symfony/security-http-HTTPプロトコルの統合セキュリティ機能。
- symfony/security-csrf-Webアプリケーションでのクロスサイトリクエストフォージェリに対する保護。
- symfony/security-acl-高度なアクセス制御リストベースのセキュリティフレームワーク。
簡単な認証と承認
簡単なデモアプリケーションを使用して、認証と承認の概念を学びましょう。
ステップ1 *-次のコマンドを使用して、新しいWebアプリケーション *securitydemo を作成します。
symfony new securitydemo
ステップ2 *-セキュリティ構成ファイルを使用して、アプリケーションのセキュリティ機能を有効にします。 セキュリティ関連の設定は、個別のファイル *security.yml に配置されます。 デフォルトの構成は次のとおりです。
security:
providers:
in_memory:
memory: ~
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
anonymous: ~
#http_basic: ~
#form_login: ~
デフォルト設定では、メモリベースのセキュリティプロバイダーとすべてのページへの匿名アクセスが有効になっています。 ファイアウォールセクションは、パターンに一致するファイル ^/(_(profiler | wdt)| css | images | js)/ をセキュリティフレームワークから除外します。 デフォルトのパターンには、スタイルシート、画像、JavaScript(およびプロファイラーなどの開発ツール)が含まれます。
- ステップ3 *-メインセクションに次のようにhttp_basicオプションを追加して、HTTPベースのセキュリティ認証システムを有効にします。
security:
# ...
firewalls:
# ...
main:
anonymous: ~
http_basic: ~
#form_login: ~
- ステップ4 *-メモリプロバイダーセクションにユーザーを追加します。 また、ユーザーのロールを追加します。
security:
providers:
in_memory:
memory:
users:
myuser:
password: user
roles: 'ROLE_USER'
myadmin:
password: admin
roles: 'ROLE_ADMIN'
ロールROLE_USERの_user_とロールROLE_ADMINの_admin_の2人のユーザーを追加しました。
- ステップ5 *-エンコーダーを追加して、現在ログインしているユーザーの完全な詳細を取得します。 エンコーダーの目的は、Web要求から現在のユーザーオブジェクトの完全な詳細を取得することです。
security:
# ...
encoders:
Symfony\Component\Security\Core\User\User: bcrypt
# ...
symfonyは、ユーザー名、ロール、パスワードなどのユーザーの詳細を取得するためのインターフェイス UserInterface を提供します。 要件へのインターフェイスを実装し、エンコーダセクションで構成する必要があります。
たとえば、ユーザーの詳細がデータベースにあるとします。 次に、新しいUserクラスを作成し、UserInterfaceメソッドを実装して、データベースからユーザーの詳細を取得する必要があります。 データが使用可能になると、セキュリティシステムはそのデータを使用してユーザーを許可/拒否します。 symfonyはメモリプロバイダーのデフォルトのユーザー実装を提供します。 アルゴリズムを使用して、ユーザーパスワードを復号化します。
ステップ6 *- *bcrypt アルゴリズムを使用してユーザーパスワードを暗号化し、構成ファイルに配置します。 bcrypt アルゴリズムを使用したため、ユーザーオブジェクトは、構成ファイルで指定されたパスワードの暗号化を解除し、ユーザーが入力したパスワードとの照合を試みます。 symfonyコンソールアプリケーションは、パスワードを暗号化する簡単なコマンドを提供します。
php bin/console security:encode-password admin
Symfony Password Encoder Utility
================================
------------------ -----------------------------------
Key Value
------------------ ------------------------------------
Encoder used Symfony\Component\Security\Core\Encoder\BCryptPasswordEncoder
Encoded password
$2y$12$0Hy6/.MNxWdFcCRDdstHU.hT5j3Mg1tqBunMLIUYkz6..IucpaPNO
------------------ ------------------------------------
! [NOTE] Bcrypt encoder used: the encoder generated its own built-in salt.
[OK] Password encoding succeeded
- ステップ7 *-コマンドを使用して暗号化されたパスワードを生成し、構成ファイルで更新します。
# To get started with security, check out the documentation:
# http://symfony.com/doc/current/securityl
security:
# http://symfony.com/doc/current/securityl#b-configuring-how-users-are-loaded
providers:
in_memory:
memory:
users:
user:
password: $2y$13$WsGWNufreEnVK1InBXL2cO/U7WftvfNvH
Vb/IJBH6JiYoDwVN4zoi
roles: 'ROLE_USER'
admin:
password: $2y$13$jQNdIeoNV1BKVbpnBuhKRuOL01NeMK
F7nEqEi/Mqlzgts0njK3toy
roles: 'ROLE_ADMIN'
encoders:
Symfony\Component\Security\Core\User\User: bcrypt
firewalls:
# disables authentication for assets and the profiler,
# adapt it according to your needs
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
anonymous: ~
# activate different ways to authenticate
# http://symfony.com/doc/current/securityl#a-co
nfiguring-howyour-users-will-authenticate
http_basic: ~
# http://symfony.com/doc/current/cookbook/security/
form_login_setupl
#form_login: ~
- ステップ8 *-次に、アプリケーションの一部のセクションにセキュリティを適用します。 たとえば、ロールのユーザーROLE_ADMINに管理セクションを制限します。
security:
# ...
firewalls:
# ...
default:
# ...
access_control:
# require ROLE_ADMIN for/admin*
- { path: ^/admin, roles: 'ROLE_ADMIN' }
- ステップ9 *-次のようにDefaultControllerに管理ページを追加します。
/* *
* @Route("/admin")
*/
public function adminLandingAction() {
return new Response('<html><body>This is admin section.</body></html>');
}
- ステップ10 *-最後に、管理ページにアクセスして、ブラウザのセキュリティ設定を確認します。 ブラウザはユーザー名とパスワードを要求し、設定されたユーザーのみを許可します。
結果
ワークフロー
ワークフローは、多くのエンタープライズアプリケーションで使用される高度な概念です。 eコマースアプリケーションでは、製品配信プロセスはワークフローです。 製品は最初に請求され(注文の作成)、ストアから調達され、パッケージ化され(パッケージング/発送準備完了)、ユーザーに発送されます。 問題がある場合、製品はユーザーから返品され、注文は元に戻されます。 アクションのフローの順序は非常に重要です。 たとえば、請求せずに製品を提供することはできません。
symfonyコンポーネントは、ワークフローを定義および管理するオブジェクト指向の方法を提供します。 プロセスの各ステップは place と呼ばれ、ある場所から別の場所に移動するために必要なアクションは transition と呼ばれます。 ワークフローを作成するための場所と遷移のコレクションは、*ワークフロー定義*と呼ばれます。
休暇管理用の簡単なアプリケーションを作成して、ワークフローの概念を理解しましょう。
ステップ1 *-新しいアプリケーション *workflow-example を作成します。
cd/path/to/dev
mkdir workflow-example
cd workflow-example
composer require symfony/workflow
ステップ2 *- *applied_by、leave_on および status 属性を持つ新しいクラス Leave を作成します。
class Leave {
public $applied_by;
public $leave_on;
public $status;
}
ここで、apply_byは退職を希望する従業員を指します。 leave_onは休暇の日付を指します。 ステータスは休暇ステータスを指します。
- ステップ3 *-休暇管理には4つの場所があります。適用、in_process、承認/拒否です。
use Symfony\Component\Workflow\DefinitionBuilder;
use Symfony\Component\Workflow\Transition;
use Symfony\Component\Workflow\Workflow;
use Symfony\Component\Workflow\MarkingStore\SingleStateMarkingStore;
use Symfony\Component\Workflow\Registry;
use Symfony\Component\Workflow\Dumper\GraphvizDumper;
$builder = new DefinitionBuilder();
$builder->addPlaces(['applied', 'in_process', 'approved', 'rejected']);
ここでは、 DefinitionBuilder を使用して新しい定義を作成し、 addPlaces メソッドを使用して場所を追加しました。
- ステップ4 *-ある場所から別の場所に移動するために必要なアクションを定義します。
$builder->addTransition(new Transition('to_process', 'applied', 'in_process'));
$builder->addTransition(new Transition('approve', 'in_process', 'approved'));
$builder->addTransition(new Transition('reject', 'in_process', 'rejected'));
ここには、 to_process、approve 、および reject の3つの遷移があります。 to_process遷移はleaveアプリケーションを受け入れ、場所をapplyからin_processに移動します。 移行の承認は、休暇申請を承認し、場所を承認済みに移動します。 同様に、拒否遷移は休暇申請を拒否し、場所を拒否に移動します。 addTransitionメソッドを使用してすべての遷移を作成しました。
- ステップ5 *-ビルドメソッドを使用して定義をビルドします。
$definition = $builder->build();
- ステップ6 *-オプションで、定義をgraphvizドット形式としてダンプできます。これは、参照目的で画像ファイルに変換できます。
$dumper = new GraphvizDumper();
echo $dumper->dump($definition);
- ステップ7 *-オブジェクトの現在の場所/ステータスを保存するために使用されるマーキングストアを作成します。
$marking = new SingleStateMarkingStore('status');
ここでは、 SingleStateMarkingStore クラスを使用してマークを作成し、現在のステータスをオブジェクトのstatusプロパティにマークしています。 この例では、オブジェクトはLeaveオブジェクトです。
- ステップ8 *-定義とマーキングを使用してワークフローを作成します。
$leaveWorkflow = new Workflow($definition, $marking);
ここでは、 Workflow クラスを使用してワークフローを作成しました。
ステップ9 *- *Registry クラスを使用して、ワークフローフレームワークのレジストリにワークフローを追加します。
$registry = new Registry();
$registry->add($leaveWorkflow, Leave::class);
ステップ10 *-最後に、ワークフローを使用して、 *can メソッドを使用して特定の遷移が適用されるかどうかを確認し、適用される場合は、applyメソッドを使用して遷移を*適用*します。 遷移が適用されると、オブジェクトのステータスはある場所から別の場所に移動します。
$workflow = $registry->get($leave);
echo "Can we approve the leave now? " . $workflow->can($leave, 'approve') . "\r\n";
echo "Can we approve the start process now? " . $workflow->can($leave, 'to_process') . "\r\n";
$workflow->apply($leave, 'to_process');
echo "Can we approve the leave now? " . $workflow->can($leave, 'approve') . "\r\n";
echo $leave->status . "\r\n";
$workflow->apply($leave, 'approve');
echo $leave->status . "\r\n";
完全なコーディングは次のとおりです-
<?php
require __DIR__ . '/vendor/autoload.php';
use Symfony\Component\Workflow\DefinitionBuilder;
use Symfony\Component\Workflow\Transition;
use Symfony\Component\Workflow\Workflow;
use Symfony\Component\Workflow\MarkingStore\SingleStateMarkingStore;
use Symfony\Component\Workflow\Registry;
use Symfony\Component\Workflow\Dumper\GraphvizDumper;
class Leave {
public $applied_by;
public $leave_on;
public $status;
}
$builder = new DefinitionBuilder();
$builder->addPlaces(['applied', 'in_process', 'approved', 'rejected']);
$builder->addTransition(new Transition('to_process', 'applied', 'in_process'));
$builder->addTransition(new Transition('approve', 'in_process', 'approved'));
$builder->addTransition(new Transition('reject', 'in_process', 'rejected'));
$definition = $builder->build();
//$dumper = new GraphvizDumper();
//echo $dumper->dump($definition);
$marking = new SingleStateMarkingStore('status');
$leaveWorkflow = new Workflow($definition, $marking);
$registry = new Registry();
$registry->add($leaveWorkflow, Leave::class);
$leave = new Leave();
$leave->applied_by = "Jon";
$leave->leave_on = "1998-12-12";
$leave->status = 'applied';
$workflow = $registry->get($leave);
echo "Can we approve the leave now? " . $workflow->can($leave, 'approve') . "\r\n";
echo "Can we approve the start process now? " . $workflow->can($leave, 'to_process') . "\r\n";
$workflow->apply($leave, 'to_process');
echo "Can we approve the leave now? " . $workflow->can($leave, 'approve') . "\r\n";
echo $leave->status . "\r\n";
$workflow->apply($leave, 'approve');
echo $leave->status . "\r\n";
?>
結果
Can we approve the leave now?
Can we approve the start process now? 1
Can we approve the leave now? 1
in_process
approved