- モデルへのサービスの埋め込み
- 変更履歴を保存する
- SQLLoggerの無効化とキャッシュのクリーニング
- 環境の分離(dev-コンソール)
Symfony 2で作業した多くの人が、サービスコンテナをモデル(エンティティ)または他のコンポーネント(サービス)に導入する問題に遭遇したと思います。 これを行う方法を知る前に、それが必要かどうかを考えてください。 特定のサービス(ユーティリティ)を作成し、そこに必要なすべてを実行できます。 さて、あなたがそれを必要とすると決めたら、それから:
モデルでのBun No. 1サービスの実装:
それを実装するにはいくつかの方法があり、多くの場合、誰もが最も簡単な方法を選択します。
オプション番号1
グローバルスコープからカーネルを取得し、「愚かに」呼び出します
class MyEntity { // ... properties // ... methods public function someAction() { global $kernel; return $kernel->getContainer() ->..... } }
私に関しては、この方法は非常にシンプルですが、同じ変数の存在を検証することは不可能なので、非常に漏れやすいです...
オプション番号2
ここでは、100個の単純な関数に対して少し「汗をかく」必要がありますが、このソリューションは最初のものよりもはるかに優れており、完全なパフォーマンスを保証します。 モデルのロード/保存中に何でもできるようにするDoctrineイベントがここで使用されます 。
まず、Doctrineのイベントまたはサブスクライバーを作成する必要があります。これにより、モデルの読み込み中に必要なコンポーネントが実装されます( postLoad )。 そして、すべてのサービスを移転できるように、このビジネスをすべてサービスとして作成する必要があります。
Doctrineのサブスクライバーを作成します。
namespace Acme\DemoBundle\EventListener; use Doctrine\Common\EventSubscriber; use Doctrine\ORM\Event\LifecycleEventArgs; use Symfony\Component\DependencyInjection\ContainerInterface; use Acme\DemoBundle\Entity\MyEntity; class MyEntitySubscriber implements EventSubscriber { protected $container; public function __construct(ContainerInterface $container) { $this->container = $container; } public function postLoad(LifecycleEventArgs $event) { $entity = $event->getEntity(); // , , , // if ($entity instanceof MyEntity) { $entity-> setMyComponent($this->container->get('....')); } } /** * , * : - * , */ public function getSubscribedEvents() { return array( 'postLoad' ); } }
新しいモデルは次のようになります。
class MyEntity { // … properties protected $myComponent; // … methods public function setMyComponent($myComponent) { $this->myComponent = $myComponent; } public function someAction() { return $this->myComponent ->.... } }
サービスとして登録する
<service id="my_entity.doctrine.subscriber" class="Acme\DemoBundle\EventListener\MyEntitySubscriber"> <!-- , subscriber --> <tag name="doctrine.event_subscriber" /> <argument type="service" id="service_container" /> </service>
それですべてです。モデルを読み込むときに、システムはこのモデルが必要かどうかをチェックし、必要であれば、セッターを使用して必要なコンポーネントをmyComponent変数に「注入」します。
結論:モデルは読み取り専用/データベースへの書き込みであるため、このような場合は避けてください。
お団子No. 2歴史の保存:
場合によっては、たとえば、将来のロールバックのためにレコード変更の履歴など、モデルの変更の履歴全体を保存する必要があります。 この状況では、教義の出来事自体が大いに役立ちます。つまり、 onFlush
従う必要がある「ニュース」モデル、つまりタイトルフィールドがあるとします。
class News { protected $title; // ... properties // ... methods }
さて、追跡するには、変更を正確に制御する別のモデルを作成する必要があります。
class NewsHistory { protected $title; // ... properties // ... methods }
イベント自体では、このフィールドが変更されたかどうかを確認する必要があります。 これは、特定のマネージャーのすべてのモデルを注意深く監視するUnitOfWorkに役立ちます。
namespace Acme\DemoBundle\EventListener; use Doctrine\Common\EventSubscriber; use Doctrine\ORM\Event\OnFlushEventArgs; use Symfony\Component\DependencyInjection\ContainerInterface; use Acme\DemoBundle\Entity\News; use Acme\DemoBundle\Entity\NewsHistory; class NewsSubscriber implements EventSubscriber { public function onFlush(OnFlushEventArgs $event) { $em = $event->getEntityManager(); $uow = $em->getUnitOfWork(); // , foreach ($uow->getScheduledEntityUpdates() as $entity) { // if ($entity instanceof News) { // , $changeSet = $uow->getEntityChangeSet($entity); // title? if (isset($changeSet['title'])) { // list ($oldTitle, $newTitle) = $changeSet['title']; // entity $newsHistory = new NewsHistory; $newsHistory->setTitle($oldTitle); // $em->persist($newsHistory); // !!! // , // , , flush // , , // , . // UnitOfWork, , // // ClassMetadata // "" $classMetadata = $em->getClassMetadata(get_class($newsHistory)); // "" UnitOfWork, $uow->computeChangeSet($classMetadata, $newsHistory); } } } } public function getSubscribedEvents() { return array( 'onFlush' ); } }
さて、いつものように、あなたはサービスとして登録する必要があり、それが教義の加入者であることを示します:
<service id="news.doctrine.subscriber" class="Acme\DemoBundle\EventListener\NewsSubscriber"> <tag name="doctrine.event_subscriber" /> </service>
UnitOfWorkは、いわゆるApiであり、これを使用してモデルで不正行為を行うことができます。
同様に、新しいモデルの作成と古いモデルの削除を制御できます。
Bun#3 SQLロガーを無効にし、Doctrineのキャッシュをクリアします:
データベースに対して大量のクエリを実行するコマンドを(コンソールから)実行する必要がある場合があります。 良い例は、データベースに100,000を超えるレコードがある場合に、ある種のCMSまたはフレーマーからSymfony 2にサイトを転送することです。 コンソールからSymphonyでコマンドを実行すると、デフォルトでシステムはdevモードで起動し、デバッグが有効になります。このモードでは、Doctrineは後続のデバッグのすべてのリクエストを保存します。 その結果、スクリプトに割り当てられたメモリは絶えず増加し、その後速度に影響を及ぼし、重大なメモリ制限エラーをスローする可能性があります。 このような状況では、Doctrine(マネージャー)が使用するすべてのロガーを無効にするか、必要なものだけを制御するために完全に再定義できます。 ロガー自体は、ドクトリンの構成に依存しています。
完全なシャットダウンの例:
Php
$container->get('doctrine') ->getManager() ->getConnection() ->getConfiguration() ->setSQLLogger(null); //
構成
doctrine:
dbal:
connections:
default:
logging: false
また、 unsetが呼び出されるか、「静的」キャッシュがリセットされるまで、データベースからダウンロードされたすべてのモデルがマネージャーに保存されることを忘れないでください。 これは、同じモデルの選択を常に照会しないように設計されました。 その結果、このような大きなスクリプト(モデルで多くの操作を行う)では、キャッシュを定期的に消去する必要があります。
$container->get('doctrine')->getManager()->clear();
Bun No. 4コンソールの環境の分離:
Symphonyの新しいアセンブリを作成するとき、いくつかのフォルダー( Permission denied )の問題が常に発生します: app / cacheおよびapp / logs 。 この問題は、ブラウザからサイトを既に起動していて、コンソールで何かを実行しようとしているときに発生します。 問題は、Webサーバー自体が別のユーザーで実行されていることです。
サーバー(ルート)に完全にアクセスできる人は、これを行う必要はありません。見栄えが良い: http : //symfony.com/doc/current/book/installation.html#configuration-and-setup
ただし、システムへの完全なアクセス権(ホスティングなど)がなく、すでにこの問題にうんざりしている場合は、スタートアップシステムをdevとコンソールに分割できます。 これは次のように行われます。
- config_dev.yml configをインポートするファイルapp / config / config_console.ymlを作成します
- app / consoleファイルでは、デフォルトではコンソールではなくdevを設定します
- 追加のバンドルが接続されている場所でapp / AppKernel.phpファイルを修正し(環境を確認中)、別のコンソールを追加します
これで、アプリ/コンソールを起動すると、システムはまったく異なる環境で動作します。これは、devに干渉しません
注意 :これは、システムが開発モードの場合のみです!
PSコードは例として作成されたものであり、prodシステムでの作業用ではありません。 Symfony 2.2を使用しました。
PSSあまりキックしないでください...私の最初の投稿。 ご清聴ありがとうございました!