Symfony-高度な概念

この章では、Symfonyフレームワークのいくつかの高度な概念について学習します。

HTTPキャッシュ

Webアプリケーションでキャッシュすると、パフォーマンスが向上します。たとえば、ショッピングカートのWebアプリケーション内の人気商品は、限られた時間だけキャッシュできるため、データベースにアクセスすることなく、迅速に顧客に提示できます。以下は、キャッシュのいくつかの基本的なコンポーネントです。

キャッシュアイテム

キャッシュアイテムは、キーと値のペアとして保存される単一の情報単位です。ザ・key 文字列である必要があります value任意のPHPオブジェクトにすることができます。PHPオブジェクトは、シリアル化によって文字列として保存され、アイテムの読み取り中にオブジェクトに変換されます。

キャッシュアダプタ

キャッシュアダプタは、アイテムをストアに格納するための実際のメカニズムです。ストアは、メモリ、ファイルシステム、データベース、redisなどです。キャッシュコンポーネントは、AdapterInterfaceアダプタがキャッシュアイテムをバックエンドストアに保存するために使用します。利用可能な組み込みのキャッシュアダプタがたくさんあります。それらのいくつかは次のとおりです-

  • 配列キャッシュアダプタ-キャッシュアイテムはPHP配列に保存されます。

  • ファイルシステムキャッシュアダプタ-キャッシュアイテムはファイルに保存されます。

  • PHPファイルキャッシュアダプタ-キャッシュアイテムはphpファイルとして保存されます。

  • APCuキャッシュアダプタ-キャッシュアイテムは、PHPAPCu拡張を使用して共有メモリに保存されます。

  • Redisキャッシュアダプター-キャッシュアイテムはRedisサーバーに保存されます。

  • PDOおよびDoctrineDBALキャッシュアダプタ-キャッシュアイテムはデータベースに保存されます。

  • チェーンキャッシュアダプタ-レプリケーションの目的で複数のキャッシュアダプタを組み合わせます。

  • プロキシキャッシュアダプタ-キャッシュアイテムは、CacheItemPoolInterfaceを実装するサードパーティのアダプタを使用して保存されます。

キャッシュプール

キャッシュプールは、キャッシュアイテムの論理リポジトリです。キャッシュプールは、キャッシュアダプタによって実装されます。

シンプルなアプリケーション

キャッシュの概念を理解するための簡単なアプリケーションを作成しましょう。

Step 1 −新しいアプリケーションを作成します。 cache-example

cd /path/to/app 
mkdir cache-example 
cd cache-example

Step 2 −キャッシュコンポーネントをインストールします。

composer require symfony/cache

Step 3 −ファイルシステムアダプタを作成します。

require __DIR__ . '/vendor/autoload.php';  
use Symfony\Component\Cache\Adapter\FilesystemAdapter;  
$cache = new FilesystemAdapter();

Step 4 −を使用してキャッシュアイテムを作成する getItem そして setアダプターの方法。getItemは、そのキーを使用してキャッシュアイテムをフェッチします。キーが存在しない場合は、新しいアイテムが作成されます。setメソッドは実際のデータを格納します。

$usercache = $cache->getitem('item.users'); 
$usercache->set(['jon', 'peter']); 
$cache->save($usercache);

Step 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); 
}

Step 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は、デバッグのプロセスを容易にするための別個のコンポーネントを提供します。を呼び出すだけでSymfonyデバッグツールを有効にできますenable Debugクラスのメソッド。

use Symfony\Component\Debug\Debug  
Debug::enable()

symfonyは2つのクラスを提供します、 ErrorHandler そして ExceptionHandlerデバッグ目的で。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アプリケーションでは、 debug environmentDebugBundleによって提供されます。AppKernelにバンドルを登録しますregisterBundles それを有効にする方法。

if (in_array($this->getEnvironment(), ['dev', 'test'], true)) { 
   $bundles[] = new Symfony\Bundle\DebugBundle\DebugBundle(); 
}

プロファイラー

アプリケーションの開発には、世界クラスのプロファイリングツールが必要です。プロファイリングツールは、実行時間、個々のモジュールの実行時間、データベースアクティビティにかかる時間、メモリ使用量など、アプリケーションに関するすべての実行時情報を収集します。Webアプリケーションには、要求時間などのより多くの情報が必要です。上記の指標に加えて、応答の作成にかかる時間など。

Symfonyは、デフォルトでWebアプリケーションでそのようなすべての情報を有効にします。Symfonyは、と呼ばれるWebプロファイリング用の個別のバンドルを提供しますWebProfilerBundle。Webプロファイラーバンドルは、AppKernelのregisterBundlesメソッドにバンドルを登録することにより、Webアプリケーションで有効にできます。

if (in_array($this->getEnvironment(), ['dev', 'test'], true)) { 
   $bundles[] = new Symfony\Bundle\WebProfilerBundle\WebProfilerBundle(); 
}

Webプロファイルコンポーネントは、以下で構成できます。 web_profile section アプリケーション構成ファイルの app/config/config.xml

web_profiler: 
   toolbar:      false 
   position:     bottom

symfonyアプリケーションは、ページの下部にプロファイルされたデータを別個のセクションとして表示します。

symfonyはまた、を使用してプロファイルデータにページに関するカスタム詳細を追加する簡単な方法を提供します DataCollectorInterface interfaceと小枝テンプレート。要するに、Symfonyは、優れたプロファイリングフレームワークを比較的簡単に提供することにより、Web開発者がワールドクラスのアプリケーションを作成できるようにします。

セキュリティ

前に説明したように、Symfonyはセキュリティコンポーネントを通じて堅牢なセキュリティフレームワークを提供します。セキュリティコンポーネントは、次のように4つのサブコンポーネントに分けられます。

  • symfony / security-core-コアセキュリティ機能。
  • symfony / security-http-HTTPプロトコルに統合されたセキュリティ機能。
  • symfony / security-csrf-Webアプリケーションでのクロスサイトリクエストフォージェリに対する保護。
  • symfony / security-acl-高度なアクセス制御リストベースのセキュリティフレームワーク。

簡単な認証と承認

簡単なデモアプリケーションを使用して、認証と承認の概念を学びましょう。

Step 1 −新しいWebアプリケーションを作成する securitydemo 次のコマンドを使用します。

symfony new securitydemo

Step 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(およびプロファイラーなどの開発ツール)が含まれます。

Step 3 −次のようにメインセクションにhttp_basicオプションを追加して、HTTPベースのセキュリティ認証システムを有効にします。

security: 
   # ...  
   firewalls: 
      # ...  
      main: 
         anonymous: ~ 
         http_basic: ~ 
         #form_login: ~

Step 4−メモリプロバイダーセクションにユーザーを追加します。また、ユーザーの役割を追加します。

security: 
   providers: 
      in_memory: 
         memory: 
            users: 
               myuser: 
                  password: user 
                  roles: 'ROLE_USER' 
                     myadmin: 
                        password: admin 
                        roles: 'ROLE_ADMIN'

ロールROLE_USERのユーザーとロールROLE_ADMINの管理者の2人のユーザーを追加しました。

Step 5−エンコーダーを追加して、現在ログインしているユーザーの完全な詳細を取得します。エンコーダーの目的は、Web要求から現在のユーザーオブジェクトの完全な詳細を取得することです。

security: 
   # ... 
   encoders: 
      Symfony\Component\Security\Core\User\User: bcrypt 
      # ...

symfonyはインターフェースを提供します UserInterface ユーザー名、役割、パスワードなどのユーザーの詳細を取得します。要件へのインターフェイスを実装し、エンコーダーセクションで構成する必要があります。

たとえば、ユーザーの詳細がデータベースにあるとしましょう。次に、新しいUserクラスを作成し、UserInterfaceメソッドを実装して、データベースからユーザーの詳細を取得する必要があります。データが利用可能になると、セキュリティシステムはそれを使用してユーザーを許可/拒否します。symfonyはメモリプロバイダーのデフォルトのユーザー実装を提供します。アルゴリズムは、ユーザーパスワードを復号化するために使用されます。

Step 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

Step 7 −コマンドを使用して、暗号化されたパスワードを生成し、構成ファイルで更新します。

# To get started with security, check out the documentation: 
# http://symfony.com/doc/current/security.html 
   security:  
      # http://symfony.com/doc/current/security.html#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/security.html#a-co
            nfiguring-howyour-users-will-authenticate 
            http_basic: ~  
            # http://symfony.com/doc/current/cookbook/security/
            form_login_setup.html 
            #form_login: ~

Step 8−次に、アプリケーションの一部のセクションにセキュリティを適用します。たとえば、adminセクションをロールROLE_ADMINのユーザーに制限します。

security: 
   # ... 
      firewalls: 
         # ... 
      default: 
         # ...  
      access_control: 
         # require ROLE_ADMIN for /admin* 
         - { path: ^/admin, roles: 'ROLE_ADMIN' }

Step 9 −次のようにDefaultControllerに管理ページを追加します。

/** 
   * @Route("/admin") 
*/ 
public function adminLandingAction() { 
   return new Response('<html><body>This is admin section.</body></html>'); 
}

Step 10−最後に、管理ページにアクセスして、ブラウザのセキュリティ構成を確認します。ブラウザはユーザー名とパスワードを要求し、設定されたユーザーのみを許可します。

結果

ワークフロー

ワークフローは、多くのエンタープライズアプリケーションで使用される高度な概念です。eコマースアプリケーションでは、製品の配送プロセスはワークフローです。製品は最初に請求され(注文の作成)、ストアから調達されてパッケージ化され(パッケージ化/発送準備完了)、ユーザーに発送されます。問題がある場合、製品はユーザーから返品され、注文は元に戻されます。アクションの流れの順序は非常に重要です。たとえば、請求なしで商品を配送することはできません。

symfonyコンポーネントは、ワークフローを定義および管理するためのオブジェクト指向の方法を提供します。プロセスの各ステップは呼び出されますplace ある場所から別の場所に移動するために必要なアクションは transition。ワークフローを作成するための場所と遷移のコレクションは、Workflow definition

休暇管理用の簡単なアプリケーションを作成して、ワークフローの概念を理解しましょう。

Step 1 −新しいアプリケーションを作成します。 workflow-example

cd /path/to/dev 
mkdir workflow-example 

cd workflow-example 
composer require symfony/workflow

Step 2 −新しいクラスを作成します。 Leave 持っている applied_by, leave_on そして status 属性。

class Leave { 
   public $applied_by; 
   public $leave_on;  
   public $status; 
}

ここで、applied_byは、休暇を希望する従業員を指します。Leave_onは、休暇の日付を示します。ステータスとは、休暇のステータスを指します。

Step 3 −休暇管理には、適用、処理中、承認/拒否の4つの場所があります。

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 方法。

Step 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'));

ここでは、3つの遷移があります。 to_process, approve そして reject。to_process遷移は、leaveアプリケーションを受け入れ、場所をappliedからin_processに移動します。移行の承認は、休暇申請を承認し、場所を承認済みに移動します。同様に、拒否遷移は、休暇申請を拒否し、場所を拒否に移動します。addTransitionメソッドを使用してすべてのトランジションを作成しました。

Step 5 −ビルドメソッドを使用して定義をビルドします。

$definition = $builder->build();

Step 6 −オプションで、定義をgraphvizドット形式としてダンプできます。これは、参照用に画像ファイルに変換できます。

$dumper = new GraphvizDumper(); 
echo $dumper->dump($definition);

Step 7 −オブジェクトの現在の場所/ステータスを保存するために使用されるマーキングストアを作成します。

$marking = new SingleStateMarkingStore('status');

ここでは、 SingleStateMarkingStoreマークを作成するクラス。現在のステータスをオブジェクトのstatusプロパティにマークします。この例では、オブジェクトはLeaveオブジェクトです。

Step 8 −定義とマーキングを使用してワークフローを作成します。

$leaveWorkflow =    new Workflow($definition, $marking);

ここでは、 Workflow ワークフローを作成するためのクラス。

Step 9 −を使用して、ワークフローをワークフローフレームワークのレジストリに追加します。 Registry クラス。

$registry = new Registry(); 
$registry->add($leaveWorkflow, Leave::class);

Step 10 −最後に、ワークフローを使用して、を使用して特定の遷移が適用されているかどうかを確認します can 方法ともしそうなら、 applyapplyメソッドを使用した遷移。遷移が適用されると、オブジェクトのステータスはある場所から別の場所に移動します。

$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