fieldwork / craftql
Craft 的 GraphQL 实现
Requires
- craftcms/cms: ^3.0.0
- react/http: ^0.7
- webonyx/graphql-php: ^0.11.0
This package is auto-updated.
Last update: 2024-09-26 02:24:06 UTC
README
Craft CMS 实现的嵌入式 GraphQL 服务器。无需配置,CraftQL 允许您通过熟悉的 GraphQL 接口访问 Craft 的所有功能。
示例
安装后,您可以使用简单的 Hello World 进行测试:
{
helloWorld
}
如果成功,您现在可以使用几乎与您的 Twig 模板完全相同的语法查询 Craft CMS。
{ entries(section:[news], limit:5, search:"body:salty") { ...on News { title url body } } }
CraftQL 提供了一个顶级 entries
字段,它接受与模板中 craft.entries
相同的参数。这是最常用的字段/访问点。例如:
query fetchNews { # The query, `query fetchNews` is completely optional entries(section:[news]) { # Arguments match `craft.entries` ...on News { # GraphQL is strongly typed, so you must specify each Entry Type you want data from id # A field to return title # A field to return body # A field to return } } }
为安装中的每个 Entry Type 自动创建类型。如果您有一个名为 news
的部分和一个名为 news
的条目类型,则 GraphQL 类型将命名为 News
。如果您有一个名为 news
的部分和一个名为 pressRelease
的条目类型,则 GraphQL 类型将命名为 NewsPressRelease
。约定是将部分句柄和条目类型句柄合并在一起,除非它们相同,在这种情况下将使用部分句柄。
query fetchNews { entries(section:[news]) { ...on News { # Any fields on the News entry type id title body } ...on NewsPressRelease { # Any fields on the Press Release entry type id title body source contactInfo downloads { title url } } } }
要修改内容,请确保您的令牌具有写入权限,然后使用顶级的 upsert{EntryType}
Mutation
。 upsert{EntryType}
接受每个在 Craft 中定义的字段参数。
mutation createNewEntry($title:String, $body:String) { upsertNews( title:$title, body:$body, ) { id url } }
上述代码可以通过以下变量传递:
{ "title": "My first mutation!", "body": "<p>Here's the body of my first mutation</p>", }
矩阵字段
处理矩阵字段与处理条目类型类似:如果您有一个名为 body
的矩阵字段,包含的块类型将命名为 Body
+ 块句柄。例如 BodyText
或 BodyImage
。您可以使用响应中的 __typename
键映射块并显示适当的组件。
{ entries(section: [news]) { ... on News { id title body { # Your Matrix Field ... on BodyText { # Block Type __typename # Ensures the response has a field describing the type of block blockHeading # Fields on Block Type, uses field handle blockContent # Fields on Block Type, uses field handle } ... on BodyImage { # Block Type __typename # Ensures the response has a field describing the type of block blockDescription # Fields on Block Type, uses field handle image { # Fields on Block Type, uses field handle id # Fields on image field on Block Type, uses field handles } } } } } }
日期
在 CraftQL 中,所有日期都以 Timestamp
标量形式输出,表示 Unix 时间戳。例如:
{ entries { dateCreated # outputs 1503368510 } }
可以使用 @date
指令将日期转换为人类友好的格式:
{ entries { dateCreated @date(as:"F j, Y") # outputs August 21, 2017 } }
关系
根据您的需求,可以以几种方式检索相关条目。
类似于 craft.entries.relatedTo(entry)
,您可以在 entries
顶级查询字段上使用 relatedTo
参数。例如,如果您有一个 ID 为 63
的 Post
与评论相关,则可以使用以下内容:
{ entries(relatedTo:[{element:63}], section:comments) { ...on Comments { id author { name } commentText } } }
注意,relatedTo:
参数接受关系数组。默认情况下,relatedTo:
查找匹配 所有 关系的元素。如果您想切换到与 任何 关系相关的元素,可以使用 orRelatedTo:
。
上述方法通常需要为源内容和相关内容分别发出请求。这相当于额外的 HTTP 请求和延迟。如果您使用的是 "connection" 方法来 CraftQL,则可以使用 EntryEdge
类型的 relatedEntries
字段在单个请求中检索关系。相同的请求可以重写如下,以在单个请求中获取帖子及其评论:
{ entriesConnection(id:63) { edges { node { ...on Post { title body } } relatedEntries(section:comments) { edges { node { ...on Comment { author { name } commentText } } } } } } }
转换
您可以通过指定任何资产字段的参数来请求CraftQL进行图像转换。注意:为了使此功能生效,存储图像的卷必须在卷设置中启用“公共URL”,否则CraftQL将返回null
值。
如果您在Craft UI中定义了命名转换,您可以通过其handle引用转换
{ entries { ...on Post { imageFieldHandle { thumbnail: url(transform: thumb) } } } }
您还可以使用crop
、fit
或stretch
参数指定确切的裁剪,这些参数在Craft文档中有说明。
{ entries { ...on Post { imageFieldHandle { poster: url(crop: {width: 1280, height: 720, position: topLeft, quality: 50, format: jpg}) } } } }
草稿
最好通过entriesConnection
查询上的边缘节点获取草稿。您可以使用以下查询获取条目的所有草稿
{ entriesConnection(id:63) { edges { node { # the published node, as `craft.entries` would return id title } drafts { # an array of drafts edges { node { # the draft content id title ...on Post { # draft fields are still referenced by entry type, as usual body } } draftInfo { # the `draftInfo` field returns the meta data about the draft draftId name notes } } } } } }
类别和标签
可以通过顶级categories
或tags
字段查询分类法。这两个字段的工作方式与其craft.entries
和craft.tags
对应物相同。
{ categories { # lists all categories, or use `tags` to get all tags id title } }
为了增加功能,通过其相关的Connection
字段查询类别和标签。这为返回提供了获取相关条目的位置
{ categoriesConnection { totalCount edges { node { title # the category title } relatedEntries { entries { title # an entry title, that's related to this category } } } } }
用户
您可以通过顶级users
字段查询用户
{ users { id name email } }
您还可以通过upsertUser
字段修改用户。当传递id:
时,它将更新用户。如果缺少id:
属性,它将创建一个新用户
mutation { upsertUser(id:1, firstName:"Mark", lastName:"Huot") { id name # returns `Mark Huot` after the mutation } }
还可以设置权限,但您必须始终传递用户权限的完整列表。例如:
mutation { upsertUser(id:1, permissions:["accessCp","editEntries:17","createEntries:17","deleteEntries:17"]) { id name # returns `Mark Huot` after the mutation } }
安全性
CraftQL支持GraphQl字段级别权限。默认情况下,令牌没有任何权利。您必须点击“作用域”部分来调整每个令牌可以做什么。
作用域允许您配置哪些GraphQL字段和条目类型包含在模式中。
第三方字段支持
要将CraftQL支持添加到您的第三方字段插件,您需要监听craftQlGetFieldSchema
事件。此事件在您的自定义字段上触发,并将“模式构建器”传递到事件处理器中,允许您指定您的自定义字段提供的字段模式。例如,在您的插件::init
方法中,您可以指定:
Event::on(\my\custom\Field::class, 'craftQlGetFieldSchema', function (\markhuot\CraftQL\Events\GetFieldSchema $event) { // the custom field is passed as the event sender $field = $event->sender; // the schema exists on a public property of the event $event->schema // you can add as many fields as you need to for your field. Typically you'll // pass your field in, which will automatically set the name and description // based on the Craft config. ->addStringField($field); // the schema is a fluent builder and can be chained to set multiple properties // of the custom field $event->schema->addEnumField('customField') ->lists() ->description('This is a custom description for the field') ->values(['KEY' => 'Label', 'KEY2' => 'Another label']); });
当调用Post条目类型上的excerpt
字段时,上述内容将生成一个与以下内容大致相当的方案:
type CustomFieldEnum { # Label KEY # Another label KEY2 } type Post { # The field instructions are automatically included excerpt: String # This is a custom description for the field customField: [CustomFieldEnum] }
如果您的自定义字段解析了一个对象,您也可以将其暴露给CraftQL。例如,如果您正在实现一个公开地图的自定义字段,该地图包含纬度、经度和缩放级别,它可能看起来像:
Event::on(\craft\base\Field::class, 'craftQlGetFieldSchema', function ($event) { $field = $event->sender; $object = $event->schema->createObjectType('MapPoint') ->addStringField('lat') ->addStringField('lng') ->addStringField('zoom'); $event->schema->addField($field)->type($object); });
路线图
没有软件是永远完成的。还有很多工作要做,才能使CraftQL功能完善。一些未解决的问题包括:
- 矩阵字段尚未包含在模式中
- 表格字段尚未包含在模式中
- 资产突变(通过传递URL或资产ID实现)
- 通过POST $_FILES在突变期间上传文件到资产
- 自动化测试尚未启用
- 自动化测试实际上尚未测试任何内容
- 突变需要更多的测试
-
relatedEntries:
改进以获取源/目标 - 持久查询
- 子类化的枚举字段能够返回原始字段值
需求
- Craft 3.0.0-RC1
- PHP 7.0+
安装
如果您还没有安装Craft 3,请先这样做
$ composer create-project craftcms/craft my-awesome-site -s beta
一旦您有了Craft 3的运行版本,您就可以使用Composer安装CraftQL
$ composer require markhuot/craftql:^1.0.0
运行CLI服务器
CraftQL 配套了一个本地的 PHP 网络服务器。通过提供的网络服务器运行 CraftQL 时,启动过程只会发生在初次启动时。这可能会显著提高响应速度,因为 PHP 会在请求之间保持状态。一般来说,我观察到性能提高了 5 倍(从 500ms 降低到 <100ms)。
注意:这也可能产生意外的副作用,因为 Craft 并非原生设计为以这种方式运行。请不要在生产环境中使用此功能,否则可能会导致内存泄漏、服务器故障和 IT 通知闹铃:
php craft craftql/server