Symfony4 ユーザー認証機能作成（前編）

今回作成する予定のテーブル

User（ユーザー）テーブル

|  項目名  | 日本語名 |  型  |  必須  |
| ---- | ---- |  ---- |  ---- |
|  id  |  ID（連番）  |  integer |  〇 |
|  username  |  ユーザー名  |  string |  〇 |
|  password  |  パスワード  |  string  |  〇 |
|  email  |  メールアドレス  |  string |  〇 |
|  isActiveted  |  活動フラグ  |  boolean |  〇 |

エンティティの作成

```bash
$ php bin/console make:entity
```
Formの作成

```bash
$ php bin/console make:form User
```
マイグレーションの作成

```bash
$ php bin/console make:migration
```

マイグレーション実行

```bash
$ php bin/console doctrine:migrations:migrate
```
User.phpに以下の記述を追記。

```php:src/Entity/User.php
<?php

namespace App\Entity;

use App\Repository\UserRepository;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;

/**
 * @ORM\Entity(repositoryClass=UserRepository::class)
 * @UniqueEntity("username")
 * @UniqueEntity("email")
 */
class User implements UserInterface, \Serializable
{
    /**
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @ORM\Column(type="string", length=255 unique=true)
     */
    private $username;

    /**
     * @ORM\Column(type="string", length=255)
     */
    private $password;

    /**
     * @ORM\Column(type="string", length=255 unique=true)
     */
    private $email;

    /**
     * @ORM\Column(type="boolean")
     */
    private $isActivated;

/*
省略
*/

    public function __construct()
    {
        $this->isActivated = true;
    }

    public function getSalt()
    {
        return null;
    }

    public function getRoles()
    {
        if ($this->username == 'admin') {
            return array('ROLE_ADMIN');
        } else {
            return array('ROLE_USER');
        }
    }

    public function eraseCredentials()
    {
    }

    public function serialize()
    {
        return serialize(array(
            $this->id,
            $this->username,
            $this->password,
            $this->isActivated,
        ));
    }

    public function unserialize($serialized)
    {
        list(
            $this->id,
            $this->username,
            $this->password,
            $this->isActivated,
        ) = unserialize($serialized, array('allowed_classes'
          => false));
    }
```
UserTypeクラスを編集

```php:src/Form/UserType.php
<?php

namespace App\Form;

use App\Entity\User;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;

class UserType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('username', TextType::class)
            ->add('password', PasswordType::class)
            ->add('email', EmailType::class)
            ->add('register', SubmitType::class)
        ;
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            'data_class' => User::class,
        ]);
    }
}

```

RegisterControllerの作成

```bash
$ php bin/console make:controller
```

```php:src/Conteoller/RegisterController.php
<?php

namespace App\Controller;

use App\Form\UserType;
use App\Entity\User;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;

class RegisterController extends AbstractController
{
    /**
     * @Route("/register", name="register")
     */
    public function register(Request $request, UserPasswordEncoderInterface $passwordEncoder): Response
    {
        $user = new User;
        $form = $this->createForm(UserType::class, $user);

        $form->handleRequest($request);

        if ($request->getMethod() == 'POST') {
            if ($form->isValid()) {
                $password = $passwordEncoder->encodePassword($user, $user->getPassword());
                $user->setPassword($password);
                $manager = $this->getDoctrine()->getManager();
                $manager->persist($user);
                $manager->flush();
                return $this->redirectToRoute('ルート先');
            }
        } else {
            return $this->render('register/register.html.twig', [
                'form' => $form->createView(),
            ]);
        }
    }
}
```
security.yamlを修正する

```yaml:config/package/security.yaml
security:
    # https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
    providers:
        our_db_provider:
            entity:
                class: App\Entity\User
                property: username

    firewalls:
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false
        main:
            anonymous: ~
            pattern: ^/
            provider: our_db_provider

            form_login:
                login_path: login
                check_path: login
            logout:
                path:   logout
                target: login
                invalidate_session: false

            # activate different ways to authenticate
            # https://symfony.com/doc/current/security.html#firewalls-authentication

            # https://symfony.com/doc/current/security/impersonating_user.html
            # switch_user: true

    # Easy way to control access for large sections of your site
    # Note: Only the *first* access control that matches will be used
    access_control:
        - { path: ^/admin, roles: ROLE_ADMIN }
        # - { path: ^/profile, roles: ROLE_USER }

    encoders:
        App\Entity\User:
            algorithm: bcrypt

```

登録できることを確認する。
http://127.0.0.1:8000/register

後編に続く
[Symfony4 ユーザー認証機能作成（後編）](https://qiita.com/RyotaIhara/items/e31e31ca2a10b9d25122)