iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 29
0
Modern Web

PHP框架-Symfony4 + api platform 系列 第 29

Day29# 建立創建使用者及登入的共用API test function

  • 分享至 

  • xImage
  •  

上一篇把test要用的前置作業做完了,這篇要來寫簡單的創建使用者和登入的function了


首先,先來提一下Request的生命週期

  • step1: 在request body裡反序列化(Deserialize)並更新JSON變成物件
  • step2: 執行 access_control (權限檢測)
  • step3: 執行 驗證 validation

接著,我們有說到,創建使用者跟登入,可以寫成共用的function,
這樣一來,以後在寫每一支API Test的時候,就不用一直重複寫一樣的code了,
只要call這兩個functoin就好

首先,我們先來建立使用者,要建立使用者,我們必須有個User的Entity,且必須繼承UserInterface,

然後提供Http Method

/**
 * @ApiResource(
 *     accessControl="is_granted('ROLE_USER')",
 *     collectionOperations={
 *          "get",
 *          "post"={
 *              "access_control"="is_granted('IS_AUTHENTICATED_ANONYMOUSLY')",
 *              "validation_groups"={"Default", "create"}
 *          },
 *     },
 *     itemOperations={
 *          "get",
 *          "put"={"access_control"="is_granted('ROLE_USER') and object == user"},
 *          "delete"={"access_control"="is_granted('ROLE_ADMIN')"}
 *     }
 * )
 * @ApiFilter(PropertyFilter::class)
 * @UniqueEntity(fields={"username"})
 * @UniqueEntity(fields={"email"})
 * @ORM\Entity(repositoryClass="App\Repository\UserRepository")
 */
class User implements UserInterface
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @ORM\Column(type="string", length=180, unique=true)
     * @Groups({"user:read", "user:write"})
     * @Assert\NotBlank()
     * @Assert\Email()
     */
    private $email;

    /**
     * @ORM\Column(type="json")
     * @Groups({"admin:read", "admin:write"})
     */
    private $roles = [];

    /**
     * @var string The hashed password
     * @ORM\Column(type="string")
     */
    private $password;

    /**
     * @ORM\Column(type="string", length=255, unique=true)
     * @Groups({"user:read", "user:write"})
     * @Assert\NotBlank()
     */
    private $username;
    

    /**
     * @Groups("user:write")
     * @SerializedName("password")
     * @Assert\NotBlank(groups={"create"})
     */
    private $plainPassword;
    


    public function getId(): ?int
    {
        return $this->id;
    }

    public function getEmail(): ?string
    {
        return $this->email;
    }

    public function setEmail(string $email): self
    {
        $this->email = $email;

        return $this;
    }

    /**
     *
     * @see UserInterface
     */
    public function getUsername(): string
    {
        return (string) $this->username;
    }

    /**
     * @see UserInterface
     */
    public function getRoles(): array
    {
        $roles = $this->roles;
        $roles[] = 'ROLE_USER';

        return array_unique($roles);
    }

    public function setRoles(array $roles): self
    {
        $this->roles = $roles;

        return $this;
    }

    /**
     * @see UserInterface
     */
    public function getPassword(): string
    {
        return (string) $this->password;
    }

    public function setPassword(string $password): self
    {
        $this->password = $password;

        return $this;
    }

    /**
     * @see UserInterface
     */
    public function getSalt()
    {
    }

    /**
     * @see UserInterface
     */
    public function eraseCredentials()
    {
        $this->plainPassword = null;
    }

    public function setUsername(string $username): self
    {
        $this->username = $username;

        return $this;
    }


  

    public function getPlainPassword(): ?string
    {
        return $this->plainPassword;
    }

    public function setPlainPassword(string $plainPassword): self
    {
        $this->plainPassword = $plainPassword;

        return $this;
    }
    

  
}

再來,在test的目錄下建立一個Test,並extends ApiTestCase => UserApiTest

  • 創建使用者的function

    protected function createUser(string $email,string $password): User{
            $user=new User();
    
            $user->setEmail($email);
            $user->setUsername(substr($email,0,strpos($email,'@')));
    
            $encoded= self::$container->get(UserPasswordEncoderInterface::class)->encodePassword($user,$password);
    
            $user->setPassword($encoded);
    
    
            $em=self::$container->get(EntityManagerInterface::class);
    
            $em->persist($user);
            $em->flush();
    
            return $user;
        }
    
    • 以上先建立一個User物件,將傳入的email寫入email欄位裡,切割email小老鼠前面的字串寫入username裡

    • 接著,使用UserPasswordEncoderInterface 來把密碼加密 , 因為在資料庫總不能讓密碼直接顯示出來吧XD!!

    • 最後 將加密過後的密碼寫入password欄位 , persist 完, 進行寫入 , 回傳User這個我們剛寫完的物件

    Test裡沒有autowiring 所以只能從容器container裡拿我們要用的東西

    這樣一來,我們就可以每次呼叫這個function,傳入不同的email跟password來產生很多個不同的user了!!

  • 登入的function

    protected  function login(Client $client,string $email,string $password){
    
    
            $client->request('POST','/login',[
                'headers' => ['Content-Type' =>'application/json'],
                'json' =>[
                    'email' =>$email,
                    'password' =>$password
                ],
            ]);
    
            $this->assertResponseStatusCodeSame(204);
        }
    
    • 利用Client Class 可以讓我們模擬使用者的動作, 透過request假裝我們訪問"/login"的路徑,方法是用POST

    • request的標頭內容給json格式 , json內容是我們傳入的email和password

    • 最後驗證我們是不是有POST成功 , 因為POST成功的http 回應碼是204 , 所以我們要比對回應碼是否為204

  • 使用創建使用者及登入的function

     protected function createdUserAndLogin(Client $client,string $email,string $password):User{
    
            $user=$this->createUser($email,$password);
    
            $this->login($client,$email,$password);
    
    
            return $user;
    
        }
    

    記得一樣要傳入Client這個物件哦,才能在login function 裡 模擬使用者動作

  • 透過指令 php bin/phpunit 來執行所有測試

  • 如果要測試所有測試檔案的話,則php bin/phpunit --filter 測試檔案名稱


以上,簡單的測試寫完了~ 已經是第29篇了阿!!!! 好感動哦இдஇ

在前面建立實體類阿..驗證阿..等等的,是不是都是手動自己打的!!?
如果是的話,是不是覺得打這麼多字,手很痠!!?
沒有問題,程式就是要拿來用簡單去解決複雜的

下一篇,也就是最後一篇,小菜鳥會介紹一個Bundle , 給各位看官們方便偷懶可以用的

=> Maker Bundle

雖然說...Symfony跟Laravel比起來 , 真的比較少人用 , 但我們還是要堅強阿 !!!


上一篇
Day#28 Cookie & SameSite Cookie 和 安裝API test 前置作業
下一篇
Day#30 Maker Bundle 讓我們少做很多事,少打很多字!!
系列文
PHP框架-Symfony4 + api platform 30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言