Skip to content

Commit

Permalink
Merge pull request #16237 from craftcms/feature/link-gql
Browse files Browse the repository at this point in the history
"Full data" GraphQL mode for Link fields
  • Loading branch information
brandonkelly authored Nov 28, 2024
2 parents 6688e61 + 93950f2 commit aa4f521
Show file tree
Hide file tree
Showing 4 changed files with 187 additions and 1 deletion.
81 changes: 80 additions & 1 deletion src/fields/Link.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,17 @@
use craft\fields\linktypes\Entry;
use craft\fields\linktypes\Phone;
use craft\fields\linktypes\Url as UrlType;
use craft\gql\GqlEntityRegistry;
use craft\gql\types\generators\LinkDataType;
use craft\helpers\ArrayHelper;
use craft\helpers\Component;
use craft\helpers\Cp;
use craft\helpers\Html;
use craft\helpers\StringHelper;
use craft\validators\ArrayValidator;
use craft\validators\StringValidator;
use GraphQL\Type\Definition\InputObjectType;
use GraphQL\Type\Definition\Type;
use Illuminate\Support\Collection;
use yii\base\InvalidArgumentException;
use yii\db\Schema;
Expand Down Expand Up @@ -180,6 +184,12 @@ private static function types(): array
*/
public int $maxLength = 255;

/**
* @var bool Whether GraphQL values should be returned as objects with `type`,
* `value`, `label`, `urlSuffix`, and `url` keys.
*/
public bool $fullGraphqlData = true;

/**
* @inheritdoc
*/
Expand All @@ -198,6 +208,15 @@ public function __construct($config = [])
unset($config['placeholder']);
}

if (isset($config['graphqlMode'])) {
$config['fullGraphqlData'] = ArrayHelper::remove($config, 'graphqlMode') === 'full';
}

// Default fullGraphqlData to false for existing fields
if (isset($config['id']) && !isset($config['fullGraphqlData'])) {
$config['fullGraphqlData'] = false;
}

parent::__construct($config);
}

Expand Down Expand Up @@ -354,7 +373,7 @@ public function getSettingsHtml(): ?string
}
}

return $html .
$html .=
Html::tag('hr') .
Cp::lightswitchFieldHtml([
'label' => Craft::t('app', 'Show the “Label” field'),
Expand All @@ -374,6 +393,15 @@ public function getSettingsHtml(): ?string
'name' => 'showTargetField',
'on' => $this->showTargetField,
]) .
Html::tag('hr') .
Html::a(Craft::t('app', 'Advanced'), options: [
'class' => 'fieldtoggle',
'data' => ['target' => 'advanced'],
]) .
Html::beginTag('div', [
'id' => 'advanced',
'class' => 'hidden',
]) .
Cp::textFieldHtml([
'label' => Craft::t('app', 'Max Length'),
'instructions' => Craft::t('app', 'The maximum length (in bytes) the field can hold.'),
Expand All @@ -386,6 +414,24 @@ public function getSettingsHtml(): ?string
'errors' => $this->getErrors('maxLength'),
'data' => ['error-key' => 'maxLength'],
]);

if (Craft::$app->getConfig()->getGeneral()->enableGql) {
$html .=
Cp::selectFieldHtml([
'label' => Craft::t('app', 'GraphQL Mode'),
'id' => 'graphql-mode',
'name' => 'graphqlMode',
'options' => [
['label' => Craft::t('app', 'Full data'), 'value' => 'full'],
['label' => Craft::t('app', 'URL only'), 'value' => 'url'],
],
'value' => $this->fullGraphqlData ? 'full' : 'url',
]);
}

$html .= Html::endTag('div');

return $html;
}

/**
Expand Down Expand Up @@ -707,6 +753,39 @@ public function previewPlaceholderHtml(mixed $value, ?ElementInterface $element)
return $this->getPreviewHtml($value, new EntryElement());
}

/**
* @inheritdoc
*/
public function getContentGqlType(): Type|array
{
if (!$this->fullGraphqlData) {
return parent::getContentGqlType();
}

return LinkDataType::generateType($this);
}

/**
* @inheritdoc
*/
public function getContentGqlMutationArgumentType(): Type|array
{
if (!$this->fullGraphqlData) {
return parent::getContentGqlMutationArgumentType();
}

$typeName = 'LinkDataInput';
return GqlEntityRegistry::getOrCreate($typeName, fn() => new InputObjectType([
'name' => $typeName,
'fields' => [
'type' => Type::string(),
'value' => Type::string(),
'label' => Type::string(),
'urlSuffix' => Type::string(),
],
]));
}

/**
* @inheritdoc
*/
Expand Down
41 changes: 41 additions & 0 deletions src/gql/types/LinkData.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php
/**
* @link https://craftcms.com/
* @copyright Copyright (c) Pixel & Tonic, Inc.
* @license https://craftcms.github.io/license/
*/

namespace craft\gql\types;

use craft\fields\data\LinkData as FieldLinkData;
use craft\gql\base\ObjectType;
use GraphQL\Type\Definition\ResolveInfo;

/**
* Class LinkData
*
* @author Pixel & Tonic, Inc. <[email protected]>
* @since 5.6.0
*/
class LinkData extends ObjectType
{
/**
* @inheritdoc
*/
protected function resolve(mixed $source, array $arguments, mixed $context, ResolveInfo $resolveInfo): mixed
{
/** @var FieldLinkData $source */
$fieldName = $resolveInfo->fieldName;
return match ($fieldName) {
'type' => $source->getType(),
'value' => $source->getValue(),
'label' => $source->getLabel(true),
'url' => $source->getUrl(),
'elementType' => $source->getElement() ? $source->getElement()::class : null,
'elementId' => $source->getElement()?->id,
'elementSiteId' => $source->getElement()?->siteId,
'elementTitle' => $source->getElement() ? (string)$source->getElement() : null,
default => $source->$fieldName,
};
}
}
63 changes: 63 additions & 0 deletions src/gql/types/generators/LinkDataType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<?php
/**
* @link https://craftcms.com/
* @copyright Copyright (c) Pixel & Tonic, Inc.
* @license https://craftcms.github.io/license/
*/

namespace craft\gql\types\generators;

use Craft;
use craft\gql\base\GeneratorInterface;
use craft\gql\base\ObjectType;
use craft\gql\base\SingleGeneratorInterface;
use craft\gql\GqlEntityRegistry;
use craft\gql\types\LinkData;
use GraphQL\Type\Definition\Type;

/**
* Class LinkDataType
*
* @author Pixel & Tonic, Inc. <[email protected]>
* @since 5.6.0
*/
class LinkDataType implements GeneratorInterface, SingleGeneratorInterface
{
/**
* @inheritdoc
*/
public static function generateTypes(mixed $context = null): array
{
return [static::generateType($context)];
}

/**
* Returns the generator name.
*/
public static function getName(): string
{
return 'LinkData';
}

/**
* @inheritdoc
*/
public static function generateType(mixed $context): ObjectType
{
$typeName = self::getName();
return GqlEntityRegistry::getOrCreate($typeName, fn() => new LinkData([
'name' => $typeName,
'fields' => fn() => Craft::$app->getGql()->prepareFieldDefinitions([
'type' => Type::string(),
'value' => Type::string(),
'label' => Type::string(),
'urlSuffix' => Type::string(),
'url' => Type::string(),
'elementType' => Type::string(),
'elementId' => Type::int(),
'elementSiteId' => Type::int(),
'elementTitle' => Type::string(),
], $typeName),
]));
}
}
3 changes: 3 additions & 0 deletions src/translations/en/app.php
Original file line number Diff line number Diff line change
Expand Up @@ -728,6 +728,7 @@
'Fuchsia' => 'Fuchsia',
'Full Name' => 'Full Name',
'Full Schema' => 'Full Schema',
'Full data' => 'Full data',
'General Settings' => 'General Settings',
'General settings saved.' => 'General settings saved.',
'General' => 'General',
Expand All @@ -749,6 +750,7 @@
'Go to Craft CMS' => 'Go to Craft CMS',
'Go to Updates' => 'Go to Updates',
'Got it' => 'Got it',
'GraphQL Mode' => 'GraphQL Mode',
'GraphQL Schemas' => 'GraphQL Schemas',
'GraphQL Tokens' => 'GraphQL Tokens',
'GraphQL queries' => 'GraphQL queries',
Expand Down Expand Up @@ -1791,6 +1793,7 @@
'URI' => 'URI',
'URL Format' => 'URL Format',
'URL Suffix' => 'URL Suffix',
'URL only' => 'URL only',
'URL type' => 'URL type',
'URL' => 'URL',
'Unable to fetch updates at this time.' => 'Unable to fetch updates at this time.',
Expand Down

0 comments on commit aa4f521

Please sign in to comment.