재사용 가능한 액션 클래스

15055 단어 laravelaction
Jetstream에 익숙하다면 프로젝트에서 app/Actions 디렉토리를 볼 수 있습니다. 이 게시물은 간단하고 재사용 가능한 액션 클래스를 작성하기 위한 것입니다.

우리의 행동이 무엇을 해야 하는지 개요를 작성해 봅시다:
  • 입력을 수락할 수 있음
  • 검증 가능
  • 업데이트/생성 가능
  • 사용은 기본 클래스를 확장하고 사용할 규칙 및 모델을 정의하기만 하면 됩니다.

  • 위의 4가지 규칙:

    <?php
    
    namespace App\Actions;
    
    use App\Contracts\Execute;
    use App\Exceptions\ActionException;
    use Illuminate\Database\Eloquent\Model;
    use Illuminate\Support\Facades\DB;
    use Illuminate\Support\Facades\Validator;
    
    abstract class AbstractAction implements Execute
    {
        protected array $constrainedBy = [];
        protected Model $record;
    
        abstract public function rules(): array;
    
        public function __construct(protected array $inputs)
        {
        }
    
        public function setInputs(array $inputs): self
        {
            $this->inputs = $inputs;
    
            return $this;
        }
    
        public function setConstrainedBy(array $constrainedBy): self
        {
            $this->constrainedBy = $constrainedBy;
    
            return $this;
        }
    
        public function getConstrainedBy(): array
        {
            return $this->constrainedBy;
        }
    
        public function hasConstrained(): bool
        {
            return count($this->getConstrainedBy()) > 0;
        }
    
        public function getInputs(): array
        {
            return $this->inputs;
        }
    
        public function model(): string
        {
            if (! property_exists($this, 'model')) {
                throw ActionException::missingModelProperty(__CLASS__);
            }
    
            return $this->model;
        }
    
        public function execute()
        {
            Validator::make(
                array_merge(
                    $this->getConstrainedBy(),
                    $this->getInputs()
                ),
                $this->rules()
            )->validate();
    
            return $this->record = DB::transaction(function () {
                return $this->hasConstrained()
                    ? $this->model::updateOrCreate($this->getConstrainedBy(), $this->getInputs())
                    : $this->model::create($this->getInputs());
            });
        }
    
        public function getRecord(): Model
        {
            return $this->record;
        }
    }
    


    그리고 커스텀 예외:

    <?php
    
    namespace App\Exceptions;
    
    use Exception;
    
    class ActionException extends Exception
    {
        public static function missingModelProperty($class)
        {
            return new self("Missing model property in class $class");
        }
    }
    


    그리고 계약:

    <?php
    
    namespace App\Contracts;
    
    interface Execute
    {
        public function execute();
    }
    


    이제 사용 방법을 살펴 보겠습니다. 추상 클래스를 확장하는 클래스를 만듭니다.

    <?php
    
    namespace App\Actions\User;
    
    use App\Actions\AbstractAction as Action;
    use App\Actions\Fortify\PasswordValidationRules;
    use App\Models\User;
    
    class UpdateOrCreate extends Action
    {
        use PasswordValidationRules;
    
        public $model = User::class;
    
        public function rules(): array
        {
            return [
                'name' => ['required', 'string', 'max:255'],
                'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
                'password' => $this->passwordRules(),
            ];
        }
    }
    


    사용법:

    use \App\Actions\User\UpdateOrCreate as UpdateOrCreateUser;
    
    $data = [
        'name' => 'Nasrul Hazim',
        'email' => '[email protected]',
        'password' => 'password',
        'password_confirmation' => 'password',
    ];
    (new UpdateOrCreateUser($data))->execute();
    


    또 다른 예:

    <?php
    
    namespace App\Actions\Ushot;
    
    use App\Actions\AbstractAction as Action;
    use App\Models\Project;
    
    class CreateOrUpdateProject extends Action
    {
        public $model = Project::class;
    
        public function rules(): array
        {
            return [
                'name' => ['required', 'string', 'max:255'],
            ];
        }
    }
    


    사용법:

    
    $project = (new Project(['name' => 'dev.to']))->execute();
    // do something with $project->getRecord();
    


    다음을 처리할 수 있습니다.
  • 암호화/복호화
  • 해싱
  • 레코드 유효성 검사/삽입/업데이트 이전의 모든 데이터 변환.
  • 좋은 웹페이지 즐겨찾기