rename package

master 1.0
Ifornew 3 years ago
commit a8332f7a8d

2
.gitignore vendored

@ -0,0 +1,2 @@
/vendor
/.idea

@ -0,0 +1,60 @@
<?php
$finder = Symfony\CS\Finder\DefaultFinder::create()
->in(__DIR__)
->exclude(
array(
'artifacts',
'vendor',
)
);
return Symfony\CS\Config\Config::create()
->level(Symfony\CS\FixerInterface::PSR2_LEVEL)
->fixers(
array(
// symfony
'blankline_after_open_tag',
'duplicate_semicolon',
'extra_empty_lines',
'include',
'join_function',
'list_commas',
'multiline_array_trailing_comma',
'namespace_no_leading_whitespace',
'new_with_braces',
'no_blank_lines_after_class_opening',
'no_empty_lines_after_phpdocs',
'object_operator',
'operators_spaces',
'phpdoc_indent',
'phpdoc_params',
'phpdoc_short_description',
'phpdoc_to_comment',
'phpdoc_trim',
'phpdoc_type_to_var',
'phpdoc_var_without_name',
'pre_increment',
'remove_leading_slash_use',
'remove_lines_between_uses',
'return',
'self_accessor',
'single_array_no_trailing_comma',
'single_blank_line_before_namespace',
'single_quote',
'spaces_before_semicolon',
'spaces_cast',
'standardize_not_equal',
'ternary_spaces',
'trim_array_spaces',
'unary_operators_spaces',
'unused_use',
'whitespacy_lines',
// contrib
'concat_with_spaces',
'multiline_spaces_before_semicolon',
'ordered_use',
)
)
->finder($finder);

15
.sami

@ -0,0 +1,15 @@
<?php
use Sami\Parser\Filter\SymfonyFilter;
use Sami\Sami;
return new Sami(
'src',
array(
'title' => 'Enumeration API',
'default_opened_level' => 2,
'build_dir' => 'artifacts/documentation/api',
'cache_dir' => 'artifacts/documentation/api-cache',
'filter' => new SymfonyFilter(),
)
);

@ -0,0 +1,19 @@
Copyright © 2018 I For New
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

@ -0,0 +1,275 @@
# Enum
*An enum implementation for PHP.*
## Installation and documentation
- Available as [Composer] package [ifornew/enum].
[composer]: http://getcomposer.org/
[ifornew/enum]: https://packagist.org/packages/ifornew/enum
## What is an Enum?
In terms of software development, an enumeration (or "enum type") is
essentially a fixed set of values. These values are called "members" or
"elements".
An enumeration is used in circumstances where it is desirable to allow an
argument to be only one of a particular set of values, and where anything else
is considered invalid.
## A basic example
*Enum* can be used like [C++ enum types]. Here is an example,
representing a set of HTTP request methods:
```php
use Ifornew\Enum\AbstractEnumeration;
/**
* Class HttpMethod
* @method static HttpMethod OPTIONS
* @method static HttpMethod GET
* @method static HttpMethod HEAD
* @method static HttpMethod POST
* @method static HttpMethod PUT
* @method static HttpMethod DELETE
* @method static HttpMethod TRACE
* @method static HttpMethod CONNECT
*/
final class HttpRequestMethod extends AbstractEnumeration
{
const OPTIONS = 'OPTIONS';
const GET = 'GET';
const HEAD = 'HEAD';
const POST = 'POST';
const PUT = 'PUT';
const DELETE = 'DELETE';
const TRACE = 'TRACE';
const CONNECT = 'CONNECT';
}
```
This class can now be used in a type hint to easily accept any valid HTTP
request method:
```php
function handleHttpRequest(HttpRequestMethod $method, $url, $body = null)
{
// handle request...
}
```
[c++ enumerated types]: https://en.wikipedia.org/wiki/Enumerated_type#C.2B.2B
## Accessing enum members
Members are accessed by static method calls, like so:
```php
handleHttpRequest(HttpRequestMethod::GET(), 'http://example.org/');
handleHttpRequest(HttpRequestMethod::POST(), 'http://example.org/', 'foo=bar&baz=qux');
```
For each member of the enumeration, a single instance of the enumeration class
is instantiated (that is, an instance of `HttpRequestMethod` in the above
example). This means that strict comparison (===) can be used to determine
which member has been passed to a function:
```php
function handleHttpRequest(HttpRequestMethod $method, $url, $body = null)
{
if ($method === HttpRequestMethod::POST()) {
// handle POST requests...
} else {
// handle other requests...
}
}
```
## Java-style enumerations
[Java's enum types] have slightly more functionality than C++ enumerated types.
They can have additional properties and/or methods, and are really just a
specialised kind of class where there are a fixed set of instances.
This is sometimes called the [Multiton] pattern, and in fact, all enumerations
in this implementation are Multitons. The `AbstractEnumeration` class simply
defines its members based upon class constants.
Here is an example borrowed from the Java documentation for its enum types. The
following multiton describes all of the planets in our solar system, including
their masses and radii:
```php
use Ifornew\Enum\AbstractMultiton;
final class Planet extends AbstractMultiton
{
/**
* Universal gravitational constant.
*
* @var float
*/
const G = 6.67300E-11;
/**
* @return float
*/
public function surfaceGravity()
{
return self::G * $this->mass / ($this->radius * $this->radius);
}
/**
* @param float $otherMass
*
* @return float
*/
public function surfaceWeight($otherMass)
{
return $otherMass * $this->surfaceGravity();
}
protected static function initializeMembers()
{
new static('MERCURY', 3.302e23, 2.4397e6);
new static('VENUS', 4.869e24, 6.0518e6);
new static('EARTH', 5.9742e24, 6.37814e6);
new static('MARS', 6.4191e23, 3.3972e6);
new static('JUPITER', 1.8987e27, 7.1492e7);
new static('SATURN', 5.6851e26, 6.0268e7);
new static('URANUS', 8.6849e25, 2.5559e7);
new static('NEPTUNE', 1.0244e26, 2.4764e7);
// new static('PLUTO', 1.31e22, 1.180e6);
}
/**
* @param string $key
* @param float $mass
* @param float $radius
*/
protected function __construct($key, $mass, $radius)
{
parent::__construct($key);
$this->mass = $mass;
$this->radius = $radius;
}
private $mass;
private $radius;
}
```
The above class can be used to take a known weight on earth (in any unit) and
calculate the weight on all of the planets (in the same unit):
```php
$earthWeight = 175;
$mass = $earthWeight / Planet::EARTH()->surfaceGravity();
foreach (Planet::members() as $planet) {
echo sprintf(
'Your weight on %s is %f' . PHP_EOL,
$planet,
$planet->surfaceWeight($mass)
);
}
```
If the above script is executed, it will produce something like the following
output:
```
Your weight on MERCURY is 66.107480
Your weight on VENUS is 158.422560
Your weight on EARTH is 175.000000
Your weight on MARS is 66.279359
Your weight on JUPITER is 442.677903
Your weight on SATURN is 186.513785
Your weight on URANUS is 158.424919
Your weight on NEPTUNE is 199.055584
```
[java's enum types]: https://en.wikipedia.org/wiki/Enumerated_type#Java
[multiton]: http://en.wikipedia.org/wiki/Multiton_pattern
## Enums and class inheritance
When an enumeration is defined, the intent is usually to define a set of valid
values that should not change, at least within the lifetime of a program's
execution.
Since PHP has no in-built support for enumerations, this library implements them
as regular PHP classes. Classes, however, allow for much more extensibility than
is desirable in a true enumeration.
For example, a naive enumeration implementation might allow a developer to
extend the `HttpRequestMethod` class from the examples above (assuming the
`final` keyword is removed):
```php
class CustomHttpMethod extends HttpRequestMethod
{
const PATCH = 'PATCH';
}
```
The problem with this scenario is that all the code written to expect only the
HTTP methods defined in `HttpRequestMethod` is now compromised. Anybody can
extend `HttpRequestMethod` to add custom values, essentially voiding the reason
for defining `HttpRequestMethod` in the first place.
This library provides built-in protection from these kinds of circumstances.
Attempting to define an enumeration that extends another enumeration will result
in an exception being thrown, unless the 'base' enumeration is abstract.
### Abstract enumerations
Assuming that there really is a need to extend `HttpRequestMethod`, the way to
go about it is to define an abstract base class, then extend this class to
create the desired concrete enumerations:
```php
use Ifornew\Enum\AbstractEnumeration;
abstract class AbstractHttpRequestMethod extends AbstractEnumeration
{
const OPTIONS = 'OPTIONS';
const GET = 'GET';
const HEAD = 'HEAD';
const POST = 'POST';
const PUT = 'PUT';
const DELETE = 'DELETE';
const TRACE = 'TRACE';
const CONNECT = 'CONNECT';
}
final class HttpRequestMethod extends AbstractHttpRequestMethod {}
final class CustomHttpMethod extends AbstractHttpRequestMethod
{
const PATCH = 'PATCH';
}
```
In this way, when a developer uses a type hint for `HttpRequestMethod`, there is
no chance they will ever receive the 'PATCH' method:
```php
function handleHttpRequest(HttpRequestMethod $method, $url, $body = null)
{
// only handles normal requests...
}
function handleCustomHttpRequest(
CustomHttpRequestMethod $method,
$url,
$body = null
) {
// handles normal requests, and custom requests...
}
```

@ -0,0 +1,42 @@
{
"name": "ifornew/enum",
"description": "An enumeration implementation for PHP.",
"keywords": [
"enum",
"enumeration",
"set",
"class",
"multiton",
"type"
],
"homepage": "https://git.ifornew.com/ifornew-enum.git",
"license": "MIT",
"authors": [
{
"name": "I For New",
"email": "i@ifornew.com",
"homepage": "http://www.ifornew.com/"
}
],
"require": {
"php": ">=5.3",
"illuminate/support": "^5.5"
},
"require-dev": {
"icecave/archer": "dev-develop",
"phpunit/phpunit": "^4",
"sami/sami": "^3"
},
"autoload": {
"psr-4": {
"Ifornew\\Enum\\": "src"
}
},
"extra": {
"laravel": {
"providers": [
"Ifornew\\Enum\\EnumServiceProvider"
]
}
}
}

1937
composer.lock generated

File diff suppressed because it is too large Load Diff

@ -0,0 +1,39 @@
<?php
namespace Ifornew\Enum;
use ReflectionClass;
/**
* Abstract base class for C++ style enumerations.
*
* @api
*/
abstract class AbstractEnumeration extends AbstractValueMultiton implements
EnumerationInterface, \JsonSerializable
{
/**
* Initializes the members of this enumeration based upon its class
* constants.
*
* Each constant becomes a member with a string key equal to the constant's
* name, and a value equal to that of the constant's value.
*/
final protected static function initializeMembers()
{
$reflector = new ReflectionClass(get_called_class());
foreach ($reflector->getConstants() as $key => $value) {
new static($key, $value, static::getDescription($value));
}
}
final public function jsonSerialize()
{
return [
'key' => $this->key(),
'value' => $this->value(),
'description' => $this->description()
];
}
}

@ -0,0 +1,490 @@
<?php
namespace Ifornew\Enum;
use Ifornew\Enum\Exception\ExtendsConcreteException;
use Ifornew\Enum\Exception\UndefinedMemberException;
use Ifornew\Enum\Exception\UndefinedMemberExceptionInterface;
use Exception as NativeException;
use ReflectionObject;
/**
* Abstract base class for Java-style enumerations.
*
* @api
*/
abstract class AbstractMultiton implements MultitonInterface
{
/**
* Returns a single member by string key.
*
* @api
*
* @param string $key The string key associated with the member.
* @param boolean|null $isCaseSensitive True if the search should be case sensitive.
*
* @return static The member associated with the given string key.
* @throws UndefinedMemberExceptionInterface If no associated member is found.
*/
final public static function memberByKey($key, $isCaseSensitive = null)
{
return static::memberBy('key', $key, $isCaseSensitive);
}
/**
* Returns a single member by string key. Additionally returns a default if
* no associated member is found.
*
* @api
*
* @param string $key The string key associated with the member.
* @param MultitonInterface|null $default The default value to return.
* @param boolean|null $isCaseSensitive True if the search should be case sensitive.
*
* @return static The member associated with the given string key, or the default value.
*/
final public static function memberByKeyWithDefault(
$key,
MultitonInterface $default = null,
$isCaseSensitive = null
) {
return static::memberByWithDefault(
'key',
$key,
$default,
$isCaseSensitive
);
}
/**
* Returns a single member by string key. Additionally returns null if the
* supplied key is null.
*
* @api
*
* @param string|null $key The string key associated with the member, or null.
* @param boolean|null $isCaseSensitive True if the search should be case sensitive.
*
* @return static|null The member associated with the given string key, or null if the supplied key is null.
* @throws UndefinedMemberExceptionInterface If no associated member is found.
*/
final public static function memberOrNullByKey(
$key,
$isCaseSensitive = null
) {
return static::memberOrNullBy('key', $key, $isCaseSensitive);
}
/**
* Returns a single member by comparison with the result of an accessor
* method.
*
* @api
*
* @param string $property The name of the property (accessor method) to match.
* @param mixed $value The value to match.
* @param boolean|null $isCaseSensitive True if the search should be case sensitive.
*
* @return static The first member for which $member->{$property}() === $value.
* @throws UndefinedMemberExceptionInterface If no associated member is found.
*/
final public static function memberBy(
$property,
$value,
$isCaseSensitive = null
) {
$member = static::memberByWithDefault(
$property,
$value,
null,
$isCaseSensitive
);
if (null === $member) {
throw static::createUndefinedMemberException(
get_called_class(),
$property,
$value
);
}
return $member;
}
/**
* Returns a single member by comparison with the result of an accessor
* method. Additionally returns a default if no associated member is found.
*
* @api
*
* @param string $property The name of the property (accessor method) to match.
* @param mixed $value The value to match.
* @param MultitonInterface|null $default The default value to return.
* @param boolean|null $isCaseSensitive True if the search should be case sensitive.
*
* @return static|null The first member for which $member->{$property}() === $value, or the default value.
*/
final public static function memberByWithDefault(
$property,
$value,
MultitonInterface $default = null,
$isCaseSensitive = null
) {
if (null === $isCaseSensitive) {
$isCaseSensitive = true;
}
if (!$isCaseSensitive && is_scalar($value)) {
$value = strtoupper(strval($value));
}
return static::memberByPredicateWithDefault(
function (MultitonInterface $member) use (
$property,
$value,
$isCaseSensitive
) {
$memberValue = $member->{$property}();
if (!$isCaseSensitive && is_scalar($memberValue)) {
$memberValue = strtoupper(strval($memberValue));
}
return $memberValue === $value;
},
$default
);
}
/**
* Returns a single member by comparison with the result of an accessor
* method. Additionally returns null if the supplied value is null.
*
* @api
*
* @param string $property The name of the property (accessor method) to match.
* @param mixed $value The value to match, or null.
* @param boolean|null $isCaseSensitive True if the search should be case sensitive.
*
* @return static|null The first member for which $member->{$property}() === $value, or null if the supplied value is null.
* @throws UndefinedMemberExceptionInterface If no associated member is found.
*/
final public static function memberOrNullBy(
$property,
$value,
$isCaseSensitive = null
) {
$member = static::memberByWithDefault(
$property,
$value,
null,
$isCaseSensitive
);
if (null === $member) {
if (null === $value) {
return null;
}
throw static::createUndefinedMemberException(
get_called_class(),
$property,
$value
);
}
return $member;
}
/**
* Returns a single member by predicate callback.
*
* @api
*
* @param callable $predicate The predicate applies to the member to find a match.
*
* @return static The first member for which $predicate($member) evaluates to boolean true.
* @throws UndefinedMemberExceptionInterface If no associated member is found.
*/
final public static function memberByPredicate($predicate)
{
$member = static::memberByPredicateWithDefault($predicate);
if (null === $member) {
throw static::createUndefinedMemberException(
get_called_class(),
'<callback>',
'<callback>'
);
}
return $member;
}
/**
* Returns a single member by predicate callback. Additionally returns a
* default if no associated member is found.
*
* @api
*
* @param callable $predicate The predicate applied to the member to find a match.
* @param MultitonInterface|null $default The default value to return.
*
* @return static The first member for which $predicate($member) evaluates to boolean true, or the default value.
*/
final public static function memberByPredicateWithDefault(
$predicate,
MultitonInterface $default = null
) {
foreach (static::members() as $member) {
if ($predicate($member)) {
return $member;
}
}
return $default;
}
/**
* Returns an array of all members in this multiton.
*
* @api
*
* @return array<string,static> All members.
*/
final public static function members()
{
$class = get_called_class();
if (!array_key_exists($class, self::$members)) {
self::$members[$class] = array();
static::initializeMembers();
}
return self::$members[$class];
}
/**
* Returns a set of members by comparison with the result of an accessor
* method.
*
* @api
*
* @param string $property The name of the property (accessor method) to match.
* @param mixed $value The value to match.
* @param boolean|null $isCaseSensitive True if the search should be case sensitive.
*
* @return array<string,static> All members for which $member->{$property}() === $value.
*/
final public static function membersBy(
$property,
$value,
$isCaseSensitive = null
) {
if (null === $isCaseSensitive) {
$isCaseSensitive = true;
}
if (!$isCaseSensitive && is_scalar($value)) {
$value = strtoupper(strval($value));
}
return static::membersByPredicate(
function (MultitonInterface $member) use (
$property,
$value,
$isCaseSensitive
) {
$memberValue = $member->{$property}();
if (!$isCaseSensitive && is_scalar($memberValue)) {
$memberValue = strtoupper(strval($memberValue));
}
return $memberValue === $value;
}
);
}
/**
* Returns a set of members by predicate callback.
*
* @api
*
* @param callable $predicate The predicate applied to the members to find matches.
*
* @return array<string,static> All members for which $predicate($member) evaluates to boolean true.
*/
final public static function membersByPredicate($predicate)
{
$members = array();
foreach (static::members() as $key => $member) {
if ($predicate($member)) {
$members[$key] = $member;
}
}
return $members;
}
/**
* Maps static method calls to members.
*
* @api
*
* @param string $key The string key associated with the member.
* @param array $arguments Ignored.
*
* @return static The member associated with the given string key.
* @throws UndefinedMemberExceptionInterface If no associated member is found.
*/
final public static function __callStatic($key, array $arguments)
{
return static::memberByKey($key);
}
/**
* Returns the string key of this member.
*
* @api
*
* @return string The associated string key of this member.
*/
final public function key()
{
return $this->key;
}
/**
* Check if this member is in the specified list of members.
*
* @api
*
* @param MultitonInterface $a The first member to check.
* @param MultitonInterface $b The second member to check.
* @param MultitonInterface $c,... Additional members to check.
*
* @return boolean True if this member is in the specified list of members.
*/
final public function anyOf(MultitonInterface $a, MultitonInterface $b)
{
return $this->anyOfArray(func_get_args());
}
/**
* Check if this member is in the specified list of members.
*
* @api
*
* @param array<MultitonInterface> $values An array of members to search.
*
* @return boolean True if this member is in the specified list of members.
*/
final public function anyOfArray(array $values)
{
return in_array($this, $values, true);
}
/**
* Returns a string representation of this member.
*
* @api
*
* Unless overridden, this is simply the string key.
*
* @return string The string representation.
*/
public function __toString()
{
return $this->key();
}
/**
* Override this method in child classes to implement one-time
* initialization for a multiton class.
*
* This method is called the first time the members of a multiton are
* accessed. It is called via late static binding, and hence can be
* overridden in child classes.
*
* @api
*/
protected static function initializeMembers()
{
}
/**
* Override this method in child classes to implement custom undefined
* member exceptions for a multiton class.
*
* @api
*
* @param string $className The name of the class from which the member was requested.
* @param string $property The name of the property used to search for the member.
* @param mixed $value The value of the property used to search for the member.
* @param NativeException|null $cause The cause, if available.
*
* @return UndefinedMemberExceptionInterface The newly created exception.
*/
protected static function createUndefinedMemberException(
$className,
$property,
$value,
NativeException $previous = null
) {
return new UndefinedMemberException(
$className,
$property,
$value,
$previous
);
}
/**
* Construct and register a new multiton member.
*
* @api
*
* If you override the constructor in a child class, you MUST call the parent
* constructor. Calling this constructor is the only way to set the string
* key for this member, and to ensure that the member is correctly
* registered.
*
* @param string $key The string key to associate with this member.
*
* @throws ExtendsConcreteException If the constructed member has an invalid inheritance hierarchy.
*/
protected function __construct($key)
{
$this->key = $key;
self::registerMember($this);
}
/**
* Registers the supplied member.
*
* Do not attempt to call this method directly. Instead, ensure that
* AbstractMultiton::__construct() is called from any child classes, as this
* will also handle registration of the member.
*
* @param MultitonInterface $member The member to register.
* @throws ExtendsConcreteException If the supplied member has an invalid inheritance hierarchy.
*/
private static function registerMember(MultitonInterface $member)
{
$reflector = new ReflectionObject($member);
$parentClass = $reflector->getParentClass();
if (!$parentClass->isAbstract()) {
throw new ExtendsConcreteException(
get_class($member),
$parentClass->getName()
);
}
self::$members[get_called_class()][$member->key()] = $member;
}
private static $members = array();
private $key;
}

@ -0,0 +1,158 @@
<?php
namespace Ifornew\Enum;
use Illuminate\Support\Collection;
use Ifornew\Enum\Exception\ExtendsConcreteException;
use Ifornew\Enum\Exception\UndefinedMemberExceptionInterface;
/**
* Abstract base class for Java-style enumerations with a value.
*
* @api
*/
abstract class AbstractValueMultiton extends AbstractMultiton implements
ValueMultitonInterface
{
/**
* Returns a single member by value.
*
* @api
*
* @param mixed $value The value associated with the member.
* @param boolean|null $isCaseSensitive True if the search should be case sensitive.
*
* @return static The first member with the supplied value.
* @throws UndefinedMemberExceptionInterface If no associated member is found.
*/
final public static function memberByValue($value, $isCaseSensitive = null)
{
return static::memberBy('value', $value, $isCaseSensitive);
}
/**
* Returns a single member by value. Additionally returns a default if no
* associated member is found.
*
* @api
*
* @param mixed $value The value associated with the member.
* @param ValueMultitonInterface|null $default The default value to return.
* @param boolean|null $isCaseSensitive True if the search should be case sensitive.
*
* @return static The first member with the supplied value, or the default value.
*/
final public static function memberByValueWithDefault(
$value,
ValueMultitonInterface $default = null,
$isCaseSensitive = null
)
{
return static::memberByWithDefault(
'value',
$value,
$default,
$isCaseSensitive
);
}
/**
* Returns a single member by value. Additionally returns null if the
* supplied value is null.
*
* @api
*
* @param mixed|null $value The value associated with the member, or null.
* @param boolean|null $isCaseSensitive True if the search should be case sensitive.
*
* @return static|null The first member with the supplied value, or null if the supplied value is null.
* @throws UndefinedMemberExceptionInterface If no associated member is found.
*/
final public static function memberOrNullByValue(
$value,
$isCaseSensitive = null
)
{
return static::memberOrNullBy('value', $value, $isCaseSensitive);
}
/**
* Returns a set of members matching the supplied value.
*
* @api
*
* @param mixed $value The value associated with the members.
* @param boolean|null $isCaseSensitive True if the search should be case sensitive.
*
* @return array<string,static> All members with the supplied value.
*/
final public static function membersByValue($value, $isCaseSensitive = null)
{
return static::membersBy('value', $value, $isCaseSensitive);
}
/**
* Returns the value of this member.
*
* @api
* @return mixed The value of this member.
*/
final public function value()
{
return $this->value;
}
final public function description()
{
return $this->description;
}
/**
* Override this method in child classes to add enum description for a multiton class.
* This method is called the first time the members of a multiton are
* accessed. It is called via late static binding, and hence can be
* overridden in child classes.
*
* @api
*/
protected static function getDescription($value)
{
}
/**
* Get the select collections og the enum
*
* @return \Illuminate\Support\Collection
*/
final public static function getCollection()
{
$collection = new Collection();
foreach (self::members() as $member) {
$collection->put($member->value, $member->description);
}
return $collection;
}
/**
* Construct and register a new value multiton member.
*
* @api
*
* @param string $key The string key to associate with this member.
* @param mixed $value The value of this member.
*
* @throws ExtendsConcreteException If the constructed member has an invalid inheritance hierarchy.
*/
protected function __construct($key, $value, $description)
{
parent::__construct($key);
$this->value = $value;
$this->description = $description;
}
private $value;
private $description;
}

@ -0,0 +1,51 @@
<?php
namespace Ifornew\Enum\Commands;
use Illuminate\Console\GeneratorCommand;
class MakeEnumCommand extends GeneratorCommand
{
/**
* The console command name.
*
* @var string
*/
protected $name = 'make:enum';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Create a new enum class';
/**
* The type of class being generated.
*
* @var string
*/
protected $type = 'Enum';
/**
* Get the stub file for the generator.
*
* @return string
*/
protected function getStub()
{
return __DIR__.'/../Stubs/Enum.stub';
}
/**
* Get the default namespace for the class.
*
* @param string $rootNamespace
*
* @return string
*/
protected function getDefaultNamespace($rootNamespace)
{
return $rootNamespace.'\Enums';
}
}

@ -0,0 +1,28 @@
<?php
namespace Ifornew\Enum;
use Illuminate\Support\ServiceProvider;
use Ifornew\Enum\Commands\MakeEnumCommand;
class EnumServiceProvider extends ServiceProvider
{
/**
* Perform post-registration booting of services.
*/
public function boot()
{
if ($this->app->runningInConsole()) {
$this->commands([
MakeEnumCommand::class,
]);
}
}
/**
* Register any package services.
*/
public function register()
{
}
}

@ -0,0 +1,11 @@
<?php
namespace Ifornew\Enum;
/**
* The interface implemented by C++ style enumeration instances.
*
* @api
*/
interface EnumerationInterface extends ValueMultitonInterface
{
}

@ -0,0 +1,68 @@
<?php
namespace Ifornew\Enum\Exception;
use Exception;
/**
* An abstract base class for implementing undefined member exceptions.
*/
abstract class AbstractUndefinedMemberException extends Exception implements
UndefinedMemberExceptionInterface
{
/**
* Construct a new undefined member exception.
*
* @param string $message The exception message.
* @param string $className The name of the class from which the member was requested.
* @param string $property The name of the property used to search for the member.
* @param mixed $value The value of the property used to search for the member.
* @param Exception|null $cause The cause, if available.
*/
public function __construct(
$message,
$className,
$property,
$value,
Exception $cause = null
) {
$this->className = $className;
$this->property = $property;
$this->value = $value;
parent::__construct($message, 0, $cause);
}
/**
* Get the class name.
*
* @return string The class name.
*/
public function className()
{
return $this->className;
}
/**
* Get the property name.
*
* @return string The property name.
*/
public function property()
{
return $this->property;
}
/**
* Get the value of the property used to search for the member.
*
* @return mixed The value.
*/
public function value()
{
return $this->value;
}
private $className;
private $property;
private $value;
}

@ -0,0 +1,64 @@
<?php
namespace Ifornew\Enum\Exception;
use Exception;
/**
* The supplied member extends an already concrete base class.
*
* This exception exists to prevent otherwise valid inheritance structures
* that are not valid in the context of enumerations.
*
* @api
*/
final class ExtendsConcreteException extends Exception
{
/**
* Construct a new extends concrete exception.
*
* @param string $className The class of the supplied member.
* @param string $parentClass The concrete parent class name.
* @param Exception|null $cause The cause, if available.
*/
public function __construct(
$className,
$parentClass,
Exception $cause = null
) {
$this->className = $className;
$this->parentClass = $parentClass;
parent::__construct(
sprintf(
"Class '%s' cannot extend concrete class '%s'.",
$this->className(),
$this->parentClass()
),
0,
$cause
);
}
/**
* Get the class name of the supplied member.
*
* @return string The class name.
*/
public function className()
{
return $this->className;
}
/**
* Get the parent class name.
*
* @return string The parent class name.
*/
public function parentClass()
{
return $this->parentClass;
}
private $className;
private $parentClass;
}

@ -0,0 +1,38 @@
<?php
namespace Ifornew\Enum\Exception;
use Exception;
/**
* The requested member was not found.
*/
final class UndefinedMemberException extends AbstractUndefinedMemberException
{
/**
* Construct a new undefined member exception.
*
* @param string $className The name of the class from which the member was requested.
* @param string $property The name of the property used to search for the member.
* @param mixed $value The value of the property used to search for the member.
* @param Exception|null $cause The cause, if available.
*/
public function __construct(
$className,
$property,
$value,
Exception $cause = null
) {
parent::__construct(
sprintf(
'No member with %s equal to %s defined in class %s.',
$property,
var_export($value, true),
var_export($className, true)
),
$className,
$property,
$value,
$cause
);
}
}

@ -0,0 +1,38 @@
<?php
namespace Ifornew\Enum\Exception;
/**
* The interface implemented by exceptions that are thrown when an undefined
* member is requested.
*
* @api
*/
interface UndefinedMemberExceptionInterface
{
/**
* Get the class name.
*
* @api
*
* @return string The class name.
*/
public function className();
/**
* Get the property name.
*
* @api
*
* @return string The property name.
*/
public function property();
/**
* Get the value of the property used to search for the member.
*
* @api
*
* @return mixed The value.
*/
public function value();
}

@ -0,0 +1,54 @@
<?php
namespace Ifornew\Enum;
/**
* The interface implemented by Java-style enumeration instances.
*
* @api
*/
interface MultitonInterface
{
/**
* Returns the string key of this member.
*
* @api
*
* @return string The associated string key of this member.
*/
public function key();
/**
* Check if this member is in the specified list of members.
*
* @api
*
* @param MultitonInterface $a The first member to check.
* @param MultitonInterface $b The second member to check.
* @param MultitonInterface $c,... Additional members to check.
*
* @return boolean True if this member is in the specified list of members.
*/
public function anyOf(MultitonInterface $a, MultitonInterface $b);
/**
* Check if this member is in the specified list of members.
*
* @api
*
* @param array<MultitonInterface> $values An array of members to search.
*
* @return boolean True if this member is in the specified list of members.
*/
public function anyOfArray(array $values);
/**
* Returns a string representation of this member.
*
* @api
*
* Unless overridden, this is simply the string key.
*
* @return string
*/
public function __toString();
}

@ -0,0 +1,64 @@
<?php
namespace Ifornew\Enum\Rules;
use Illuminate\Contracts\Validation\Rule;
/**
* Rule:EnumKey
* @package Ifornew\Enum\Rules
*/
class EnumKey implements Rule
{
/**
* @var array $validValues
*/
private $validValues;
/**
* 大小写敏感
* @var boolean $isCaseSensitive
*/
private $isCaseSensitive;
/**
* EnumValue constructor.
* @param string $enum
* @param boolean $isCaseSensitive
* @param array|\Illuminate\Support\Collection|null $excepts
*/
public function __construct(string $enum, $excepts = null, bool $isCaseSensitive = false)
{
$this->isCaseSensitive=$isCaseSensitive;
$this->validValues = $enum::members();
if ($excepts != null) {
$this->validValues = array_except($this->validValues, $excepts);
}
}
/**
* Determine if the validation rule passes.
*
* @param string $attribute
* @param mixed $value
*
* @return bool
*/
public function passes($attribute, $value)
{
if (!$this->isCaseSensitive) {
$value = strtoupper($value);
}
return array_has($this->validValues, $value);
}
/**
* Get the validation error message.
*
* @return string
*/
public function message()
{
return trans('validation.enum_key');
}
}

@ -0,0 +1,53 @@
<?php
namespace Ifornew\Enum\Rules;
use Illuminate\Contracts\Validation\Rule;
/**
* Rule:EnumValue
* @package Ifornew\Enum\Rules
*/
class EnumValue implements Rule
{
/**
* @var \Illuminate\Support\Collection $validValues
*/
private $validValues;
/**
* EnumValue constructor.
* @param string $enum
* @param array|\Illuminate\Support\Collection|null $excepts
*/
public function __construct(string $enum,$excepts=null)
{
$this->validValues = $enum::getCollection();
if($excepts!=null){
$this->validValues=$this->validValues->except($excepts);
}
}
/**
* Determine if the validation rule passes.
*
* @param string $attribute
* @param mixed $value
*
* @return bool
*/
public function passes($attribute, $value)
{
return $this->validValues->has($value);
}
/**
* Get the validation error message.
*
* @return string
*/
public function message()
{
return trans('validation.enum_value');
}
}

@ -0,0 +1,42 @@
<?php
namespace DummyNamespace;
use Ifornew\Enum\AbstractEnumeration as Enum;
/**
* Enum: DummyClass
* @method static static OPTION_ONE
* @method static static OPTION_TWO
* @method static static OPTION_THREE
*
* @package DummyNamespace
*/
final class DummyClass extends Enum
{
const OPTION_ONE = 0;
const OPTION_TWO = 1;
const OPTION_THREE = 2;
/**
* Get the description for an enum value
*
* @param $value
*
* @return string
*/
final public static function getDescription($value)
{
switch ($value){
case self::OPTION_ONE:
return 'OptionOne';
case self::OPTION_TWO:
return 'OptionTwo';
case self::OPTION_THREE:
return 'OptionThree';
default:
return null;
}
}
}

@ -0,0 +1,19 @@
<?php
namespace Ifornew\Enum;
/**
* The interface implemented by Java-style enumeration instances with a value.
*
* @api
*/
interface ValueMultitonInterface extends MultitonInterface
{
/**
* Returns the value of this member.
*
* @api
*
* @return mixed The value of this member.
*/
public function value();
}

@ -0,0 +1,18 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Validation Language Lines
|--------------------------------------------------------------------------
|
| The following language lines contain the default error messages used by
| the validator class. Some of these rules have multiple versions such
| as the size rules. Feel free to tweak each of these messages here.
|
*/
'enum_key' => ':attribute is invalid enum key.',
'enum_value' => ':attribute is invalid enum value.',
];

@ -0,0 +1,18 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Validation Language Lines
|--------------------------------------------------------------------------
|
| The following language lines contain the default error messages used by
| the validator class. Some of these rules have multiple versions such
| as the size rules. Feel free to tweak each of these messages here.
|
*/
'enum_key' => ':attribute 不是合法的允许键。',
'enum_value' => ':attribute 不是合法的允许值。',
];
Loading…
Cancel
Save