Symfony
================================
## フレームワークとは
* [フレームワーク特集](https://hackmd.io/GZiheT72SeeClEnJFguvnw)からコピー!
## Symfony はどんなフレームワーク?(森下)
* [フレームワーク特集](https://hackmd.io/GZiheT72SeeClEnJFguvnw)
- Symfonyの定義とPHP開発における役割
Symfonyとは
> What could be more useful than an application developed by users for their own needs
> https://symfony.com/at-a-glance#a-philosophy
ユーザーが自分たちのニーズに合わせて開発したアプリケーションほど便利なものはない
作成されたコンポーネントを組み合わせて、フルスタックフレームワークを作成することもマイクロサービスを作成することも可能。
開発者の目的に応じて規模を変えることができることが特徴。
コンポーネントが標準化されており、アプリケーションが成熟しても使用したいコンポーネントを自由に導入することができる。
Java の [Spring Framework](https://spring.io/) や Ruby の [Ruby on Rails](https://rubyonrails.org/) の影響を受けていることにより、「バンドル」という概念が用意されています。
Symfonyは、最初スポンサーである Sensio Labs の名前から "Sensio Framework" と呼ばれていた。クラス名には接頭辞として"sf"が付けられていた。OSSにするにあたって、"sf" がそのまま使える "Symfony" になった。(そのため"Sym**pho**ny"ではないので注意。)
- コミュニティとサポートの重要性
- [日本Symfonyユーザー会](https://symfony-japan.github.io/)
- [symfony コミュニティ](https://symfony.com/legacy/doc/more-with-symfony/1_4/ja/15-working-with-the-symfony-community)
主な特徴
- モダンなアーキテクチャと設計原則 (MVC, モジュール性など)
- 拡張性とカスタマイズ性
- コマンドラインツールの強力なサポート
- ドキュメンテーションと学習リソースの充実
## [Symfony Official Book](https://symfony.com/book)(加納)
日本語にも翻訳されている入門用ドキュメント。
[日本語の翻訳者](https://speakerdeck.com/ippey/symfonygong-shi-false-ri-ben-yu-ru-men-shu-gadekitayotutehua?slide=14)は以下の通り
* Ippei Sumida
* Nana YAMANE
* Shin Ohno
* Taku Shinohara
* Hiromi Hishida
入門用とされているが、以下について記載されており非常に重厚。
* 環境構築
* Docker
* Git
* MVC
* DB
* メール
* イベント
* 非同期処理
* セキュリティ
* スパム対策
* デプロイ
* 管理画面
* 認証
* ワークフロー
* キャッシュ
* テスト
* Webpack
* cron
* Notification
* API
* SPA
* 国際化
## 開発環境
PhpStormであればプラグインあり
https://plugins.jetbrains.com/plugin/7219-symfony-support
## コンポーネントについて(加納)(沼本)
- Laravelでも使われているなど
↓ひとまずざっくり概要を調べました。深く掘り下げて調査する箇所などあればご連絡ください。(沼本)👍
### Symfonyコンポーネントとは
Symfonyの構成要素であり、再利用可能なコンポーネント。
Symfonyはコンポーネントベースで構築されており、それぞれのコンポーネントは独立して使用できる。
■Symfonyコンポーネント公式
https://symfony.com/components
### 代表的なコンポーネント
* [HTTP Foundation Component](https://symfony.com/components/HttpFoundation): HTTPリクエストとレスポンスを扱うためのコンポーネント。
* [Routing Component](https://symfony.com/components/Routing): URLとコントローラのマッピングを管理するためのコンポーネント。
* [Form Component](https://symfony.com/components/Form): フォームの作成、バリデーション、データの処理を行うためのコンポーネント。
* [Validator Component](https://symfony.com/components/Validator): データのバリデーションを行うためのコンポーネントです。
* [Security Component](https://symfony.com/components/Security%20Bundle): 認証や認可、アクセス制御を担当するコンポーネントです。
* [Cache Component](https://symfony.com/components/Cache): キャッシュ機能を提供するコンポーネント。
* [Console Component](https://symfony.com/components/Console): コンソールコマンドを作成、実行するためのツールセットを提供するコンポーネント。
### Laravelで使用されているSymfonyコンポーネント
SymfonyコンポーネントはLaravelでも使用されている。
https://symfony.com/projects/laravel
* 認証、ルーティング、セッション、キャッシュなど多くの部分でSymfonyコンポーネントに依存している。
* LaravelがSymfonyに依存していることにより、SymfonyのリリースがLaravelのリリースに影響を及ぼすこともあった。
## Symfony の機能紹介(久山)(神山)
* [公式ドキュメント](https://symfony.com/doc/current/index.html)
* かなり内容が充実しているため、本番までにここを集中的に見えていきたい
### インストールと設定(久山)
インストール方法は以下2種類
* Symfony CLI
* Composer
#### [Symfony CLI のインストール](https://symfony.com/download)
- 環境によって手順が異なる
- 以下は Ubuntu のインストール方法
```bash=
curl -1sLf 'https://dl.cloudsmith.io/public/symfony/stable/setup.deb.sh' | sudo -E bash
sudo apt install symfony-cli
```
#### 環境のチェック
```bash=
symfony check:requirements
```
以下が出力されればOK
```
[OK]
Your system is ready to run Symfony projects
```
#### Symfony アプリケーションの作成
* Symfony CLI 経由でインストールする場合
```bash=
# Webアプリ作成に必要なコンポーネントが同梱されたアプリ作成手順
symfony new [任意のプロジェクト名] --version="6.3.*" --webapp
# API作成手順
symfony new [任意のプロジェクト名] --version="6.3.*"
```
* composer 経由でアプリケーション作成する場合
```bash=
# Webアプリ作成手順
composer create-project symfony/skeleton:"6.3.*" [任意のプロジェクト名]
cd [任意のプロジェクト名]
composer require webapp
# API作成手順
composer create-project symfony/skeleton:"6.3.*" [任意のプロジェクト名]
```
#### アプリケーションの起動
```bash=
cd [任意のプロジェクト名]/
symfony server:start
```
```bash=
masaku@DESKTOP-IU10L8A:~/study/my_project_directory$ symfony server:start
[WARNING] run "symfony server:ca:install" first if you want to run the web server with TLS support, or use "--p12" or
"--no-tls" to avoid this warning
Following Web Server log file (/home/masaku/.symfony5/log/32b830512543ff353a0a7b4c87e29ce092a0601e.log)
Following PHP log file (/home/masaku/.symfony5/log/32b830512543ff353a0a7b4c87e29ce092a0601e/7daf403c7589f4927632ed3b6af762a992f09b78.log)
[WARNING] The local web server is optimized for local development and MUST never be used in a production setup.
[OK] Web server listening
The Web server is using PHP CLI 8.2.5
http://127.0.0.1:8000
[Web Server ] Jun 19 14:01:31 |DEBUG | PHP Reloading PHP versions
[Web Server ] Jun 19 14:01:34 |DEBUG | PHP Using PHP version 8.2.5 (from default version in $PATH)
[Application] Jun 19 04:53:39 |INFO | DEPREC User Deprecated: The "Monolog\Logger" class is considered final. It may change without further notice as of its next major version. You should not extend it from "Symfony\Bridge\Monolog\Logger".
[Web Server ] Jun 19 14:01:34 |INFO | PHP listening path="/usr/bin/php8.2" php="8.2.5" port=45015
[PHP ] [Mon Jun 19 14:01:34 2023] PHP 8.2.5 Development Server (http://127.0.0.1:45015) started
```

### ルーティング(久山)
#### routes.yaml に記載するパターン
`routes.yaml` を以下の通り編集する
```yaml=
app_lucky_number:
path: /lucky/number
controller: App\Controller\LuckyController::number
```
`/lucky/number` にアクセスすることで `LuckyController` の `number` メソッドにルーティングされる
#### アノテーションまたはアトリビュートを利用するパターン(こっちが推奨)
コントローラを以下の通り変更
```php=
<?php
// src/Controller/LuckyController.php
namespace App\Controller;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
class LuckyController
{
#[Route('/lucky/number')]
public function number(): Response
{
$number = random_int(0, 100);
return new Response(
'<html><body>Lucky number: '.$number.'</body></html>'
);
}
}
```
上記の通り記述することで `routes.yaml` を作成しなくともルーティングされる
以下にブラウザ経由でアクセスするとルーティングされてページが表示される。
```
http://127.0.0.1:45015/lucky/number
```

#### ルーティング設定の確認
ルーティングが正しく設定されているかを確認するための方法。
Symfony には `bin/console` というデバッガーが標準搭載されている。
以下のコマンドで正しく設定されているかどうかをチェックできる。
```bash=
php bin/console debug:router
```
```bash=
masaku@DESKTOP-IU10L8A:~/study/my_project_directory$ php bin/console debug:router
-------------------------- -------- -------- ------ -----------------------------------
Name Method Scheme Host Path
-------------------------- -------- -------- ------ -----------------------------------
_preview_error ANY ANY ANY /_error/{code}.{_format}
_wdt ANY ANY ANY /_wdt/{token}
_profiler_home ANY ANY ANY /_profiler/
_profiler_search ANY ANY ANY /_profiler/search
_profiler_search_bar ANY ANY ANY /_profiler/search_bar
_profiler_phpinfo ANY ANY ANY /_profiler/phpinfo
_profiler_xdebug ANY ANY ANY /_profiler/xdebug
_profiler_search_results ANY ANY ANY /_profiler/{token}/search/results
_profiler_open_file ANY ANY ANY /_profiler/open
_profiler ANY ANY ANY /_profiler/{token}
_profiler_router ANY ANY ANY /_profiler/{token}/router
_profiler_exception ANY ANY ANY /_profiler/{token}/exception
_profiler_exception_css ANY ANY ANY /_profiler/{token}/exception.css
app_lucky_number ANY ANY ANY /lucky/number
-------------------------- -------- -------- ------ -----------------------------------
```
### セッション管理(久山)
HttpFoundation コンポーネントを利用する。
```bash=
composer require symfony/http-foundation
```
フレームワーク上で利用する方法とスタンドアロンで利用する方法の二通りがある。
#### フレームワークで利用する場合
RequestStack で引数をタイプヒントすると、サービスとコントローラーにセッションを管理するサービスを挿入される。
```php=
use Symfony\Component\HttpFoundation\RequestStack;
class SomeService
{
public function __construct(
private RequestStack $requestStack,
) {
// Accessing the session in the constructor is *NOT* recommended, since
// it might not be accessible yet or lead to unwanted side-effects
// $this->session = $requestStack->getSession();
}
public function someMethod()
{
$session = $this->requestStack->getSession();
// ...
}
}
```
公式にはサービスのコンストラクタ内でセッションにアクセスすることは非推奨とされている。
セッションにアクセスする場合は、各メソッド内で実行することを推奨して入りう。
コントローラーには `Request` パラメータからセッション情報を引き継ぐことができる。
```php=
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
public function index(Request $request): Response
{
$session = $request->getSession();
// ...
}
```
#### スタンドアロンでの利用方法
```php=
use Symfony\Component\HttpFoundation\Session\Session;
$session = new Session();
$session->start();
```
### リクエスト管理(久山)
#### コントローラー基礎
https://symfony.com/doc/current/controller.html
#### コントローラーでリクエストを処理する
[コントローラでリクエストをパラメータを受け取る](https://symfony.com/doc/current/controller.html#the-request-and-response-object)
```php=
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
public function index(Request $request): Response
{
$request->isXmlHttpRequest(); // is it an Ajax request?
$request->getPreferredLanguage(['en', 'fr']);
// retrieves GET and POST variables respectively
$request->query->get('page');
$request->request->get('page');
// retrieves SERVER variables
$request->server->get('HTTP_HOST');
// retrieves an instance of UploadedFile identified by foo
$request->files->get('foo');
// retrieves a COOKIE value
$request->cookies->get('PHPSESSID');
// retrieves an HTTP request header, with normalized, lowercase keys
$request->headers->get('host');
$request->headers->get('content-type');
}
```
#### リクエスト処理のアーキテクチャ
https://symfony.com/doc/current/components/http_kernel.html
#### 神山担当分
[過去資料](https://hackmd.io/zZgyeMjQTKusRpX2HFFYjw)と[最新のSymphony](https://symfony.com/doc/current/index.html)で差分を調査。
#### エラーハンドリング(神山)
Symfony アプリケーションでは、エラーが 404 Not Found エラーであろうと、コードで何らかの例外をスローすることによってトリガーされた致命的なエラーであろうと、すべてのエラーは例外として扱われます。
組み込みの Twig エラーレンダラーを使用して、デフォルトのエラーテンプレートをオーバーライドできます。
```bash
composer require symfony/twig-pack
```
これらのテンプレートをオーバーライドするには、標準の Symfony メソッドを使用し て、バンドル内にあるテンプレートをオーバーライドし、それらをtemplates/bundles/TwigBundle/Exception/ディレクトリに配置します。
HTML ページを返す典型的なプロジェクトは次のようになります。
```
Copy
templates/
└─ bundles/
└─ TwigBundle/
└─ Exception/
├─ error404.html.twig
├─ error403.html.twig
└─ error.html.twig # All other HTML errors (including 500)
```
HTML ページの 404 エラー テンプレートをオーバーライドするには、`templates/bundles/TwigBundle/Exception/`に新しいテンプレート(error404.html.twig)を作成します。
```htmlembedded
{# templates/bundles/TwigBundle/Exception/error404.html.twig #}
{% extends 'base.html.twig' %}
{% block body %}
<h1>Page not found</h1>
<p>
The requested page couldn't be located. Checkout for any URL
misspelling or <a href="{{ path('homepage') }}">return to the homepage</a>.
</p>
{% endblock %}
```
[error_controller](https://github.com/symfony/symfony/blob/6.1/src/Symfony/Component/HttpKernel/Controller/ErrorController.php)
[参考](https://symfony.com/doc/current/controller/error_pages.html)
Symfony はアプリケーションの実行中に、多くのイベント通知がトリガーされます。アプリケーションはこれらの通知をリッスンし、任意のコードを実行して応答できます。
- EventListenerクラスを作成する
```php=
// src/EventListener/ExceptionListener.php
namespace App\EventListener;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
class ExceptionListener
{
public function __invoke(ExceptionEvent $event): void
{
// You get the exception object from the received event
$exception = $event->getThrowable();
$message = sprintf(
'My Error says: %s with code: %s',
$exception->getMessage(),
$exception->getCode()
);
// Customize your response object to display the exception details
$response = new Response();
$response->setContent($message);
// HttpExceptionInterface is a special type of exception that
// holds status code and header details
if ($exception instanceof HttpExceptionInterface) {
$response->setStatusCode($exception->getStatusCode());
$response->headers->replace($exception->getHeaders());
} else {
$response->setStatusCode(Response::HTTP_INTERNAL_SERVER_ERROR);
}
// sends the modified response object to the event
$event->setResponse($response);
}
}
```
- タグを登録する
Yaml
```yaml=
# config/services.yaml
services:
App\EventListener\ExceptionListener:
tags: [kernel.event_listener]
```
XML
```xml=
<!-- config/services.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services
https://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<service id="App\EventListener\ExceptionListener">
<tag name="kernel.event_listener"/>
</service>
</services>
</container>
```
PHP
```php=
// config/services.php
namespace Symfony\Component\DependencyInjection\Loader\Configurator;
use App\EventListener\ExceptionListener;
return function(ContainerConfigurator $container): void {
$services = $container->services();
$services->set(ExceptionListener::class)
->tag('kernel.event_listener')
;
};
```
[イベントリスナを使ったエラーハンドリング](https://symfony.com/doc/current/event_dispatcher.html)
#### DBサポート(神山)
* コネクション
Doctrine(ORM)を使用
```
composer require symfony/orm-pack
composer require --dev symfony/maker-bundle
```
インストールが完了すると .env ファイルにデータベースへの接続設定に関する項目が書き足されます。
DATABASE_URL の箇所を接続するデータベースに合わせて書き換えて下さい。
```:.env
DATABASE_URL=mysql://db_user:db_password@127.0.0.1:3306/db_name
```
```
php bin/console doctrine:database:create
```
エンティティクラスを作成する
```
php bin/console make:entity
```
https://symfony.com/doc/current/doctrine.html
#### バリデーション(神山)
https://symfony.com/doc/current/doctrine.html#validating-objects
導入
```
composer require symfony/validator
```
config/validator/ ディレクトリ内の .yaml または .xml ファイルとして定義する。
(例)$nameプロパティが空
```php=
Attributes
// src/Entity/Author.php
namespace App\Entity;
// ...
use Symfony\Component\Validator\Constraints as Assert;
class Author
{
#[Assert\NotBlank]
private $name;
}
```
YAML
```yaml
# config/validator/validation.yaml
App\Entity\Author:
properties:
name:
- NotBlank: ~
```
XML
```xml=
<!-- config/validator/validation.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<constraint-mapping xmlns="http://symfony.com/schema/dic/constraint-mapping"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/constraint-mapping
https://symfony.com/schema/dic/constraint-mapping/constraint-mapping-1.0.xsd">
<class name="App\Entity\Author">
<property name="name">
<constraint name="NotBlank"/>
</property>
</class>
</constraint-mapping>
```
PHP
```php=
// src/Entity/Author.php
namespace App\Entity;
// ...
use Symfony\Component\Validator\Constraints\NotBlank;
use Symfony\Component\Validator\Mapping\ClassMetadata;
class Author
{
private $name;
public static function loadValidatorMetadata(ClassMetadata $metadata)
{
$metadata->addPropertyConstraint('name', new NotBlank());
}
}
```
※値が空白にならないという保証はまだない
バリデーターサービスを作成
```php=
// ...
use App\Entity\Author;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Validator\Validator\ValidatorInterface;
// ...
public function author(ValidatorInterface $validator): Response
{
$author = new Author();
// ... do something to the $author object
$errors = $validator->validate($author);
if (count($errors) > 0) {
/*
* Uses a __toString method on the $errors variable which is a
* ConstraintViolationList object. This gives us a nice string
* for debugging.
*/
$errorsString = (string) $errors;
return new Response($errorsString);
}
return new Response('The author is valid! Yes!');
}
```
`$name`が空のとき、次のエラーメッセージが表示されます。
```php=
Object(App\Entity\Author).name:
This value should not be blank.
```
#### マイグレーション(神山)
Doctrine Migrationsを使用。
```
symfony console make:migration
```
生成されたファイル名が出力されます(migrations/Version20220718170654.php のような名前のファイル):
```php=
final class Version20220718170654 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE SEQUENCE vinyl_mix_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
$this->addSql('CREATE TABLE vinyl_mix (id INT NOT NULL, title VARCHAR(255) NOT NULL, description TEXT DEFAULT NULL, track_count INT NOT NULL, genre VARCHAR(255) NOT NULL, created_at TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, PRIMARY KEY(id))');
$this->addSql('COMMENT ON COLUMN vinyl_mix.created_at IS \'(DC2Type:datetime_immutable)\'');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE SCHEMA public');
$this->addSql('DROP SEQUENCE vinyl_mix_id_seq CASCADE');
$this->addSql('DROP TABLE vinyl_mix');
}
}
```
マイグレーションを実行
```
symfony console doctrine:migrations:migrate
```
レコード取得
```
symfony console doctrine:query:sql 'SELECT * FROM vinyl_mix'
```
https://symfonycasts.com/screencast/symfony-doctrine/migrations
---------------------------
【タイトル】Symfony: PHPの優れたフレームワーク
【イントロダクション】
- PHPのフレームワークとは何か
- Symfonyの概要とその特徴
- Symfonyの人気と広まりについて
【セクション1: Symfonyの概要】
1.1 Symfonyとは?
- Symfonyの定義とPHP開発における役割
- コミュニティとサポートの重要性
1.2 主な特徴
- モダンなアーキテクチャと設計原則 (MVC, モジュール性など)
- 拡張性とカスタマイズ性
- コマンドラインツールの強力なサポート
- ドキュメンテーションと学習リソースの充実
【セクション2: Symfonyの利点】
2.1 性能と効率性
- キャッシュ機構と最適化
- バンドルの再利用性による効率的な開発
2.2 テストとデバッグのサポート
- ユニットテストや機能テストの容易な実装
- デバッグツールとエラーハンドリングの強力な機能
2.3 セキュリティと保守性
- セキュリティベストプラクティスの組み込み
- 長期サポートとアップデートの継続的な提供
【セクション3: Symfonyのエコシステム】
3.1 パッケージとバンドル
- コミュニティによる豊富なパッケージの提供
- オープンソースプロジェクトや共有リソース
3.2 Symfony Flex
- バンドルの管理とインストールの簡素化
- バンドルの設定と自動化
【結論】
- SymfonyはPHP開発において強力なフレームワークであり、多くの利点があります。
- 性能と効率性、テストとデバッグのサポート、セキュリティと保守性など、開発プロセスを向上させる機能が豊富に備わっています。
- Symfonyのエコシステムは豊かで、共有リソースやパッケージの提供があります。
- 多くの有名プロジェクトや企業で採用されており、ビジネス上のメリットもあります。
- 学習リソースやコミュニティのサポートも充実しており、初心者でも学びやすい環境です。
【参考資料】
- Symfony公式ウェブサイト: https://symfony.com/
- Symfonyドキュメンテーション: https://symfony.com/doc/current/index.html
- SymfonyのGitHubリポジトリ: https://github.com/symfony/symfony
以上がSymfonyについてのプレゼン資料の一部です。SymfonyはPHP開発において信頼性と効率性を高めるための強力なツールです。これを活用することで、より効果的なウェブアプリケーションの開発が可能となります。
==========
【タイトル】Symfony: PHP開発をサポートするフレームワーク
【イントロダクション】
- フレームワークとは何か?
- Symfonyの概要と簡単な説明
- Symfonyの人気と広まりについて
【セクション1: Symfonyの概要】
1.1 Symfonyとは?
- Symfonyは、PHP開発を助ける道具のようなものです。
- ウェブアプリケーションの作成や管理を簡単にします。
- 多くの人々がSymfonyを使って素晴らしいウェブサイトやアプリを作っています。
1.2 Symfonyの特徴
- Symfonyは、開発者がコードを効率的に書けるようにサポートします。
- ウェブアプリケーションの作成や保守が簡単になります。
- エラーを見つけて修正するのも簡単です。
【セクション2: Symfonyの利点】
2.1 簡単な開発
- Symfonyは、コードの書き方を教えてくれるツールです。
- 使いやすいテンプレートや機能がたくさんあります。
2.2 早くて安全なウェブアプリケーション
- Symfonyは速くて安全なコードを生成します。
- セキュリティに問題があると警告してくれるので、安心して使えます。
2.3 コミュニティとサポート
- Symfonyは多くの人々に使われているので、助けを求めることができます。
- フォーラムやチャットルームで質問や意見を交換できます。
【セクション3: Symfonyの使い方】
3.1 インストールと設定
- Symfonyを使うためには、まずコンピュータにインストールする必要があります。
- インストール手順や設定の方法を説明します。
3.2 ウェブアプリケーションの作成
- Symfonyを使って簡単なウェブアプリケーションを作成する手順を説明します。
- ページの表示やデータの保存など、基本的な作業ができます。
【結論】
- SymfonyはPHP開発を手助けする素晴らしいツールです。
- ウェブアプリケーションの作成や管理が簡単になります。
- 初心者でも使いやすいので、ぜひ試してみてください!
【参考資料】
- Symfony公式ウ