symfony3がリリースされたので触ってみた

December 1, 2015,
tags: symfony php


このエントリーをはてなブックマークに追加

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/logsvar/logs
app/cachevar/cache
app/sessionsvar/sessions
って感じで変わってる

コマンドも app/consolebin/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)は必ず読んでおきましょう。

comments powered by Disqus