π¦ΈπΏββοΈ Gato GraphQL ΡΠ΅ΠΏΠ΅ΡΡ ΡΡΠ°Π½ΡΠΏΠΈΠ»ΠΈΡΡΠ΅ΡΡΡ Ρ PHP 8.0 Π΄ΠΎ 7.1
ΠΠ΅ΠΊΠΎΡΠΎΡΠΎΠ΅ Π²ΡΠ΅ΠΌΡ Π½Π°Π·Π°Π΄ Ρ Π½Π°ΠΏΠΈΡΠ°Π» ΠΎ ΡΠΎΠΌ, ΡΡΠΎ ΡΠ°ΠΊΠΎΠ΅ ΡΡΠ°Π½ΡΠΏΠΈΠ»ΡΡΠΈΡ PHP-ΠΊΠΎΠ΄Π°:
- Transpiling PHP code from 8.0 to 7.x via Rector
- Coding in PHP 7.4 and deploying to 7.1 via Rector and GitHub Actions
Π’ΡΠ°Π½ΡΠΏΠΈΠ»ΡΡΠΈΡ PHP-ΠΊΠΎΠ΄Π° ΠΏΠΎΠ·Π²ΠΎΠ»ΡΠ΅Ρ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΡ Π½ΠΎΠ²Π΅ΠΉΡΠΈΠ΅ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡΠΈ PHP ΠΏΡΠΈ ΡΠ°Π·ΡΠ°Π±ΠΎΡΠΊΠ΅, Π½ΠΎ Π²ΡΠΏΡΡΠΊΠ°ΡΡ ΠΏΠ»Π°Π³ΠΈΠ½ Ρ ΠΊΠΎΠ΄ΠΎΠΌ, ΠΊΠΎΠ½Π²Π΅ΡΡΠΈΡΠΎΠ²Π°Π½Π½ΡΠΌ Π² Π±ΠΎΠ»Π΅Π΅ ΡΡΠ°ΡΡΡ Π²Π΅ΡΡΠΈΡ PHP Π΄Π»Ρ ΠΏΡΠΎΠ΄Π°ΠΊΡΠ΅Π½Π°, ΡΡΠΎΠ±Ρ ΠΎΡ Π²Π°ΡΠΈΡΡ Π±ΠΎΠ»Π΅Π΅ ΡΠΈΡΠΎΠΊΡΡ Π°ΡΠ΄ΠΈΡΠΎΡΠΈΡ ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»Π΅ΠΉ.
ΠΠΎΡΠ»Π΅Π΄Π½ΠΈΠ΅ Π½Π΅ΡΠΊΠΎΠ»ΡΠΊΠΎ Π½Π΅Π΄Π΅Π»Ρ Ρ Π·Π°Π½ΠΈΠΌΠ°Π»ΡΡ Π΄Π°Π»ΡΠ½Π΅ΠΉΡΠ΅ΠΉ Π΄ΠΎΡΠ°Π±ΠΎΡΠΊΠΎΠΉ ΡΡΠΎΠ³ΠΎ ΠΏΡΠΎΡΠ΅ΡΡΠ° Π΄Π»Ρ ΠΏΠ»Π°Π³ΠΈΠ½Π° Gato GraphQL.
Π Π°Π΄ ΡΠΎΠΎΠ±ΡΠΈΡΡ, ΡΡΠΎ ΠΎΡΠ½ΡΠ½Π΅ ΠΌΠΈΠ½ΠΈΠΌΠ°Π»ΡΠ½ΠΎ ΡΡΠ΅Π±ΡΠ΅ΠΌΠ°Ρ Π²Π΅ΡΡΠΈΡ PHP Π±ΡΠ»Π° ΠΏΠΎΠ²ΡΡΠ΅Π½Π° Π΄ΠΎ PHP 8.0:

ΠΠΎΡΠΊΠΎΠ»ΡΠΊΡ ΠΏΠ»Π°Π³ΠΈΠ½ ΡΠ΅ΠΏΠ΅ΡΡ ΠΌΠΎΠΆΠ΅Ρ ΡΠ°ΡΡΡΠΈΡΡΠ²Π°ΡΡ Π½Π° PHP 8.0, ΠΌΠ½Π΅ ΡΠ΄Π°Π»ΠΎΡΡ Π·Π°Π²Π΅ΡΡΠΈΡΡ Π΄ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠ΅ ΡΠΈΠΏΠΎΠ² ΠΊΠΎ Π²ΡΠ΅ΠΌ ΡΠ²ΠΎΠΉΡΡΠ²Π°ΠΌ Π²ΠΎ Π²ΡΠ΅Ρ PHP-ΠΊΠ»Π°ΡΡΠ°Ρ ΠΊΠΎΠ΄ΠΎΠ²ΠΎΠΉ Π±Π°Π·Ρ, Π²ΠΊΠ»ΡΡΠ°Ρ union types.
ΠΡΠ΅Π²ΠΎΡΡ ΠΎΠ΄Π½ΠΎ!
ΠΠΎΡ ΠΊΡΠ°ΡΠΊΠΎΠ΅ ΠΎΠΏΠΈΡΠ°Π½ΠΈΠ΅ Π²ΡΠ΅Ρ Π½ΠΎΠ²ΡΡ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡΠ΅ΠΉ PHP 8.0, Π΄ΠΎΡΡΡΠΏΠ½ΡΡ ΠΏΡΠΈ ΡΠ°Π·ΡΠ°Π±ΠΎΡΠΊΠ΅ ΠΏΠ»Π°Π³ΠΈΠ½Π°.
ΠΠΎΠ²ΡΠ΅ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡΠΈ PHP 8.0
ΠΡΠΈ ΡΠ°Π·ΡΠ°Π±ΠΎΡΠΊΠ΅ Gato GraphQL ΡΠ΅ΠΏΠ΅ΡΡ Π΄ΠΎΡΡΡΠΏΠ½Ρ ΡΠ»Π΅Π΄ΡΡΡΠΈΠ΅ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡΠΈ PHP 8.0:
- Union types
- ΠΡΠ΅Π²Π΄ΠΎΡΠΈΠΏ
mixed - ΠΠΎΠ·Π²ΡΠ°ΡΠ°Π΅ΠΌΡΠΉ ΡΠΈΠΏ
static - ΠΠ°Π³ΠΈΡΠ΅ΡΠΊΠ°Ρ ΠΊΠΎΠ½ΡΡΠ°Π½ΡΠ°
::classΠ½Π° ΠΎΠ±ΡΠ΅ΠΊΡΠ°Ρ - ΠΡΡΠ°ΠΆΠ΅Π½ΠΈΡ
match catchΠΈΡΠΊΠ»ΡΡΠ΅Π½ΠΈΠΉ ΡΠΎΠ»ΡΠΊΠΎ ΠΏΠΎ ΡΠΈΠΏΡ- Null-safe ΠΎΠΏΠ΅ΡΠ°ΡΠΎΡ
- ΠΡΠΎΠ΄Π²ΠΈΠΆΠ΅Π½ΠΈΠ΅ ΡΠ²ΠΎΠΉΡΡΠ² Π² ΠΊΠΎΠ½ΡΡΡΡΠΊΡΠΎΡΠ΅ ΠΊΠ»Π°ΡΡΠ°
- ΠΠ°Π²Π΅ΡΡΠ°ΡΡΠΈΠ΅ Π·Π°ΠΏΡΡΡΠ΅ Π² ΡΠΏΠΈΡΠΊΠ°Ρ
ΠΏΠ°ΡΠ°ΠΌΠ΅ΡΡΠΎΠ² ΠΈ ΡΠΏΠΈΡΠΊΠ°Ρ
useΠ² Π·Π°ΠΌΡΠΊΠ°Π½ΠΈΡΡ
Π Π°ΡΡΠΌΠΎΡΡΠΈΠΌ ΠΏΡΠΈΠΌΠ΅Ρ ΠΊΠ°ΠΆΠ΄ΠΎΠΉ ΠΈΠ· Π½ΠΈΡ
: ΠΊΠ°ΠΊ ΠΎΠ½ΠΈ ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΡΡΡΡ Π² ΠΏΠ»Π°Π³ΠΈΠ½Π΅ ΠΏΡΠΈ ΡΠ°Π·ΡΠ°Π±ΠΎΡΠΊΠ΅ ΠΈ Π²ΠΎ ΡΡΠΎ ΡΡΠ°Π½ΡΠΏΠΈΠ»ΠΈΡΡΡΡΡΡ ΠΏΡΠΈ Π³Π΅Π½Π΅ΡΠ°ΡΠΈΠΈ graphql-api.zip.
Union types
interface CustomPostTypeAPIInterface
{
public function createCustomPost(array $data): string | int | null | Error;
}Π’ΡΠ°Π½ΡΠΏΠΈΠ»ΠΈΡΡΠ΅ΡΡΡ Π²:
interface CustomPostTypeAPIInterface
{
public function createCustomPost(array $data)
}ΠΡΠ΅Π²Π΄ΠΎΡΠΈΠΏ mixed
interface CMSServiceInterface
{
public function getOption(string $option, mixed $default = false): mixed;
}Π’ΡΠ°Π½ΡΠΏΠΈΠ»ΠΈΡΡΠ΅ΡΡΡ Π²:
interface CMSServiceInterface
{
public function getOption(string $option, $default = false);
}ΠΠ°Π³ΠΈΡΠ΅ΡΠΊΠ°Ρ ΠΊΠΎΠ½ΡΡΠ°Π½ΡΠ° ::class Π½Π° ΠΎΠ±ΡΠ΅ΠΊΡΠ°Ρ
foreach ($directiveResolvers as $directiveResolver) {
$directiveResolverName = $directiveResolver->getDirectiveName();
$this->directiveNameClasses[$directiveResolverName][] = $directiveResolver::class;
}Π’ΡΠ°Π½ΡΠΏΠΈΠ»ΠΈΡΡΠ΅ΡΡΡ Π²:
foreach ($directiveResolvers as $directiveResolver) {
$directiveResolverName = $directiveResolver->getDirectiveName();
$this->directiveNameClasses[$directiveResolverName][] = get_class($directiveResolver);
}ΠΡΡΠ°ΠΆΠ΅Π½ΠΈΡ match
public function getSchemaFieldType(TypeResolverInterface $typeResolver, string $fieldName): ?string
{
$ret = match($fieldName) {
'accessControlLists' => TypeCastingHelpers::makeArray(SchemaDefinition::TYPE_ID),
'cacheControlLists' => TypeCastingHelpers::makeArray(SchemaDefinition::TYPE_ID),
'fieldDeprecationLists' => TypeCastingHelpers::makeArray(SchemaDefinition::TYPE_ID),
'schemaConfigurations' => TypeCastingHelpers::makeArray(SchemaDefinition::TYPE_ID),
default => parent::getSchemaFieldType($typeResolver, $fieldName),
};
return $ret;
}Π’ΡΠ°Π½ΡΠΏΠΈΠ»ΠΈΡΡΠ΅ΡΡΡ Π²:
public function getSchemaFieldType(TypeResolverInterface $typeResolver, string $fieldName): ?string
{
switch ($fieldName) {
case 'accessControlLists':
$ret = TypeCastingHelpers::makeArray(SchemaDefinition::TYPE_ID);
break;
case 'cacheControlLists':
$ret = TypeCastingHelpers::makeArray(SchemaDefinition::TYPE_ID);
break;
case 'fieldDeprecationLists':
$ret = TypeCastingHelpers::makeArray(SchemaDefinition::TYPE_ID);
break;
case 'schemaConfigurations':
$ret = TypeCastingHelpers::makeArray(SchemaDefinition::TYPE_ID);
break;
default:
$ret = parent::getSchemaFieldType($typeResolver, $fieldName);
break;
}
return $ret;
}catch ΠΈΡΠΊΠ»ΡΡΠ΅Π½ΠΈΠΉ ΡΠΎΠ»ΡΠΊΠΎ ΠΏΠΎ ΡΠΈΠΏΡ
try {
// ...
} catch (InvalidArgumentException) {
return sprintf(
'<p>%s</p>',
\__('Oops, the documentation for this module is not available', 'graphql-api')
);
}Π’ΡΠ°Π½ΡΠΏΠΈΠ»ΠΈΡΡΠ΅ΡΡΡ Π²:
try {
// ...
} catch (InvalidArgumentException $exception) {
return sprintf(
'<p>%s</p>',
\__('Oops, the documentation for this module is not available', 'graphql-api')
);
}Null-safe ΠΎΠΏΠ΅ΡΠ°ΡΠΎΡ
public function getSchemaDirectiveDeprecationDescription(TypeResolverInterface $typeResolver): ?string
{
return $this->getSchemaDefinitionResolver($typeResolver)?->getSchemaDirectiveDeprecationDescription($typeResolver);
}Π’ΡΠ°Π½ΡΠΏΠΈΠ»ΠΈΡΡΠ΅ΡΡΡ Π²:
public function getSchemaDirectiveDeprecationDescription(TypeResolverInterface $typeResolver): ?string
{
return $this->getSchemaDefinitionResolver($typeResolver) ? $this->getSchemaDefinitionResolver($typeResolver)->getSchemaDirectiveDeprecationDescription($typeResolver) : null;
}ΠΡΠΎΠ΄Π²ΠΈΠΆΠ΅Π½ΠΈΠ΅ ΡΠ²ΠΎΠΉΡΡΠ² Π² ΠΊΠΎΠ½ΡΡΡΡΠΊΡΠΎΡΠ΅ ΠΊΠ»Π°ΡΡΠ°
abstract class AbstractEndpointResolver
{
function __construct(protected EndpointHelpers $endpointHelpers)
{
}
}Π’ΡΠ°Π½ΡΠΏΠΈΠ»ΠΈΡΡΠ΅ΡΡΡ Π²:
abstract class AbstractEndpointResolver
{
/**
* @var \GraphQLAPI\GraphQLAPI\Services\Helpers\EndpointHelpers
*/
protected $endpointHelpers;
function __construct(EndpointHelpers $endpointHelpers)
{
$this->endpointHelpers = $endpointHelpers;
}
}ΠΠ°Π²Π΅ΡΡΠ°ΡΡΠΈΠ΅ Π·Π°ΠΏΡΡΡΠ΅ Π² ΡΠΏΠΈΡΠΊΠ°Ρ
ΠΏΠ°ΡΠ°ΠΌΠ΅ΡΡΠΎΠ² ΠΈ ΡΠΏΠΈΡΠΊΠ°Ρ
use Π² Π·Π°ΠΌΡΠΊΠ°Π½ΠΈΡΡ
public function resolveFieldTypeResolverClass(TypeResolverInterface $typeResolver, string $fieldName): ?string
{
switch ($fieldName) {
case 'accessControlLists':
return CustomPostTypeResolver::class;
}
return parent::resolveFieldTypeResolverClass(
$typeResolver,
$fieldName,
);
}Π’ΡΠ°Π½ΡΠΏΠΈΠ»ΠΈΡΡΠ΅ΡΡΡ Π²:
public function resolveFieldTypeResolverClass(TypeResolverInterface $typeResolver, string $fieldName): ?string
{
switch ($fieldName) {
case 'accessControlLists':
return CustomPostTypeResolver::class;
}
return parent::resolveFieldTypeResolverClass($typeResolver, $fieldName);
}