Search by

aimeos / pagible-graphql

aimeos

Pagible CMS - GraphQL API

Package info

github.com/aimeos/pagible-graphql

Homepage

pkg:composer/aimeos/pagible-graphql

Statistics

Installs: 199

Dependents: 4

Suggesters: 2

Stars: 0

Open Issues: 0

0.13.2 2026-09-30 17:23 UTC

README

GraphQL API for Pagible CMS built on Lighthouse. Provides full CRUD for pages, elements, files, and metrics.

This package is part of the Pagible CMS monorepo. For full installation, use:

composer require aimeos/pagible

Configuration

GraphQL-specific configuration is available in config/cms/graphql.php:

Option Env Variable Default Description
maxdepth CMS_GRAPHQL_MAXDEPTH 15 Maximum query nesting depth
maxcomplexity CMS_GRAPHQL_MAXCOMPLEXITY 10000 Maximum query complexity score

The upload policy is shared by every CMS interface and configured through upload.filesize and upload.mimetypes in config/cms.php.

Page access

The Page.restricted field tells page viewers whether immediate frontend access rules exist without exposing their values. Page.access requires page:access and represents the rules independently from page versions:

  • null means public access
  • an empty list permits authenticated users of the current tenant
  • a non-empty list permits users granted any listed access value

Users with page:access can replace this state with setPageAccess(id:, access:, descendants:). The nullable access argument must be provided explicitly. Multiple selected page IDs are supported; recursive changes are limited to one root page. Page bulk operations are limited to 1,000 unique pages, and recursive calls fail before writing if the resolved subtree exceeds 1,000 pages. Query.access lists catalog names for both the general catalog screen and page access controls, so it accepts either access:view or page:access. Without arguments it returns the complete bounded catalog; callers can provide term and first for autocomplete searches. The permissions remain registered in separate namespaces.

The admin access route and navigation require access:view. Within its Users tab, user creation, frontend access, and CMS editor permissions remain independent capabilities:

  • createUser(email:) requires user:create. It creates a user through the active Eloquent authentication provider with a hashed random password, the email as the internal name fallback, and no frontend access or CMS permissions. Existing emails are rejected rather than modified, and the created CmsUserData can be used without another lookup.
  • cmsUser(email:) performs one exact normalized email lookup and returns the narrow CmsUserData projection, including an opaque ID for subsequent writes. The query accepts either user:access or user:permission; its access and permissions fields enforce those capabilities independently.
  • setUserAccess(id:, access:) requires user:access and atomically replaces direct frontend values supported by the configured access adapter.
  • permissions returns configured CMS role names and registered permission names, while setUserPermissions(id:, permissions:) atomically replaces the raw cmsperms entries. Both require user:permission; this is a super-admin capability that permits assigning any configured role or permission, including to the current user. Supported role, permission, wildcard, and deny values are validated before writing.

All user-specific operations resolve users through the configured authentication provider and apply Tenancy::allows() before disclosure or change. Missing and foreign-tenant users are indistinguishable. CmsUserData exposes only an opaque ID, the email, and independently protected authorization assignments; clients must treat the ID as opaque and use it instead of the mutable email for assignment writes. CmsUser remains the authenticated-user projection returned by me, and the application's standard User GraphQL type is not extended. The generated password is never returned, so applications need a password-reset or invitation flow before password login. Successful creation and assignment replacement emit the structured UserChanged audit event; the built-in watch listener records it as cms.user with actor, target, tenant, and resulting assignments.

Extending the schema

cms:install:graphql imports the CMS schema into your graphql/schema.graphql, so you can add your own queries and mutations there and use the CMS types like Page:

extend type Mutation {
  "Publish all subpages of the page"
  publishChildren(id: ID! @rules(apply: ["uuid"])): [Page]!
    @guard @cmsPermission(action: "page:publish") @throttle(name: "cms-graphql")
}

Lighthouse resolves the mutation by the App\GraphQL\Mutations\PublishChildren class. Pass the authenticated user to the facades, so the CMS permissions and versioning apply like in the built-in mutations:

namespace App\GraphQL\Mutations;

use Aimeos\Cms\Facades\Pages;
use Aimeos\Cms\Models\Page;
use Illuminate\Support\Facades\Auth;

final class PublishChildren
{
    public function __invoke( $rootValue, array $args ) : array
    {
        $ids = Page::where( 'parent_id', $args['id'] )->pluck( 'id' )->all();

        return Pages::publishMany( $ids, Auth::user() )->all();
    }
}

@cmsPermission(action: [...], any: true) requires all listed CMS permissions, or one of them with any: true. As CMS permissions are Laravel Gate abilities, Lighthouse directives like @canRoot(ability: "page:publish") work too. Aimeos\Cms\Exception errors thrown in any resolver are returned as client-safe GraphQL errors with their message.

Commands

cms:install:graphql

Installs the Pagible GraphQL package.

php artisan cms:install:graphql

Publishes the Lighthouse schema and configuration, registers CMS models/mutations/queries in the Lighthouse config, and adds the CMS schema import to graphql/schema.graphql.

License

MIT