Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
D
doctrine-dbal
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Tomáš Trávníček
doctrine-dbal
Commits
11b67bbd
Unverified
Commit
11b67bbd
authored
Apr 13, 2019
by
Sergei Morozov
Committed by
GitHub
Apr 13, 2019
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #3354 from Majkl578/type-registry
Extract type factory and registry from Type into TypeRegistry
parents
773275d1
089f32e6
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
398 additions
and
73 deletions
+398
-73
DBALException.php
lib/Doctrine/DBAL/DBALException.php
+14
-0
Type.php
lib/Doctrine/DBAL/Types/Type.php
+78
-73
TypeRegistry.php
lib/Doctrine/DBAL/Types/TypeRegistry.php
+118
-0
TypeRegistryTest.php
tests/Doctrine/Tests/DBAL/Types/TypeRegistryTest.php
+154
-0
TypeTest.php
tests/Doctrine/Tests/DBAL/Types/TypeTest.php
+34
-0
No files found.
lib/Doctrine/DBAL/DBALException.php
View file @
11b67bbd
...
@@ -6,6 +6,7 @@ use Doctrine\DBAL\Driver\DriverException as DriverExceptionInterface;
...
@@ -6,6 +6,7 @@ use Doctrine\DBAL\Driver\DriverException as DriverExceptionInterface;
use
Doctrine\DBAL\Driver\ExceptionConverterDriver
;
use
Doctrine\DBAL\Driver\ExceptionConverterDriver
;
use
Doctrine\DBAL\Exception\DriverException
;
use
Doctrine\DBAL\Exception\DriverException
;
use
Doctrine\DBAL\Platforms\AbstractPlatform
;
use
Doctrine\DBAL\Platforms\AbstractPlatform
;
use
Doctrine\DBAL\Types\Type
;
use
Exception
;
use
Exception
;
use
Throwable
;
use
Throwable
;
use
function
array_map
;
use
function
array_map
;
...
@@ -18,6 +19,7 @@ use function is_resource;
...
@@ -18,6 +19,7 @@ use function is_resource;
use
function
is_string
;
use
function
is_string
;
use
function
json_encode
;
use
function
json_encode
;
use
function
preg_replace
;
use
function
preg_replace
;
use
function
spl_object_hash
;
use
function
sprintf
;
use
function
sprintf
;
class
DBALException
extends
Exception
class
DBALException
extends
Exception
...
@@ -277,4 +279,16 @@ class DBALException extends Exception
...
@@ -277,4 +279,16 @@ class DBALException extends Exception
{
{
return
new
self
(
'Type to be overwritten '
.
$name
.
' does not exist.'
);
return
new
self
(
'Type to be overwritten '
.
$name
.
' does not exist.'
);
}
}
public
static
function
typeNotRegistered
(
Type
$type
)
:
self
{
return
new
self
(
sprintf
(
'Type of the class %s@%s is not registered.'
,
get_class
(
$type
),
spl_object_hash
(
$type
)));
}
public
static
function
typeAlreadyRegistered
(
Type
$type
)
:
self
{
return
new
self
(
sprintf
(
'Type of the class %s@%s is already registered.'
,
get_class
(
$type
),
spl_object_hash
(
$type
))
);
}
}
}
lib/Doctrine/DBAL/Types/Type.php
View file @
11b67bbd
...
@@ -5,6 +5,8 @@ namespace Doctrine\DBAL\Types;
...
@@ -5,6 +5,8 @@ namespace Doctrine\DBAL\Types;
use
Doctrine\DBAL\DBALException
;
use
Doctrine\DBAL\DBALException
;
use
Doctrine\DBAL\ParameterType
;
use
Doctrine\DBAL\ParameterType
;
use
Doctrine\DBAL\Platforms\AbstractPlatform
;
use
Doctrine\DBAL\Platforms\AbstractPlatform
;
use
function
array_map
;
use
function
get_class
;
use
function
str_replace
;
use
function
str_replace
;
use
function
strrpos
;
use
function
strrpos
;
use
function
substr
;
use
function
substr
;
...
@@ -16,76 +18,70 @@ use function substr;
...
@@ -16,76 +18,70 @@ use function substr;
*/
*/
abstract
class
Type
abstract
class
Type
{
{
public
const
TARRAY
=
'array'
;
public
const
SIMPLE_ARRAY
=
'simple_array'
;
public
const
JSON_ARRAY
=
'json_array'
;
public
const
JSON
=
'json'
;
public
const
BIGINT
=
'bigint'
;
public
const
BIGINT
=
'bigint'
;
public
const
BINARY
=
'binary'
;
public
const
BLOB
=
'blob'
;
public
const
BOOLEAN
=
'boolean'
;
public
const
BOOLEAN
=
'boolean'
;
public
const
DATE
=
'date'
;
public
const
DATE_IMMUTABLE
=
'date_immutable'
;
public
const
DATEINTERVAL
=
'dateinterval'
;
public
const
DATETIME
=
'datetime'
;
public
const
DATETIME
=
'datetime'
;
public
const
DATETIME_IMMUTABLE
=
'datetime_immutable'
;
public
const
DATETIME_IMMUTABLE
=
'datetime_immutable'
;
public
const
DATETIMETZ
=
'datetimetz'
;
public
const
DATETIMETZ
=
'datetimetz'
;
public
const
DATETIMETZ_IMMUTABLE
=
'datetimetz_immutable'
;
public
const
DATETIMETZ_IMMUTABLE
=
'datetimetz_immutable'
;
public
const
DATE
=
'date'
;
public
const
DATE_IMMUTABLE
=
'date_immutable'
;
public
const
TIME
=
'time'
;
public
const
TIME_IMMUTABLE
=
'time_immutable'
;
public
const
DECIMAL
=
'decimal'
;
public
const
DECIMAL
=
'decimal'
;
public
const
FLOAT
=
'float'
;
public
const
GUID
=
'guid'
;
public
const
INTEGER
=
'integer'
;
public
const
INTEGER
=
'integer'
;
public
const
JSON
=
'json'
;
public
const
JSON_ARRAY
=
'json_array'
;
public
const
OBJECT
=
'object'
;
public
const
OBJECT
=
'object'
;
public
const
SIMPLE_ARRAY
=
'simple_array'
;
public
const
SMALLINT
=
'smallint'
;
public
const
SMALLINT
=
'smallint'
;
public
const
STRING
=
'string'
;
public
const
STRING
=
'string'
;
public
const
TARRAY
=
'array'
;
public
const
TEXT
=
'text'
;
public
const
TEXT
=
'text'
;
public
const
BINARY
=
'binary'
;
public
const
TIME
=
'time'
;
public
const
BLOB
=
'blob'
;
public
const
TIME_IMMUTABLE
=
'time_immutable'
;
public
const
FLOAT
=
'float'
;
public
const
GUID
=
'guid'
;
public
const
DATEINTERVAL
=
'dateinterval'
;
/**
* Map of already instantiated type objects. One instance per type (flyweight).
*
* @var self[]
*/
private
static
$_typeObjects
=
[];
/**
/**
* The map of supported doctrine mapping types.
* The map of supported doctrine mapping types.
*
* @var string[]
*/
*/
private
static
$_typesMap
=
[
private
const
BUILTIN_TYPES_MAP
=
[
self
::
TARRAY
=>
ArrayType
::
class
,
self
::
BIGINT
=>
BigIntType
::
class
,
self
::
SIMPLE_ARRAY
=>
SimpleArrayType
::
class
,
self
::
BINARY
=>
BinaryType
::
class
,
self
::
JSON_ARRAY
=>
JsonArrayType
::
class
,
self
::
BLOB
=>
BlobType
::
class
,
self
::
JSON
=>
JsonType
::
class
,
self
::
BOOLEAN
=>
BooleanType
::
class
,
self
::
OBJECT
=>
ObjectType
::
class
,
self
::
DATE
=>
DateType
::
class
,
self
::
BOOLEAN
=>
BooleanType
::
class
,
self
::
DATE_IMMUTABLE
=>
DateImmutableType
::
class
,
self
::
INTEGER
=>
IntegerType
::
class
,
self
::
DATEINTERVAL
=>
DateIntervalType
::
class
,
self
::
SMALLINT
=>
SmallIntType
::
class
,
self
::
DATETIME
=>
DateTimeType
::
class
,
self
::
BIGINT
=>
BigIntType
::
class
,
self
::
DATETIME_IMMUTABLE
=>
DateTimeImmutableType
::
class
,
self
::
STRING
=>
StringType
::
class
,
self
::
DATETIMETZ
=>
DateTimeTzType
::
class
,
self
::
TEXT
=>
TextType
::
class
,
self
::
DATETIME
=>
DateTimeType
::
class
,
self
::
DATETIME_IMMUTABLE
=>
DateTimeImmutableType
::
class
,
self
::
DATETIMETZ
=>
DateTimeTzType
::
class
,
self
::
DATETIMETZ_IMMUTABLE
=>
DateTimeTzImmutableType
::
class
,
self
::
DATETIMETZ_IMMUTABLE
=>
DateTimeTzImmutableType
::
class
,
self
::
DATE
=>
DateType
::
class
,
self
::
DECIMAL
=>
DecimalType
::
class
,
self
::
DATE_IMMUTABLE
=>
DateImmutableType
::
class
,
self
::
FLOAT
=>
FloatType
::
class
,
self
::
TIME
=>
TimeType
::
class
,
self
::
GUID
=>
GuidType
::
class
,
self
::
TIME_IMMUTABLE
=>
TimeImmutableType
::
class
,
self
::
INTEGER
=>
IntegerType
::
class
,
self
::
DECIMAL
=>
DecimalType
::
class
,
self
::
JSON
=>
JsonType
::
class
,
self
::
FLOAT
=>
FloatType
::
class
,
self
::
JSON_ARRAY
=>
JsonArrayType
::
class
,
self
::
BINARY
=>
BinaryType
::
class
,
self
::
OBJECT
=>
ObjectType
::
class
,
self
::
BLOB
=>
BlobType
::
class
,
self
::
SIMPLE_ARRAY
=>
SimpleArrayType
::
class
,
self
::
GUID
=>
GuidType
::
class
,
self
::
SMALLINT
=>
SmallIntType
::
class
,
self
::
DATEINTERVAL
=>
DateIntervalType
::
class
,
self
::
STRING
=>
StringType
::
class
,
self
::
TARRAY
=>
ArrayType
::
class
,
self
::
TEXT
=>
TextType
::
class
,
self
::
TIME
=>
TimeType
::
class
,
self
::
TIME_IMMUTABLE
=>
TimeImmutableType
::
class
,
];
];
/** @var TypeRegistry|null */
private
static
$typeRegistry
;
/**
/**
*
Prevents instantiation and forces use of the factory metho
d.
*
@internal Do not instantiate directly - use {@see Type::addType()} method instea
d.
*/
*/
final
p
rivate
function
__construct
()
final
p
ublic
function
__construct
()
{
{
}
}
...
@@ -148,6 +144,29 @@ abstract class Type
...
@@ -148,6 +144,29 @@ abstract class Type
*/
*/
abstract
public
function
getName
();
abstract
public
function
getName
();
/**
* @internal This method is only to be used within DBAL for forward compatibility purposes. Do not use directly.
*/
final
public
static
function
getTypeRegistry
()
:
TypeRegistry
{
if
(
self
::
$typeRegistry
===
null
)
{
self
::
$typeRegistry
=
self
::
createTypeRegistry
();
}
return
self
::
$typeRegistry
;
}
private
static
function
createTypeRegistry
()
:
TypeRegistry
{
$registry
=
new
TypeRegistry
();
foreach
(
self
::
BUILTIN_TYPES_MAP
as
$name
=>
$class
)
{
$registry
->
register
(
$name
,
new
$class
());
}
return
$registry
;
}
/**
/**
* Factory method to create type instances.
* Factory method to create type instances.
* Type instances are implemented as flyweights.
* Type instances are implemented as flyweights.
...
@@ -160,14 +179,7 @@ abstract class Type
...
@@ -160,14 +179,7 @@ abstract class Type
*/
*/
public
static
function
getType
(
$name
)
public
static
function
getType
(
$name
)
{
{
if
(
!
isset
(
self
::
$_typeObjects
[
$name
]))
{
return
self
::
getTypeRegistry
()
->
get
(
$name
);
if
(
!
isset
(
self
::
$_typesMap
[
$name
]))
{
throw
DBALException
::
unknownColumnType
(
$name
);
}
self
::
$_typeObjects
[
$name
]
=
new
self
::
$_typesMap
[
$name
]();
}
return
self
::
$_typeObjects
[
$name
];
}
}
/**
/**
...
@@ -182,11 +194,7 @@ abstract class Type
...
@@ -182,11 +194,7 @@ abstract class Type
*/
*/
public
static
function
addType
(
$name
,
$className
)
public
static
function
addType
(
$name
,
$className
)
{
{
if
(
isset
(
self
::
$_typesMap
[
$name
]))
{
self
::
getTypeRegistry
()
->
register
(
$name
,
new
$className
());
throw
DBALException
::
typeExists
(
$name
);
}
self
::
$_typesMap
[
$name
]
=
$className
;
}
}
/**
/**
...
@@ -198,7 +206,7 @@ abstract class Type
...
@@ -198,7 +206,7 @@ abstract class Type
*/
*/
public
static
function
hasType
(
$name
)
public
static
function
hasType
(
$name
)
{
{
return
isset
(
self
::
$_typesMap
[
$name
]
);
return
self
::
getTypeRegistry
()
->
has
(
$name
);
}
}
/**
/**
...
@@ -213,15 +221,7 @@ abstract class Type
...
@@ -213,15 +221,7 @@ abstract class Type
*/
*/
public
static
function
overrideType
(
$name
,
$className
)
public
static
function
overrideType
(
$name
,
$className
)
{
{
if
(
!
isset
(
self
::
$_typesMap
[
$name
]))
{
self
::
getTypeRegistry
()
->
override
(
$name
,
new
$className
());
throw
DBALException
::
typeNotFound
(
$name
);
}
if
(
isset
(
self
::
$_typeObjects
[
$name
]))
{
unset
(
self
::
$_typeObjects
[
$name
]);
}
self
::
$_typesMap
[
$name
]
=
$className
;
}
}
/**
/**
...
@@ -245,7 +245,12 @@ abstract class Type
...
@@ -245,7 +245,12 @@ abstract class Type
*/
*/
public
static
function
getTypesMap
()
public
static
function
getTypesMap
()
{
{
return
self
::
$_typesMap
;
return
array_map
(
static
function
(
Type
$type
)
:
string
{
return
get_class
(
$type
);
},
self
::
getTypeRegistry
()
->
getMap
()
);
}
}
/**
/**
...
...
lib/Doctrine/DBAL/Types/TypeRegistry.php
0 → 100644
View file @
11b67bbd
<?php
declare
(
strict_types
=
1
);
namespace
Doctrine\DBAL\Types
;
use
Doctrine\DBAL\DBALException
;
use
function
array_search
;
use
function
in_array
;
/**
* The type registry is responsible for holding a map of all known DBAL types.
* The types are stored using the flyweight pattern so that one type only exists as exactly one instance.
*
* @internal TypeRegistry exists for forward compatibility, its API should not be considered stable.
*/
final
class
TypeRegistry
{
/** @var array<string, Type> Map of type names and their corresponding flyweight objects. */
private
$instances
=
[];
/**
* Finds a type by the given name.
*
* @throws DBALException
*/
public
function
get
(
string
$name
)
:
Type
{
if
(
!
isset
(
$this
->
instances
[
$name
]))
{
throw
DBALException
::
unknownColumnType
(
$name
);
}
return
$this
->
instances
[
$name
];
}
/**
* Finds a name for the given type.
*
* @throws DBALException
*/
public
function
lookupName
(
Type
$type
)
:
string
{
$name
=
$this
->
findTypeName
(
$type
);
if
(
$name
===
null
)
{
throw
DBALException
::
typeNotRegistered
(
$type
);
}
return
$name
;
}
/**
* Checks if there is a type of the given name.
*/
public
function
has
(
string
$name
)
:
bool
{
return
isset
(
$this
->
instances
[
$name
]);
}
/**
* Registers a custom type to the type map.
*
* @throws DBALException
*/
public
function
register
(
string
$name
,
Type
$type
)
:
void
{
if
(
isset
(
$this
->
instances
[
$name
]))
{
throw
DBALException
::
typeExists
(
$name
);
}
if
(
$this
->
findTypeName
(
$type
)
!==
null
)
{
throw
DBALException
::
typeAlreadyRegistered
(
$type
);
}
$this
->
instances
[
$name
]
=
$type
;
}
/**
* Overrides an already defined type to use a different implementation.
*
* @throws DBALException
*/
public
function
override
(
string
$name
,
Type
$type
)
:
void
{
if
(
!
isset
(
$this
->
instances
[
$name
]))
{
throw
DBALException
::
typeNotFound
(
$name
);
}
if
(
!
in_array
(
$this
->
findTypeName
(
$type
),
[
$name
,
null
],
true
))
{
throw
DBALException
::
typeAlreadyRegistered
(
$type
);
}
$this
->
instances
[
$name
]
=
$type
;
}
/**
* Gets the map of all registered types and their corresponding type instances.
*
* @internal
*
* @return array<string, Type>
*/
public
function
getMap
()
:
array
{
return
$this
->
instances
;
}
private
function
findTypeName
(
Type
$type
)
:
?
string
{
$name
=
array_search
(
$type
,
$this
->
instances
,
true
);
if
(
$name
===
false
)
{
return
null
;
}
return
$name
;
}
}
tests/Doctrine/Tests/DBAL/Types/TypeRegistryTest.php
0 → 100644
View file @
11b67bbd
<?php
declare
(
strict_types
=
1
);
namespace
Doctrine\Tests\DBAL\Types
;
use
Doctrine\DBAL\DBALException
;
use
Doctrine\DBAL\Types\BinaryType
;
use
Doctrine\DBAL\Types\BlobType
;
use
Doctrine\DBAL\Types\StringType
;
use
Doctrine\DBAL\Types\TextType
;
use
Doctrine\DBAL\Types\TypeRegistry
;
use
PHPUnit\Framework\TestCase
;
class
TypeRegistryTest
extends
TestCase
{
private
const
TEST_TYPE_NAME
=
'test'
;
private
const
OTHER_TEST_TYPE_NAME
=
'other'
;
/** @var TypeRegistry */
private
$registry
;
/** @var BlobType */
private
$testType
;
/** @var BinaryType */
private
$otherTestType
;
protected
function
setUp
()
:
void
{
$this
->
testType
=
new
BlobType
();
$this
->
otherTestType
=
new
BinaryType
();
$this
->
registry
=
new
TypeRegistry
();
$this
->
registry
->
register
(
self
::
TEST_TYPE_NAME
,
$this
->
testType
);
$this
->
registry
->
register
(
self
::
OTHER_TEST_TYPE_NAME
,
$this
->
otherTestType
);
}
public
function
testGet
()
:
void
{
self
::
assertSame
(
$this
->
testType
,
$this
->
registry
->
get
(
self
::
TEST_TYPE_NAME
));
self
::
assertSame
(
$this
->
otherTestType
,
$this
->
registry
->
get
(
self
::
OTHER_TEST_TYPE_NAME
));
$this
->
expectException
(
DBALException
::
class
);
$this
->
registry
->
get
(
'unknown'
);
}
public
function
testGetReturnsSameInstances
()
:
void
{
self
::
assertSame
(
$this
->
registry
->
get
(
self
::
TEST_TYPE_NAME
),
$this
->
registry
->
get
(
self
::
TEST_TYPE_NAME
)
);
}
public
function
testLookupName
()
:
void
{
self
::
assertSame
(
self
::
TEST_TYPE_NAME
,
$this
->
registry
->
lookupName
(
$this
->
testType
)
);
self
::
assertSame
(
self
::
OTHER_TEST_TYPE_NAME
,
$this
->
registry
->
lookupName
(
$this
->
otherTestType
)
);
$this
->
expectException
(
DBALException
::
class
);
$this
->
registry
->
lookupName
(
new
TextType
());
}
public
function
testHas
()
:
void
{
self
::
assertTrue
(
$this
->
registry
->
has
(
self
::
TEST_TYPE_NAME
));
self
::
assertTrue
(
$this
->
registry
->
has
(
self
::
OTHER_TEST_TYPE_NAME
));
self
::
assertFalse
(
$this
->
registry
->
has
(
'unknown'
));
}
public
function
testRegister
()
:
void
{
$newType
=
new
TextType
();
$this
->
registry
->
register
(
'some'
,
$newType
);
self
::
assertTrue
(
$this
->
registry
->
has
(
'some'
));
self
::
assertSame
(
$newType
,
$this
->
registry
->
get
(
'some'
));
}
public
function
testRegisterWithAlradyRegisteredName
()
:
void
{
$this
->
registry
->
register
(
'some'
,
new
TextType
());
$this
->
expectException
(
DBALException
::
class
);
$this
->
registry
->
register
(
'some'
,
new
TextType
());
}
public
function
testRegisterWithAlreadyRegisteredInstance
()
:
void
{
$newType
=
new
TextType
();
$this
->
registry
->
register
(
'some'
,
$newType
);
$this
->
expectException
(
DBALException
::
class
);
$this
->
registry
->
register
(
'other'
,
$newType
);
}
public
function
testOverride
()
:
void
{
$baseType
=
new
TextType
();
$overrideType
=
new
StringType
();
$this
->
registry
->
register
(
'some'
,
$baseType
);
$this
->
registry
->
override
(
'some'
,
$overrideType
);
self
::
assertSame
(
$overrideType
,
$this
->
registry
->
get
(
'some'
));
}
public
function
testOverrideAllowsExistingInstance
()
:
void
{
$type
=
new
TextType
();
$this
->
registry
->
register
(
'some'
,
$type
);
$this
->
registry
->
override
(
'some'
,
$type
);
self
::
assertSame
(
$type
,
$this
->
registry
->
get
(
'some'
));
}
public
function
testOverrideWithAlreadyRegisteredInstance
()
:
void
{
$newType
=
new
TextType
();
$this
->
registry
->
register
(
'first'
,
$newType
);
$this
->
registry
->
register
(
'second'
,
new
StringType
());
$this
->
expectException
(
DBALException
::
class
);
$this
->
registry
->
override
(
'second'
,
$newType
);
}
public
function
testOverrideWithUnknownType
()
:
void
{
$this
->
expectException
(
DBALException
::
class
);
$this
->
registry
->
override
(
'unknown'
,
new
TextType
());
}
public
function
testGetMap
()
:
void
{
$registeredTypes
=
$this
->
registry
->
getMap
();
self
::
assertCount
(
2
,
$registeredTypes
);
self
::
assertArrayHasKey
(
self
::
TEST_TYPE_NAME
,
$registeredTypes
);
self
::
assertArrayHasKey
(
self
::
OTHER_TEST_TYPE_NAME
,
$registeredTypes
);
self
::
assertSame
(
$this
->
testType
,
$registeredTypes
[
self
::
TEST_TYPE_NAME
]);
self
::
assertSame
(
$this
->
otherTestType
,
$registeredTypes
[
self
::
OTHER_TEST_TYPE_NAME
]);
}
}
tests/Doctrine/Tests/DBAL/Types/TypeTest.php
0 → 100644
View file @
11b67bbd
<?php
declare
(
strict_types
=
1
);
namespace
Doctrine\Tests\DBAL\Types
;
use
Doctrine\DBAL\Types\Type
;
use
PHPUnit\Framework\TestCase
;
use
ReflectionClass
;
class
TypeTest
extends
TestCase
{
/**
* @dataProvider defaultTypesProvider()
*/
public
function
testDefaultTypesAreRegistered
(
string
$name
)
:
void
{
self
::
assertTrue
(
Type
::
hasType
(
$name
));
}
/**
* @return string[][]
*/
public
function
defaultTypesProvider
()
:
iterable
{
foreach
((
new
ReflectionClass
(
Type
::
class
))
->
getReflectionConstants
()
as
$constant
)
{
if
(
!
$constant
->
isPublic
())
{
continue
;
}
yield
[
$constant
->
getValue
()];
}
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment