symfony3がリリースされたので触ってみた
Symfony3が12/1にリリースされたという事で早速触ってみました。
いきなりインストールでコケた・・・
$ symfony new blog3 Downloading Symfony...
4.93 MB/4.93 MB ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ 100%
Preparing project...
Warning: require(/Users/polidog/workspace/php/blog3/app/SymfonyRequirements.php): failed to open stream: No such file or directory in phar:///usr/local/bin/symfony/src/Symfony/Installer/DownloadCommand.php on line 236
Call Stack:
0.0016 230168 1. {main}() /usr/local/bin/symfony:0
0.0029 386760 2. require('phar:///usr/local/bin/symfony/symfony') /usr/local/bin/symfony:10
0.0163 1968520 3. Symfony\Component\Console\Application->run() phar:///usr/local/bin/symfony/symfony:35
0.0186 2282248 4. Symfony\Component\Console\Application->doRun() phar:///usr/local/bin/symfony/vendor/symfony/console/Symfony/Component/Console/Application.php:126
0.0187 2283168 5. Symfony\Component\Console\Application->doRunCommand() phar:///usr/local/bin/symfony/vendor/symfony/console/Symfony/Component/Console/Application.php:195
0.0188 2283640 6. Symfony\Component\Console\Command\Command->run() phar:///usr/local/bin/symfony/vendor/symfony/console/Symfony/Component/Console/Application.php:874
0.0197 2430896 7. Symfony\Installer\NewCommand->execute() phar:///usr/local/bin/symfony/vendor/symfony/console/Symfony/Component/Console/Command/Command.php:252
3.4350 4687240 8. Symfony\Installer\DownloadCommand->checkSymfonyRequirements() phar:///usr/local/bin/symfony/src/Symfony/Installer/NewCommand.php:64
Fatal error: require(): Failed opening required '/Users/polidog/workspace/php/blog3/app/SymfonyRequirements.php' (include_path='.:/usr/local/Cellar/php56/5.6.11_2/lib/php:/Users/polidog/workspace/php/paygent/dev') in phar:///usr/local/bin/symfony/src/Symfony/Installer/DownloadCommand.php on line 236
Call Stack:
0.0016 230168 1. {main}() /usr/local/bin/symfony:0
0.0029 386760 2. require('phar:///usr/local/bin/symfony/symfony') /usr/local/bin/symfony:10
0.0163 1968520 3. Symfony\Component\Console\Application->run() phar:///usr/local/bin/symfony/symfony:35
0.0186 2282248 4. Symfony\Component\Console\Application->doRun() phar:///usr/local/bin/symfony/vendor/symfony/console/Symfony/Component/Console/Application.php:126
0.0187 2283168 5. Symfony\Component\Console\Application->doRunCommand() phar:///usr/local/bin/symfony/vendor/symfony/console/Symfony/Component/Console/Application.php:195
0.0188 2283640 6. Symfony\Component\Console\Command\Command->run() phar:///usr/local/bin/symfony/vendor/symfony/console/Symfony/Component/Console/Application.php:874
0.0197 2430896 7. Symfony\Installer\NewCommand->execute() phar:///usr/local/bin/symfony/vendor/symfony/console/Symfony/Component/Console/Command/Command.php:252
3.4350 4687240 8. Symfony\Installer\DownloadCommand->checkSymfonyRequirements() phar:///usr/local/bin/symfony/src/Symfony/Installer/NewCommand.php:64
SymfonyRequirements.phpがないと怒られました。
Symfony3からはSymfonyRequirements.phpがvarディレクトリの中に移ったのでその影響ですね。
おそらくSymfony Installerの1.4.3を使えば大丈夫ですが、今(2015/12/1 9:54現在)だとアップデートできないので、とりあえず飛ばしますw ちなみにvendorにはファイルがあるので、念のためcomposer updateするぐらいでいいかと思います。
ディレクトリが変わっている
ログとかキャッシュが
app/logs → var/logs
app/cache → var/cache
app/sessions → var/sessions
って感じで変わってる
コマンドも
app/console → bin/console
に変わってました。
それからtestのディレクトリも
src/tests → testsへ変わっている
とりあえずブログチュートリアルやってみる
まずはdb作る
$ create database blog3
バンドルの作成は飛ばす
AppBundleの中でさくっと作っちゃうので今回は飛ばします。
Postモデルの作成
こんな感じ。
$ bin/console generate:doctrine:entity --entity=AppBundle:Post --format=annotation --fields="title:string(255) body:text createdAt:datetime updatedAt:datetime"
スキーマを作成
$ bin/console doctrine:schema:create
コントローラとルーティング
こんな感じです。
<?php
// Blog/DefaultController.php
namespace AppBundle\Controller\Blog;
use AppBundle\Entity\Post;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
/**
* Class DefaultController
* @package AppBundle\Controller\Blog
*
* @Route("/blog")
*/
class DefaultController extends Controller
{
/**
* @Route()
* @Method("GET")
* @Template(":blog/default:index.html.twig")
*/
public function indexAction()
{
return [
'posts' => $this->getDoctrine()->getRepository('AppBundle:Post')->findAll()
];
}
/**
* @Route("/{id}", requirements={"id": "\d+"})
* @Method("GET")
* @Template(":blog/default:show.html.twig",vars={"post"})
*/
public function showAction(Post $post)
{
}
}
テンプレートの作成
こんな感じ
{# app/Resources/views/blog/default/index.html.twig #}
<h1>Blog posts</h1>
<table>
<tr>
<td>Id</td>
<td>Title</td>
<td>CreatedAt</td>
</tr>
{# ここから、posts配列をループして、投稿記事の情報を表示 #}
{% for post in posts %}
<tr>
<td>{{ post.id }}</td>
<td><a href="{{ path('app_blog_default_show', {'id':post.id}) }}">{{ post.title }}</a></td>
<td>{{ post.createdAt|date('Y/m/d H:i') }}</td>
</tr>
{% else %}
<tr>
<td colspan="3">No posts found</td>
</tr>
{% endfor %}
</table>
{# app/Resources/views/blog/default/show.html.twig #}
<h1>{{ post.title }}</h1>
<p><small>Created: {{ post.createdAt|date('Y/m/d H:i') }}</small></p>
<p>{{ post.body|nl2br }}</p>
記事の追加
Defaultコントローラにnew,saveのアクションを追加しました。
<?php
/**
* Created by PhpStorm.
* User: polidog
* Date: 2015/12/01
* Time: 10:12
*/
namespace AppBundle\Controller\Blog;
use AppBundle\Entity\Post;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
/**
* Class DefaultController
* @package AppBundle\Controller\Blog
*
* @Route("/blog")
*/
class DefaultController extends Controller
{
/**
* @Route()
* @Method("GET")
* @Template(":blog/default:index.html.twig")
*/
public function indexAction()
{
return [
'posts' => $this->getDoctrine()->getRepository('AppBundle:Post')->findAll()
];
}
/**
* @Route("/{id}", requirements={"id": "\d+"})
* @Method("GET")
* @Template(":blog/default:show.html.twig",vars={"post"})
*/
public function showAction(Post $post)
{
}
/**
* @Route("/new")
* @Method("GET")
* @Template(":blog/default:new.html.twig")
*
* @return array
*/
public function newAction()
{
$form = $this->postForm();
return [
'form' => $form->createView(),
];
}
/**
* @Route("/new")
* @Method("POST")
* @Template(":blog/default:new.html.twig")
*
* @param Request $request
* @return \Symfony\Component\HttpFoundation\RedirectResponse
*/
public function saveAction(Request $request)
{
$form = $this->postForm();
$form->handleRequest($request);
if ($form->isValid()) {
$post = $form->getData();
$post->setCreatedAt(new \DateTime());
$post->setUpdatedAt(new \DateTime());
$em = $this->getDoctrine()->getManager();
$em->persist($post);
return $this->redirectToRoute('app_blog_default_index');
}
return [
'form' => $form->createView(),
];
}
/**
* @return \Symfony\Component\Form\Form
*/
private function postForm()
{
return $this->createFormBuilder(new Post())
->add('title')
->add('body')
->getForm();
}
}
viewも追加しています
{# app/Resources/views/blog/default/new.html.twig #}
<h1>Add Post</h1>
<form action="{{ path('app_blog_default_save') }}" method="post">
{{ form_widget(form) }}
<input type="submit" value="Save Post" />
</form>
index.html.twigもリンクを追記しました。
{# app/Resources/views/blog/default/index.html.twig #}
<h1>Blog posts</h1>
<div>
<a href="{{ path('app_blog_default_new') }}">add post</a>
</div>
<table>
<tr>
<td>Id</td>
<td>Title</td>
<td>CreatedAt</td>
</tr>
{# ここから、posts配列をループして、投稿記事の情報を表示 #}
{% for post in posts %}
<tr>
<td>{{ post.id }}</td>
<td><a href="{{ path('app_blog_default_show', {'id':post.id}) }}">{{ post.title }}</a></td>
<td>{{ post.createdAt|date('Y/m/d H:i') }}</td>
</tr>
{% else %}
<tr>
<td colspan="3">No posts found</td>
</tr>
{% endfor %}
</table>
バリデーションの追加
// src/My/BlogBundle/Entity/Post.php
use Symfony\Component\Validator\Constraints as Assert;
// ...
/**
* @ORM\Column(name="title", type="string", length=255)
* @Assert\NotBlank()
* @Assert\Length(min=2,max=50)
*/
protected $title;
/**
* @ORM\Column(name="body", type="text")
* @Assert\NotBlank()
* @Assert\Length(min=2)
*/
protected $body;
// ...
削除
<?php
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
class DefaultController extends Controller
{
// ...
/**
* @Route("/{id}/delete", requirements={"id":"\d+"})
* @Method("GET")
* @param Post $post
*
* @param Post $post
* @return \Symfony\Component\HttpFoundation\RedirectResponse
*/
public function deleteAction(Post $post)
{
$em = $this->getDoctrine()->getManager();
$em->remove($post);
$em->flush();
return $this->redirectToRoute('app_blog_default_index');
}
}
<h1>Blog posts</h1>
<div>
<a href="{{ path('app_blog_default_new') }}">add post</a>
</div>
<table>
<tr>
<td>Id</td>
<td>Title</td>
<td>CreatedAt</td>
<td>Operation</td>
</tr>
{# ここから、posts配列をループして、投稿記事の情報を表示 #}
{% for post in posts %}
<tr>
<td>{{ post.id }}</td>
<td><a href="{{ path('app_blog_default_show', {'id':post.id}) }}">{{ post.title }}</a></td>
<td>{{ post.createdAt|date('Y/m/d H:i') }}</td>
<td><a href="{{ path('blog_delete', {'id':post.id}) }}">Delete</a></td>
</tr>
{% else %}
<tr>
<td colspan="3">No posts found</td>
</tr>
{% endfor %}
</table>
最後に
登録までとりあえずブログチュートリアルやってみましたが、symfony2.7でコード書いていた自分としてはそこまで変更は内容に感じました。 Symfony1からSymfony2へのような変更はないので、移行は思ったよりは楽なのではないでしょうか?
しかしプロジェクトレベルだと変更に対応しなければならない箇所もあるとおもうので[UPGRADE-3.0])(https://github.com/symfony/symfony/blob/2.8/UPGRADE-3.0.md)は必ず読んでおきましょう。