Как использовать laravel enum, по дополнительным атрибутам и локализации

Я хочу использовать Ben Sampo Package для перечисления в laravel. этот пакет имеет свойство с именем «описание» в качестве нового свойства. но я не могу добавить дополнительные свойства (атрибуты) в свои перечисления.

Я хочу иметь статус перечисления с атрибутом isfinal. чтобы определить, является ли этот ключ окончательным или нет?

Мне действительно нужно добавить некоторые атрибуты к некоторым перечислениям. там в любом случае ?

Я проверил этот пакет тоже. это так хорошо и действительно легко добавить дополнительные свойства. но мне тоже нужна локализация, а ее по умолчанию нет.

Редактировать: перечисление, которое мне нужно, выглядит примерно так:

final class Status extends Enum
{
#[Color('red')]
#[Description('Initial status')]
#[IsFinal(false)]    
const Initial = 1;

#[Color('blue')]
#[Description('suspended status')]
#[IsFinal(false)] 
const Pending = 2;

#[Color('white')]
#[Description('completed status')]
#[IsFinal(true)] 
const Completed = 3;

#[Color('red')]
#[Description('canceled status')]
#[IsFinal(true)] 
const Canceled = 4;
 }

И затем я хочу получить значение цвета или окончательное значение, подобное этому:

Status::getColor(1);

 

и

Status::Initial->getColor();

и

$enum->getColor();

Обновление: теперь у меня есть эта черта:

   <?php
namespace App\Enums\Concerns;

use BenSampo\Enum\Attributes\Description;
use Exception;

/**
 * Get Enum attributes
 */
trait GetEnumAttributes
{
    public $color;
    public $isFinal;

    public function __construct(mixed $enumValue)
    {
        $this->color = $this->getCustomAttribute($enumValue, 'color');
        $this->isFinal = $this->getCustomAttribute($enumValue, 'is_final');
        $this->description = self::getDescription($enumValue);
        parent::__construct($enumValue);
    }

    protected static function getCustomAttribute(mixed $value, $key)
    {
        $reflection = self::getReflection();
        $constantName = static::getKey($value);
        $constReflection = $reflection->getReflectionConstant($constantName);
        if ($constReflection === false) {
            return null;
        }

        switch ($key) {
            case 'color':
              //  dd( $constReflection->getAttributes(Color::class));
                $customAttributes = $constReflection->getAttributes(Color::class);
                break;
            case 'is_final':
                $customAttributes = $constReflection->getAttributes(IsFinal::class);
                break;
            case 'description':
                    $customAttributes = $constReflection->getAttributes(Description::class);
                    break;
            default:
                $customAttributes = [];
                break;
        }

        return match (count($customAttributes)) {
            0 => null,
            1 => $customAttributes[0]->newInstance()->$key,
            default => throw new Exception('You cannot use more than 1 custom attribute on ' . class_basename(static::class) . '::' . $constantName),
        };
    }
    public static function getCustomInstances()
    {
        return array_map(
            function ($constantValue) {
                $newStatic = new static($constantValue);
                $newStatic = (array) $newStatic;
                $newStatic['description'] = self::getCustomAttribute($constantValue,'description');//getDescription($constantValue);
                $newStatic['color'] = self::getCustomAttribute($constantValue,'color');
                $newStatic['isFinal'] = self::getCustomAttribute($constantValue,'is_final');
                $newStatic = (object) $newStatic;
                return $newStatic;
            },
            static::getConstants(),
        );
    }  

}

И это происходит, когда я использую:

dd(Status::getInstances());

результат:

array:4 [▼ // app\Http\Controllers\testController.php:19
  "Initial" => App\Enums\Status {#416 ▼
    +value: 1
    +key: "Initial"
    +description: "initial status"
    +color: null
    +isFinal: null
  }
  "Pending" => App\Enums\Status {#418 ▼
    +value: 2
    +key: "Pending"
    +description: "suspended status"
    +color: null
    +isFinal: null
  }
  "Completed" => App\Enums\Status {#421 ▶}
  "Canceled" => App\Enums\Status {#422 ▶}
]

Я проверил проблему в «getCustomAttribute» на случай:

case 'color':
                dd( $constReflection->getAttributes(Color::class));
                $customAttributes = $constReflection->getAttributes(Color::class);
                break;

возвращает null, однако $constReflection имеет все атрибуты правильно. то же самое происходит, когда я использую

Status::getCustomInstances();
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
2
0
223
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Для пакета BenSampo вы можете сделать это следующим образом:
Создайте черту:

<?php

namespace App\Traits;

/**
 * Get Enum Description
 */
trait GetEnumDescription
{
    private static $thisClass;

    public static function getCustomEnumDescription($enumValue = 0)
    {
        return __(self::getEnumDescription(intval($enumValue)));
    }

    private static function getEnumDescription($enumValue = 0)
    {
        self::$thisClass = static::class;
        $key = self::$thisClass::getKey($enumValue);
        return ucwords(str_replace('_', ' ', $key));
    }

    public static function getCustomInstances()
    {
        return array_map(
            function ($constantValue) {
                $newStatic = new static($constantValue);
                $newStatic = (array) $newStatic;
                $newStatic['custom_description'] = self::getCustomEnumDescription($constantValue);
                $newStatic = (object) $newStatic;
                return $newStatic;
            },
            static::getConstants(),
        );
    }
}

Создайте Enum (обычно я делаю значения перечисления с числовыми именами и именами переменных в змеином регистре. Вы можете настроить методы по своему усмотрению):

<?php

declare(strict_types=1);

namespace App\Enums;

use App\Traits\GetEnumDescription;
use BenSampo\Enum\Enum;

/**
 * Menu item types
 */
final class MenuItemType extends Enum
{
    use GetEnumDescription;

    const both = 0;
    const only_customer = 1;
    const only_vendor = 2;
    const closed = 3;
}

Убедитесь, что вы используете черту GetEnumDescription. Примеры:

// app()->setLocale('tr');
// dd(MenuItemType::getCustomInstances());
// RESULT:
array:4 [▼
  "both" => {#1156 ▼
    +"value": 0
    +"key": "both"
    +"description": "Both"
    +"custom_description": "Her ikisi de"
  }
  "only_customer" => {#1157 ▼
    +"value": 1
    +"key": "only_customer"
    +"description": "Only customer"
    +"custom_description": "Sadece müşteri"
  }
  "only_vendor" => {#1159 ▼
    +"value": 2
    +"key": "only_vendor"
    +"description": "Only vendor"
    +"custom_description": "Sadece bayi"
  }
  "closed" => {#1158 ▼
    +"value": 3
    +"key": "closed"
    +"description": "Closed"
    +"custom_description": "Closed"
  }
]

Пример:

public static function getCustomInstances()
{
    return array_map(
        function ($constantValue) {
            $newStatic = new static($constantValue);
            $newStatic = (array) $newStatic;
            $newStatic['custom_description'] = self::getCustomEnumDescription($constantValue);
            $newStatic['color'] = 'red';
            $newStatic['is_final'] = true;
            $newStatic = (object) $newStatic;
            return $newStatic;
        },
        static::getConstants(),
    );
}

Результат:

// after attributes added: dd(MenuItemType::getCustomInstances());
array:4 [▼
  "both" => {#1156 ▼
    +"value": 0
    +"key": "both"
    +"description": "Both"
    +"custom_description": "Her ikisi de"
    +"color": "red"
    +"is_final": true
  }
  "only_customer" => {#1157 ▼
    +"value": 1
    +"key": "only_customer"
    +"description": "Only customer"
    +"custom_description": "Sadece müşteri"
    +"color": "red"
    +"is_final": true
  }
  "only_vendor" => {#1158 ▼
    +"value": 2
    +"key": "only_vendor"
    +"description": "Only vendor"
    +"custom_description": "Sadece bayi"
    +"color": "red"
    +"is_final": true
  }
  "closed" => {#1159 ▼
    +"value": 3
    +"key": "closed"
    +"description": "Closed"
    +"custom_description": "Kapalı"
    +"color": "red"
    +"is_final": true
  }
]

Создайте два атрибута, чтобы сделать его в нужной вам структуре:
Color Атрибут:

<?php

declare(strict_types=1);

namespace App\Attributes;

use Attribute;

#[Attribute(Attribute::TARGET_CLASS_CONSTANT | Attribute::TARGET_CLASS)]
class Color
{
    public function __construct(
        public string $color,
    ) {
    }
}

И IsFinal Атрибут:

<?php

declare(strict_types=1);

namespace App\Attributes;

use Attribute;

#[Attribute(Attribute::TARGET_CLASS_CONSTANT | Attribute::TARGET_CLASS)]
class IsFinal
{
    public function __construct(
        public bool $is_final,
    ) {
    }
}

Вот как я создал ваше перечисление:

<?php

declare(strict_types=1);

namespace App\Enums;

use App\Attributes\Color;
use App\Attributes\IsFinal;
use BenSampo\Enum\Attributes\Description;
use BenSampo\Enum\Enum;
use Exception;

/**
 * Menu item types
 */
final class MenuItemType extends Enum
{
    public $color;
    public $isFinal;

    public function __construct(mixed $enumValue)
    {
        $this->color = $this->getCustomAttribute($enumValue, 'color');
        $this->isFinal = $this->getCustomAttribute($enumValue, 'is_final');
        parent::__construct($enumValue);
    }

    protected static function getCustomAttribute(mixed $value, $key)
    {
        $reflection = self::getReflection();
        $constantName = static::getKey($value);
        $constReflection = $reflection->getReflectionConstant($constantName);
        if ($constReflection === false) {
            return null;
        }

        switch ($key) {
            case 'color':
                $customAttributes = $constReflection->getAttributes(Color::class);
                break;
            case 'is_final':
                $customAttributes = $constReflection->getAttributes(IsFinal::class);
                break;
            default:
                break;
        }

        return match (count($customAttributes)) {
            0 => null,
            1 => $customAttributes[0]->newInstance()->$key,
            default => throw new Exception('You cannot use more than 1 custom attribute on ' . class_basename(static::class) . '::' . $constantName),
        };
    }

    const both = 0;
    const only_customer = 1;

    #[Color('blue')]
    #[Description('test')]
    #[IsFinal(true)]
    const only_vendor = 2;

    #[Color('red')]
    #[IsFinal(false)]
    const closed = 3;
}

Сделайте это с помощью dd(MenuItemType::getInstances()); Результат, когда я печатаю экран с помощью:

array:4 [▼ // app\Providers\AppServiceProvider.php:24
  "both" => App\Enums\MenuItemType {#1156 ▼
    +value: 0
    +key: "both"
    +description: "Both"
    +color: null
    +isFinal: null
  }
  "only_customer" => App\Enums\MenuItemType {#1157 ▼
    +value: 1
    +key: "only_customer"
    +description: "Only customer"
    +color: null
    +isFinal: null
  }
  "only_vendor" => App\Enums\MenuItemType {#1158 ▼
    +value: 2
    +key: "only_vendor"
    +description: "test"
    +color: "blue"
    +isFinal: true
  }
  "closed" => App\Enums\MenuItemType {#1160 ▼
    +value: 3
    +key: "closed"
    +description: "Closed"
    +color: "red"
    +isFinal: false
  }
]

Наслаждайся работой.

спасибо, но где мне определить значение custon_description для всех ключей в перечислении? Я добавляю #[custom_description('red')] но это не работает.

ERasekh 19.05.2023 10:53

могу ли я использовать этот код для любых других атрибутов? как "цвет", "конечный", ...

ERasekh 19.05.2023 10:54

Я хочу иметь статус перечисления с атрибутом isfinal. чтобы определить, является ли этот ключ окончательным или нет?

ERasekh 19.05.2023 10:58

@ERasekh Да, можешь. Я добавил свойства color и is_final в качестве примера и обновил ответ.

cengsemihsahin 19.05.2023 11:24

Пожалуйста, добавляйте код и данные в виде текста (с использованием форматирования кода ), а не изображений. Изображения: A) не позволяйте нам копировать и вставлять код/ошибки/данные для тестирования; Б) не разрешать поиск по коду/ошибке/содержимому данных; и много других причин. Изображения должны использоваться в дополнение к тексту в формате кода только в том случае, если изображение добавляет что-то важное, что не передается только текстовым кодом/ошибкой/данными.

gre_gor 19.05.2023 11:46

В вашем wxample цвет и isFinal всегда одинаковы. Я хочу определить эти свойства следующим образом: #[Color('red')] выше для каждого ключа перечисления, который я хочу.

ERasekh 19.05.2023 14:49

Хорошо, вы можете сделать эту функцию, создав Attribute. Вскоре я добавлю пример в конец своего ответа.

cengsemihsahin 19.05.2023 15:29

Я обновил свой вопрос и добавил то, что хочу, в примере кода. Вы знаете, что я имею в виду?

ERasekh 19.05.2023 15:29

мой вопрос, как добавить дополнительный атрибут? спасибо за ваши быстрые ответы. но я думаю, вы неправильно понимаете.

ERasekh 19.05.2023 15:30

спасибо @cengsemihsahin. Я создал атрибут рядом с «описанием» в пакете bensampo. но я не знал, что мне делать, чтобы получить значения этого атрибута, которые выше ключей перечисления.

ERasekh 19.05.2023 15:33

возвращает null для двух моих новых атрибутов. вы сообщаете getInstances(), но определили getCustomInstances сегодня утром. теперь оба метода возвращают null для новых атрибутов.

ERasekh 19.05.2023 16:22

Вы не должны использовать оба способа вместе. Можете ли вы поделиться полным содержанием классов атрибутов и Enum, которые вы создали, обновив свой вопрос?

cengsemihsahin 19.05.2023 16:26

Я обновил, можешь проверить?

ERasekh 19.05.2023 17:02

Я путаюсь. Я удаляю свой трейт и пишу код, как вы, в классе enum. оно работает!! почему черта не работает? есть подвох????

ERasekh 20.05.2023 09:14

так красиво! Огромное спасибо. Я понял ваш код и поведение. и теперь я могу настроить его. большое спасибо.

ERasekh 20.05.2023 09:33

Пакет BenSampo Laravel Enum отлично подходит для простой настройки перечислений в Laravel. Однако добавление дополнительных настраиваемых атрибутов может быть немного сложным, так как на данный момент он не поддерживается пакетом.

Вот несколько возможных подходов к достижению вашей цели:

  1. Расширьте класс Enum с помощью пользовательских методов:

Вы можете расширить базовый класс Enum для поддержки дополнительных атрибутов. Однако для этого требуется изменить сам класс Enum, что может быть не идеально, если вы работаете в команде или планируете обновить пакет в будущем.

    namespace App\Enums;

use BenSampo\Enum\Enum as BaseEnum;

class Enum extends BaseEnum
{
    public static function isFinal($value) {
        // define the logic here
    }
}

А затем используйте этот базовый класс для своих перечислений:

namespace App\Enums;

class Status extends Enum
{
    const DRAFT = 0;
    const FINAL = 1;
    
    public static function getDescription($value): string
    {
        if ($value === self::FINAL) {
            return 'Final';
        }

        return parent::getDescription($value);
    }
}

С помощью описанного выше метода теперь вы можете проверить, является ли значение перечисления окончательным или нет:

Status::isFinal(Status::FINAL); // Should return true
  1. Используйте дополнительные классы Enum:

Другой подход может заключаться в создании отдельных Enum для этих особых случаев. Например, у вас может быть класс перечисления FinalStatus для статусов, которые являются окончательными.

namespace App\Enums;

use BenSampo\Enum\Enum;

final class FinalStatus extends Enum
{
    const PUBLISHED = 1;
    // Add more final statuses here
}

Затем вы можете использовать функции локализации Laravel для локализации ваших перечислений. Вы должны создать языковые файлы для каждого языка, который хотите поддерживать, и использовать функцию __() в коде вашего приложения для извлечения локализованной строки.

В любом случае, самым чистым решением было бы наличие в пакете встроенной поддержки дополнительных атрибутов. Вы можете создать проблему или запрос на извлечение в репозитории пакета GitHub, чтобы узнать, будут ли сопровождающие открыты для такой функции.

спасибо, я отредактировал свой вопрос и добавил код. Я хочу написать код как это.

ERasekh 19.05.2023 14:59

о проблеме с пакетом, да, я сначала отправил проблему, но он закрыл ее без какого-либо надлежащего ответа, который решил мою проблему.

ERasekh 19.05.2023 15:00
github.com/BenSampo/laravel-enum/issues/314
ERasekh 19.05.2023 15:00

Я думаю, вы слишком все усложняете. Класс Enum из этого пакета является классом php, как и любой другой, поэтому в вашем случае я бы посоветовал добавить некоторые статические методы в класс Status, которые возвращают соответствующее значение в зависимости от случая ввода.

например это может выглядеть примерно так:

<?php

use BenSampo\Enum\Enum;

final class Status extends Enum
{
    const Initial = 1;
    const Pending = 2;
    const Completed = 3;
    const Canceled = 4;

    public static function getColor(Status $status): string
    {
        return match ($status->value) {
            self::Initial => 'gray',
            self::Pending => 'yellow',
            self::Completed => 'green',
            self::Canceled => 'red',
        };
    }

    public static function isFinal(Status $status): bool
    {
        return in_array($status->value, [self::Completed, self::Canceled]);
    }
 }

Который вы можете использовать следующим образом:

$status = Status::Completed();

Status::getColor($status); // "green"
Status::isFinal($status); // true

PR на упаковке приветствуются и учитываются, если они хорошо продуманы и правильно реализованы. Более динамичная система атрибутов может быть хорошим дополнением.

спасибо, но если подход @cengsemihsahin решил мою проблему, мне это нравится больше.

ERasekh 19.05.2023 16:47

хотя, в вашем методе, я могу добавить локализацию, запросто. Я думаю...

ERasekh 19.05.2023 16:48

спасибо, в приведенном выше посте один программист решил мою проблему и помог мне лучше понять ваш пакет. Я могу отправить вам обновление Documentaion, чтобы добавить его в ваш гайд, если хотите.

ERasekh 20.05.2023 09:36

Другие вопросы по теме