use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
class PostLoadTest extends KernelTestCase
{
/**
* @var Doctrine\ORM\EntityManager
*/
private $em;
protected function setUp()
{
self::bootKernel();
$this->em = static::$kernel->getContainer()
->get('doctrine')
->getManager();
}
public function testPostLoad()
{
$entity = new \Hyoujun\AppBundle\Entity\AnEntity();
//...
$this->em->persist($entity);
$this->em->flush();
self::bootKernel();//ここでプロセスをリフレッシュ。
$loaded = $this->em->getRepository('HyoujunAppBundle:AnEntity')
->find($entity->getId());
//...(postLoadが呼ばれたかを検証)
}
protected function tearDown()
{
parent::tearDown();
$this->em->close();
$this->em = null;
}
}
Symfony\Bundle\FrameworkBundle\Test\KernelTestCase::bootKernel()で、プロセスをリフレッシュすれば、postLoad()が呼ばれる。
21世紀のライフスタイルに合った新しい装束 ―
日本標準機構では、日本の装束をカジュアルにアレンジして販売しています。
狩衣(かりぎぬ)、直衣(のうし)、直垂(ひたたれ)などを現代のライフスタイルに合わせてより着やすく、よりカジュアルに。
カジュアル装束の販売は
日本標準機構
2017年9月23日土曜日
テストではbootKernel()でリフレッシュしないとpostLoad()が呼ばれない場合がある
イベントリスナーのpostLoadはEntityを取得した後で実行される。しかしユニットテストなどで、あるEntityをEntityManagerによって登録したあと、そのEntityManagerから再び同じEntityを取得すると、イベントが発生しない。その場合は、取得前に一旦、プロセスをリフレッシュすればイベントが発生するようになる。
2017年9月19日火曜日
postPersist内でpersist()とflush()を呼びたい時の無限再帰を止める方法
イベントリスナーのpostPersist内でEntityManagerがpersist()とflush()を呼ぶと、そのためにイベントリスナーのpostPersistが呼ばるため、無限の再帰となりOutOfMemoryException等が発生する。もし、イベントリスナー内で登録したいEntityクラスがあらゆる場所でそのイベントリスナーを呼ぶ必要がない場合には、無限の再帰を止める方法がある。
use Doctrine\ORM\Event\LifecycleEventArgs;
class EventListener
{
public function postPersist(LifecycleEventArgs $args)
{
$entity = $args->getEntity();
if($entity instanceof Only\In\Listener\Entity) return;
$entityManager = $args->getEntityManager();
$entity = new Only\In\Listener\Entity();
//...
$entityManager->persist($entity);
$entityManager->flush();
}
}
イベントリスナー内で登録されるEntityクラスの登録がイベントの発生源となった場合に、instanceofで判定し、returnすれば良い。
2017年9月9日土曜日
FOSRestBundleの後、JMSSerializerBundleをセットアップしようとした時のエラー解決
Step 1: Setting up the bundleの通りFOSRestBundleをセットアップし、
次に、JMSSerializerBundleをインストールしようとした時に、エラー:
[InvalidArgumentException]
Neither a service called "jms_serializer.serializer" nor "serializer" is av
ailable and no serializer is explicitly configured. You must either enable
the JMSSerializerBundle, enable the FrameworkBundle serializer or configure
a custom serializer.
とりあえず、app/config/config.ymlの
#serializer: { enable_annotations: true }
のコメントアウトを外すとインストールできるようになる。
次に、JMSSerializerBundleをインストールしようとした時に、エラー:
[InvalidArgumentException]
Neither a service called "jms_serializer.serializer" nor "serializer" is av
ailable and no serializer is explicitly configured. You must either enable
the JMSSerializerBundle, enable the FrameworkBundle serializer or configure
a custom serializer.
とりあえず、app/config/config.ymlの
#serializer: { enable_annotations: true }
のコメントアウトを外すとインストールできるようになる。
webディレクトリを任意の位置に動かした場合の設定
symfonyでwebディレクトリの名前を変え、かつ階層を下げた場合(web/をfoo/bar/へ)の変更点は以下の通り:
1. composer.jsonの最下方、symfony-web-dir:
1. composer.jsonの最下方、symfony-web-dir:
"extra": {
"symfony-app-dir": "app",
"symfony-bin-dir": "bin",
"symfony-var-dir": "var",
"symfony-web-dir": "foo/bar",
"symfony-tests-dir": "tests",
"symfony-assets-install": "relative",
"incenteev-parameters": {
"file": "app/config/parameters.yml"
},
"branch-alias": null
}
2. web/app.php(foo/bar/app.php)の5〜7行目付近でautoload.phpとbootstrap.php.cacheへのパスに「../../」追加:use Symfony\Component\HttpFoundation\Request;
require __DIR__.'/../../vendor/autoload.php';
if (PHP_VERSION_ID < 70000) {
include_once __DIR__.'/../../var/bootstrap.php.cache';
}
$kernel = new AppKernel('prod', false);
//...
3. web/app_dev.php(foo/bar/app_dev.php)の21行目付近でautoload.phpへのパスに「../../」追加:use Symfony\Component\Debug\Debug;
use Symfony\Component\HttpFoundation\Request;
//...
require __DIR__.'/../../vendor/autoload.php';
Debug::enable();
$kernel = new AppKernel('dev', true);
if (PHP_VERSION_ID < 70000) {
$kernel->loadClassCache();
}
//...
varフォルダのパーミッションを設定する
symfonyは下記リンクの指示通りコマンドを実行しないと、動かない。
3. Using ACL on a System that Supports setfacl (Linux/BSD)
要は、環境変数HTTPDUSERにサーバーのユーザ名リストを代入し(1行目)
varフォルダに対して、そのリストのユーザと自分(whoami)の権限を777に設定している(3,4行目)、
ということのようだ。
うまく行かない場合のnオプションをつけると、
3. Using ACL on a System that Supports setfacl (Linux/BSD)
要は、環境変数HTTPDUSERにサーバーのユーザ名リストを代入し(1行目)
varフォルダに対して、そのリストのユーザと自分(whoami)の権限を777に設定している(3,4行目)、
ということのようだ。
うまく行かない場合のnオプションをつけると、
$ HTTPDUSER=$(ps axo user,comm | grep -E '[a]pache|[h]ttpd|[_]www|[w]ww-data|[n]ginx' | grep -v root | head -1 | cut -d\ -f1) $ sudo setfacl -ndR -m u:"$HTTPDUSER":rwX -m u:$(whoami):rwX var $ sudo setfacl -nR -m u:"$HTTPDUSER":rwX -m u:$(whoami):rwX varとなるようだ。
$ sudo chmod -R 777 varでもいいかと思いきや、キャッシュを削除するたびにこのコマンドを打たなかればならなかったような記憶がある。
symfonyが動かない時はとりあえずキャッシュクリア
理由もなくコード更新後にsymfonyが動かない場合、キャッシュをクリアすれば大概動く。
ただし、各環境ごとにクリアする必要があるかも知れない。
開発環境:
ただし、各環境ごとにクリアする必要があるかも知れない。
開発環境:
$ php app/console cache:clear製品環境:
$ php app/console cache:clear --env=prod
Bundle新規作成後のClassNotFoundExceptionに対してはcomposerを設定
Bundle新規作成後はcomposer.jsonのautoloadの設定を変更し、以下のコマンドを実行:
新しいBundle「Hyoujun\AppBundle」を作るとする:
その場合、composer.jsonの下記3行目を変更:
$ composer dumpautoloadさもなくばClassNotFoundExceptionが出る。
新しいBundle「Hyoujun\AppBundle」を作るとする:
$ php app/console generate:bundle Are you planning on sharing this bundle across multiple applications? [no]: yes Bundle namespace: Hyoujun\AppBundle Bundle name [HyoujunAppBundle]: Target Directory [src/]: Configuration format (annotation, yml, xml, php) [xml]: annotation
その場合、composer.jsonの下記3行目を変更:
"autoload": {
"psr-4": {
"Hyoujun\\": "src/Hyoujun"
},
"classmap": [
"app/AppKernel.php",
"app/AppCache.php"
]
},
修正を反映させるため以下のコマンドを実行:$ composer dumpautoloadこれでClassNotFoundExceptionは出なくなる。
docker経由のsymfonyが自動生成したファイルの所有者に注意
docker上でsymfonyを動かしている場合で、ボリュームをローカルに指定している時、docker経由でapp/consoleコマンドを実行すると、ローカル上に生成されたファイルがrootの所有になる場合がある。
で戻す。
$ sudo chown -R user:user
で戻す。
localhostでもポートが違ったら、ガードをコメントアウト
dockerでsymfonyを動かしており、localhostであってもポートが80でない場合app_dev.phpとconfig.phpにアクセスできない。
その場合、 両ファイルの一部をコメントアウトすることでアクセスできる。
以下は10〜18行目をコメントアウトしている:
以下は16〜22行目をコメントアウトしている。
その場合、 両ファイルの一部をコメントアウトすることでアクセスできる。
以下は10〜18行目をコメントアウトしている:
// web/app_dev.php
use Symfony\Component\Debug\Debug;
use Symfony\Component\HttpFoundation\Request;
// If you don't want to setup permissions the proper way, just uncomment the following PHP line
// read https://symfony.com/doc/current/setup.html#checking-symfony-application-configuration-and-setup
// for more information
//umask(0000);
// This check prevents access to debug front controllers that are deployed by accident to production servers.
// Feel free to remove this, extend it, or make something more sophisticated.
//if (isset($_SERVER['HTTP_CLIENT_IP'])
// || isset($_SERVER['HTTP_X_FORWARDED_FOR'])
// || !(in_array(@$_SERVER['REMOTE_ADDR'], ['127.0.0.1', '::1'], true) || PHP_SAPI === 'cli-server')
//) {
// header('HTTP/1.0 403 Forbidden');
// exit('You are not allowed to access this file. Check '.basename(__FILE__).' for more information.');
//}
require __DIR__.'/../vendor/autoload.php';
Debug::enable();
$kernel = new AppKernel('dev', true);
if (PHP_VERSION_ID < 70000) {
$kernel->loadClassCache();
}
$request = Request::createFromGlobals();
$response = $kernel->handle($request);
$response->send();
$kernel->terminate($request, $response);
以下は16〜22行目をコメントアウトしている。
// web/config.php
/*
* ************** CAUTION **************
*
* DO NOT EDIT THIS FILE as it will be overridden by Composer as part of
* the installation/update process. The original file resides in the
* SensioDistributionBundle.
*
* ************** CAUTION **************
*/
if (!isset($_SERVER['HTTP_HOST'])) {
exit("This script cannot be run from the CLI. Run it from a browser.\n");
}
//if (!in_array(@$_SERVER['REMOTE_ADDR'], array(
// '127.0.0.1',
// '::1',
//))) {
// header('HTTP/1.0 403 Forbidden');
// exit('This script is only accessible from localhost.');
//}
require_once dirname(__FILE__).'/../var/SymfonyRequirements.php';
登録:
コメント (Atom)