Laravel에서 Carbon과 같은 캐스트 만들기

Laravel을 사용하는 대부분의 사람들은 Carbon이 패키지와 함께 제공되고 단순히 굉장하기 때문에 날짜 캐스팅에 Carbon을 사용했습니다.

자신만의 맞춤형 캐스트에 대해 유사한 경험을 만들고 싶다면 어떻게 해야 할까요?

따라서 비슷한 것을 달성하는 방법에 대한 간단한 가이드가 있습니다.
(예를 들어 통화를 사용하지만 이를 모든 것에 적용할 수 있습니다.)

첫째, 간단한 생성자와 몇 개의 정적 개시자가 있는 신뢰할 수 있는 유형 클래스가 필요합니다( Carbon::parse('05/05/22') 와 같이). 또한 사용하기 쉽도록 toUsd()toCents()와 같은 일부 게터가 있으면 좋을 것입니다.

class Currency
{
    public function __construct(int $amountInCents)
    {
        $this->amountInCents = $amountInCents;
    }

    public static function fromCents(int $amountInCents):Currency
    {
        return new self($amountInCents);
    }

    public static function fromUsd(float|int $amount): Currency
    {
        return new self($amount * 100);
    }

    public function toUsd(): float|int
    {
        return $this->amountInCents / 100;
    }

    public function toCents(): int
    {
        return $this->amountInCents;
    }
}


이제 우리는 Currency::fromCents(100) 를 사용하여 클래스를 시작할 수 있습니다. 부동 소수점은 데이터베이스 수준에서 이상하기 때문에 모든 통화를 센트 단위로 저장하는 것을 선호하지만 여기서 핵심에 들어가지 않겠습니다.

둘째, 이를 위해 라라벨의 커스텀 캐스트 기능을 활용할 것입니다.

class Currency implements CastsAttributes
{
    /**
     * Cast the given value.
     *
     * @param  Model  $model
     * @param  string  $key
     * @param  mixed  $value
     * @param  array  $attributes
     * @return CurrencyType
     */
    public function get($model, string $key, mixed $value, array $attributes): CurrencyType
    {
        return CurrencyType::fromCents($value);
    }

    /**
     * @param  Model  $model
     * @param  string  $key
     * @param  CurrencyType|string|float|int  $value
     * @param  array  $attributes
     * @return int
     * @throws InvalidCurrencyFormatException
     */
    public function set($model, string $key, mixed $value, array $attributes): int
    {
        if (!($value instanceof CurrencyType)) {
            $currency = CurrencyType::class;
            $type = getType($value);
            throw new InvalidCurrencyFormatException("The given value must be $currency. $type was given.");
        }

        return $value->toCents();
    }


이 단계에 대한 자세한 내용은 docs을 참조하십시오.

이제 다음과 같은 모든 모델에서 사용할 수 있는 반짝이는Currency 캐스트가 있습니다.

'money_column' => Currency::class,


나는 우리 모두 캐스트가 얼마나 마법 같은 🪄인지 알고 있다고 확신하지만 여기서 우리가 달성한 것을 간략하게 설명하겠습니다.
  • 이 열을 저장하고 싶을 때마다 Currency 개체를 사용하고 데이터베이스로 보내면 질문 없이 자동으로 센트 단위로 저장됩니다.
  • 데이터베이스에서 이 레코드를 가져올 때마다 자동으로 Currency 형식이 되며 원하는 대로 getter를 사용할 수 있습니다.

  • 이제 이 시점에서 멈추고 하루라고 부를 수 있습니다. 나는 당신을 전혀 비난하지는 않지만 완전한 Carbon 스타일 캐스트 경험을 제공하기 위해 여기에 있습니다. 그러니 조금 더 나아가면 후회하지 않을 거라고 확신합니다(그렇지 않기를 바랍니다).

    우리의 다음 단계는 우리 대부분이 Carbon에 대해 당연하게 여기는 아름다운 디테일입니다.(적어도 저는 최근까지 그랬습니다)

    Carbon 객체가 프런트엔드(블레이드 또는 json)에 전달되면 마술처럼 객체 대신 형식이 지정된 문자열로 바뀝니다.

    이것을 Currency 클래스에 추가해 봅시다.

    use JsonSerializable;
    
    class Currency implements JsonSerializable
    {
        protected int $amountInCents;
    
        public function __construct(int $amountInCents)
        {
            $this->amountInCents = $amountInCents;
        }
    
        public static function fromCents(int $amountInCents): Currency
        {
            return new self($amountInCents);
        }
    
        public static function fromUsd(float|int $amount): Currency
        {
            return new self($amount * 100);
        }
    
        public function toUsd(): float|int
        {
            return $this->amountInCents / 100;
        }
    
        public function toCents(): int
        {
            return $this->amountInCents;
        }
    
        public function toReadable(): string
        {
            return number_format($this->toUsd(), 2);
        }
    
        public function jsonSerialize(): string
        {
            return $this->toReadable();
        }
    
        public function __toString(): string
        {
            return $this->toReadable();
        }
    }
    


    JsonSerializable은 자세한 정보를 볼 수 있는 기본 PHP 인터페이스입니다php docs.
    _JsonSerializable 인터페이스를 사용하면 클래스가 json_encode()를 거칠 때마다 jsonSerialize( 함수가 사용되고 Laravel은 거의 항상 json_encode() 클래스 내에서 ResponseFactory를 통해 모든 응답을 실행합니다.
    이것을 알아내는 데 너무 오래 걸렸다는 것을 인정해야 합니다.

    또한 __toString() 메서드를 추가하여 언제든지 이 클래스를 문자열로 사용하려는 경우 다른 도우미가 필요하지 않습니다.

    $currency = Currency::fromUsd(1);
    json_encode($currency); //"1.00"
    echo $currency; //"1.00"
    
    ...
    return response()->json(['amount' => $currency]) //would be "1.00" on the front-end
    


    나는 그것이 우아하다고 생각합니다. 통화를 센트 또는 USD로 저장하는 것에 대한 모든 걱정이 사라졌습니다.

    이와 같은 다른 사용 사례가 있다면 의견에서 보고 싶습니다. 많을 것이라고 확신합니다.

    읽어주셔서 감사합니다. 여기까지 읽으셨다면 ❤️를 남겨주세요.

    또한 이것에 대한 추가 개선 사항이 있거나 이것이 유용하거나 아이디어가 싫은 경우 댓글로 알려주십시오 😬

    좋은 웹페이지 즐겨찾기