markhuot/craftql

此软件包的最新版本(2.0.0-beta1)没有可用的许可证信息。

Craft 的 GraphQL 实现

安装量: 43,722

依赖项: 0

建议者: 1

安全: 0

星标: 319

关注者: 13

分叉: 53

公开问题: 133

语言:JavaScript

类型:craft 插件


README

CraftQL seen through the GraphiQL UI

Build Status

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
    }
  }
}

为您的安装中的每个条目类型自动创建类型。如果您有一个名为 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} 变异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 + 块处理程序。例如 BodyTextBodyImage。您可以使用响应中的键 __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 为 63Post 与评论相关,可以使用以下内容。

{
  entries(relatedTo:[{element:63}], section:comments) {
    ...on Comments {
      id
      author {
        name
      }
      commentText
    }
  }
}

注意,relatedTo: 参数接受一个关系数组。默认情况下,relatedTo: 查找匹配 所有 关系的项目。如果您想切换到与 任何 关系相关的项目,可以使用 orRelatedTo:

上述方法通常需要为源内容和相关内容分别发出请求。这相当于额外的 HTTP 请求和延迟。如果您使用 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)
      }
    }
  }
}

您还可以使用cropfitstretch参数指定确切的裁剪,具体请参考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
          }
        }
      }
    }
  }
}

类别和标签

可以通过顶层categoriestags字段查询分类法。这两个字段与它们的craft.entriescraft.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字段级别权限。默认情况下,令牌没有任何权利。您必须点击“作用域”部分来调整每个令牌可以做什么。

token scopes

作用域允许您配置哪些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.6.0+
  • 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