△blueprint (設計図)

Flex ブループリントの基本構造は、タイトル、説明、タイプを記述するセクションと、ディレクトリタイプとは異なる側面を記述する config、blueprints、form の 3 つのセクションで構成されています。

contacts.yaml の主な構造

title: Contacts
description: Simple contact directory with tags.
type: flex-objects  # do not change

# Flex Configuration
config: {}

# Flex Directory Forms
blueprints: {}

# Flex Object Form
form: {}

独自の Directory を作成するには、まずタイプ(ファイル名)に名前を付け、タイトルと 説明を記入する必要があります。

ファイルを作成し、基本情報を入力したら、次は既存のフォームをコピーするか、ファイルにいくつかのフィールドを追加します。

TIP: ここでは、独自のフォームと blueprint を作成する方法を既にご存知であると仮定します。

WARNING: It is better not to use the simple list format to describe the fields as described in Create a simple single form. Also do not pass process section of the form to this file, it will not be used by Flex.

フォーム

連絡先の例では、フォームセクションは次のようになります。

# Flex Object Form
form:
  validation: loose

  fields:
    published:
      type: toggle
      label: Published
      highlight: 1
      default: 1
      options:
        1: PLUGIN_ADMIN.YES
        0: PLUGIN_ADMIN.NO
      validate:
        type: bool
        required: true

    last_name:
      type: text
      label: Last Name
      validate:
        required: true

    first_name:
      type: text
      label: First Name
      validate:
        required: true

    email:
      type: email
      label: Email Address
      validate:
        required: true

    website:
      type: url
      label: Website URL

    tags:
      type: selectize
      size: large
      label: Tags
      classes: fancy
      validate:
        type: commalist

このフォームは、ページから取得したものであっても、設定、プラグイン、テーマのブループリント・ファイルから取得したものであっても、同じように見えます。これはディレクトリ内のすべてのオブジェクトのメイン設計図で、オブジェクトで定義されたすべてのフィールドを含む必要があります。管理者に表示されるフォームと同じだと考えてください。

WARNING: Be careful when you modify a blueprint for existing Flex Type. Make sure objects you have already saved are compatible with the new version of the blueprint - meaning that you should be able to both save and display the older objects.

まだ、完成したわけではありません。 データストレージ層を設定することと、管理者リストビューに表示するフィールドを定義する必要があります。この2つは設定セクションで行うことができます。

Config

ConfigセクションはFlex Blueprintの中で最も複雑な部分ですが、その多くはカスタマイズを可能にするためだけのものです。データセクション、管理セクション、サイトセクションを含みます。

# Flex Configuration
config:

  # Data Settings
  data: {}

  # Admin Settings
  admin: {}

  # Site Settings
  site: {}

最小構成は以下のようになります。

# Flex Configuration
config:

  # Data Settings
  data:
    storage: user-data://flex-objects/contacts.json

  # Admin Settings
  admin:
    # List view
    list:
      # List of fields to display
      fields:
        last_name:
          link: edit # Edit link
        first_name:
          link: edit # Edit link
        email:
        website:

設定には、config.data.storage と config.admin.list.fields という2つの必須セクションがあります。後者は、管理者リストビュー内に表示されるフィールドを定義します。一方、データストレージは、データがどのように保存されるかを定義します。

Config > Data

Flex Directory is highly customizable. You can use your own object, collection and index PHP classes to add your own behavior. Additionally, you can configure the storage layer to best fit your needs. Directory also has it's default ordering and search functionality.

config:
  data:
    # Flex Object Class
    object: CLASSNAME
    # Flex Collection Class
    collection: CLASSNAME
    # Flex Index Class
    index: CLASSNAME
    # Storage Options
    storage: {}
    # Ordering Options
    ordering: {}
    # Search Options
    search: {}

Object, collection and index take class names. If they are not provided, Grav will use the following default configuration:

config:
  data:
    object: 'Grav\Common\Flex\Types\Generic\GenericObject'
    collection: 'Grav\Common\Flex\Types\Generic\GenericCollection'
    index: 'Grav\Common\Flex\Types\Generic\GenericIndex'

These classes will together define the behavior for your type. If you want to customize your own type, it is possible by extending these classes and passing your own classes here.

One of the most important parts is to define where and how the data is being stored:

config:
  data:
    storage:
      class: 'Grav\Framework\Flex\Storage\SimpleStorage'
      options:
        formatter:
          class: 'Grav\Framework\File\Formatter\JsonFormatter'
        folder: user-data://flex-objects/contacts.json

Above is a special case which can also be written in a short form:

config:
  data:
    storage: user-data://flex-objects/contacts.json

Grav 1.7 provides 3 different storage strategies, though you can easily create your own:

Name Class Description
Simple Storage Grav\Framework\Flex\Storage\SimpleStorage All objects are stored into a single file. Does not support media.
File Storage Grav\Framework\Flex\Storage\FileStorage Objects are stored into separate files in a single folder.
Folder Storage Grav\Framework\Flex\Storage\FolderStorage Every object is stored into a separate folder.

Additionally you can provide file format with options.formatter.class:

Name Class Description
JSON Grav\Framework\File\Formatter\JsonFormatter Use JSON file format.
YAML Grav\Framework\File\Formatter\YamlFormatter Use YAML file format.
Markdown Grav\Framework\File\Formatter\MarkdownFormatter Use Grav's Markdown file format with YAML frontmatter.
Serialize Grav\Framework\File\Formatter\SerializeFormatter Use PHP serializer. Fast but not human readable.
INI Grav\Framework\File\Formatter\IniFormatter Use INI file format. Not recommended.
CSV Grav\Framework\File\Formatter\CsvFormatter Use CSV file format. Not recommended.

Configuration options (with defaults) for the default formatters can be found below inside the tabs:

[ui-tabs] [ui-tab title="JSON"]
# JSON
formatter:
  class: 'Grav\Framework\File\Formatter\JsonFormatter'
  options:
    file_extension: '.json'
    encode_options: '' # See https://www.php.net/manual/en/function.json-encode.php (separate options with space)
    decode_assoc: true # Decode objects as arrays
    decode_depth: 512  # Decode up to 512 levels
    decode_options: '' # See https://www.php.net/manual/en/function.json-decode.php (separate options with space)
[/ui-tab] [ui-tab title="YAML"]
# YAML
formatter:
  class: 'Grav\Framework\File\Formatter\YamlFormatter'
  options:
    file_extension: '.yaml'
    inline: 5           # Save with up to 4 expanded levels
    indent: 2           # Indent with 2 spaces
    native: true        # Use native YAML decoder if available
    compat: true        # If YAML cannot be decoded, use compatibility mode (SLOW)
[/ui-tab] [ui-tab title="Markdown"]
# Markdown
formatter:
  class: 'Grav\Framework\File\Formatter\MarkdownFormatter'
  options:
    file_extension: '.md'
    header: 'header'    # Header variable eg. header.title
    body: 'markdown'    # Body variable
    raw: 'frontmatter'  # RAW YAML variable
    yaml:
      inline: 20        # YAML options, see YAML formatter from above
[/ui-tab] [ui-tab title="Serialize"]
# PHP Serialize
formatter:
  class: 'Grav\Framework\File\Formatter\SerializeFormatter'
  options:
    file_extension: '.ser'
    decode_options:
      allowed_classes: ['stdClass'] # List of allowed / safe classes during unserialize
[/ui-tab] [ui-tab title="INI"]
# INI
formatter:
  class: 'Grav\Framework\File\Formatter\IniFormatter'
  options:
    file_extension: '.ini'
[/ui-tab] [ui-tab title="CSV"]
# CSV
formatter:
  class: 'Grav\Framework\File\Formatter\CsvFormatter'
  options:
    file_extension: ['.csv', '.tsv']
    delimiter: ','      # Delimiter to separate the values
    mime: 'text/x-csv'  # MIME type for downloading file
[/ui-tab] [/ui-tabs]

You can also set default ordering, which is defined by key: ASC|DESC pairs:

config:
  data:
    # Ordering Options
    ordering:
      key: ASC
      timestamp: ASC

Finally, you can add search fields, which are looked at when you call collection.search():

config:
  data:
    search:
      # Fields to be searched
      fields:
        - last_name
        - first_name
        - email
      # Search Options
      options:
        - contains: 1   # If field contains the search string, assign weight 1 to the object

Fields contain a list of fields to be searched against.

Search options can be:

Name Value Description
case_sensitive true or false If true, all checks are case sensitive, defaults to false
same_as 0 ... 1 Value of the field must be identical to the search string
starts_with 0 ... 1 Value of the field must start with the search string
ends_with 0 ... 1 Value of the field must end with the search string
contains 0 ... 1 Value of the field must contain the search string

Search function returns 0 if the field does not match and weight between 0 and 1 if there is a match. Weight is used for ordering the search results. Object which gets the highest core has better match than one with a lower score.

Currently, search does not support having different weights or strategies per field.

Config > Admin

Admin section contains various configuration options to customize directory administration. It contains a few main sections: router, actions, permissions, menu, template and views.

config:
  # Admin Settings
  admin:
    # Admin router
    router: {}
    # Allowed admin actions
    actions: {}
    # Permissions
    permissions: {}
    # Admin menu
    menu: {}
    # Admin template type
    template: pages
    # Admin views
    views: {}

Optional router section can be used to customize the Flex Directory admin routes. Routing supports a base path, customizable routes for every action as well as redirects to handle for example backwards compatibility. All the paths are relative to admin base URL.

config:
  admin:
    # Admin router
    router:
      path: '/contacts' # Custom path to the directory
      actions:
        configure: # Action name
          path: '/contacts/configure' # New path to the action.
      redirects: # List of redirects (from: to)
        '/flex-objects/contacts': '/contacts'

Sometimes you want to restrict the administration to only display the entries or for example to only allow editing the existing ones. For this actions is where you can tweak the allowed CRUD operations to fit better your needs.

config:
  admin:
    # Allowed admin actions (for all users, including super user)
    actions:
      list: true   # Needs to be true (may change in the future)
      create: true # Set to false to disable creating new objects
      read: true   # Set to false to disable link to edit / details of the objects
      update: false # Set to false to disable saving existing objects
      delete: false # Set to false to disable deleting objects

Above example will prevent saving existing objects and deleting them for every user, including Super Admin.

Permissions section allows you to add new permission rules for Grav. These rules will appear in user/group admin. You can create as many permission rules as you wish, but you need to add your own logic or authorize rules in this file to use them.

config:
  admin:
    # Permissions
    permissions:
      # Primary permissions (used for the objects)
      admin.contacts:
        type: crudl # Create, Read, Update, Delete, List
        label: Contacts Directory
      # Secondary permissions (you need to assign these to a view, otherwise these will not be used)
      admin.configuration.contacts:
        type: default # Simple permission
        label: Contacts Configuration

If you do not want to display your directory in Flex Objects administration, one option is to display menu item in the main navigation. You can do just that in the menu section of the configuration.

config:
  admin:
    # Admin Menu
    menu:
      list:
        hidden: false # If true, hide the menu item.
        route: '/contacts' # Alias to `config.admin.router.path` if router path is not set.
        title: Contacts
        icon: fa-address-card-o
        authorize: ['admin.contacts.list', 'admin.super'] # Authorization needed to access the menu item.
        priority: 2 # Priority -10 .. 10 (highest goes up)

Above example creates Contacts menu item pointing to /admin/contacts.

When you're creating your own Flex Directories, you may sometimes want to share the same templates between all of your custom directories. You can do this with template:

config:
  admin:
    # Admin template type (folder)
    template: contacts

Flex Admin has multiple views to the objects. By default, following views are supported: list, edit, configure and optionally preview & export. It is possible to add your own views as well.

config:
  admin:
    views:
      # List view
      list: {}
      # Edit view
      edit: {}
      # Configure view
      configure: {}
      # Preview
      preview: {}
      # Data Export
      export: {}

List View

The first view you will need, is the one which lists all of your objects. By default list view uses VueTable and AJAX to paginate the objects. It needs a list of fields to display as well as options to define how many items are being shown at once as well as the default field used for ordering.

config:
  admin:
    views:
      # List view
      list:
        icon: fa-address-card-o
        title: Site Contacts
        fields: {}        # See below
        options:
          per_page: 20    # Default number of items per page
          order:
            by: last_name # Default field used for ordering
            dir: asc      # Default ordering direction

Icon and title are used to customize the icon and title of the listing page. Title supports also using Twig template by using following format:

        title:
          template: "{{ 'PLUGIN_CONTACTS.CONTACTS_TITLE'|tu }}"

Fields contains the fields you want to display in the directory listing. Each field has a key, which is the name of the field. Value can be omitted or it can contain the following configuration options:

Name Value Example Description
width integer 8 Width of the field in pixels
alias string 'header.published' Name of the form field to use. VueTable doesn't like dots in the names, so set alias for nested variables.
field array Form field override. Written just like any form field, but just without a key.
link string 'edit' Adds edit link to the text.
search boolean true Makes the field searchable in admin list.
sort array field: 'first_name' You can specify different value if you use different field name when querying data on the server side, e.g. first_name.
title_class string 'center' CSS classes used in titles.
data_class string 'left' CSS classes used in data columns.

Edit View

Edit view has the same basic configuration options as list view:

config:
  admin:
    views:
      # Edit view
      edit:
        icon: fa-address-card-o
        title:
          template: '{{ object.last_name ?? ''Last'' }}, {{ object.first_name ?? ''First Name'' }}'

Configure view

Configure view allows you to add directory wide configuration options, which can then be used in the template files.

config:
  admin:
    views:
      # Configure view
      configure:
        hidden: false # Configuration button can be hidden, for example if you have custom tab to replace it, like in Accounts.
        authorize: 'admin.configuration.contacts' # Optional custom authorize rule for this view.
        file: 'config://flex/contacts.yaml' # Optional file where the configuration is saved.

        icon: fa-cog
        title:
          template: "{{ directory.title }} {{ 'PLUGIN_ADMIN.CONFIGURATION'|tu }}"

Preview view

Flex also supports preview, though right now it works by rendering a page from the frontend, which can be defined in the blueprint file.

    # Preview View
    preview:
      enabled: true
      route:
        template: '/contacts' # Twig template to create URL. In this case we use the list view

       icon: fa-address-card-o
        title:
          template: "{{ object.form.getValue('title') ?? object.title ?? key }}"

Export view

All objects can be exported into a single file, here is an example configuration how to export data into YAML file:

    # Data Export
    export:
      enabled: true
      method: 'jsonSerialize'
      formatter:
        class: 'Grav\Framework\File\Formatter\YamlFormatter'
      filename: 'contacts'

Config > Site

config:
  # Site Settings
  site:
    templates:
      collection:
        # Lookup for the template layout files for collections of objects
        paths:
          - 'flex/{TYPE}/collection/{LAYOUT}{EXT}'
      object:
        # Lookup for the template layout files for objects
        paths:
          - 'flex/{TYPE}/object/{LAYOUT}{EXT}'
      defaults:
        # Default template variable {TYPE}; overridden by filename of this blueprint if template folder exists
        type: contacts
        # Default template variable {LAYOUT}; can be overridden in render calls (usually Twig in templates)
        layout: default

Template settings allow you to customize the template lookup paths and set the default type and layout name in the frontend.

Blueprints

Blueprints section defines the common configuration options for the whole Directory. The options allow you to customize a common directory to better suit the needs of the site without requiring manual editing of the files.

blueprints:
  # Blueprint for configure view.
  configure:
    # We are inside TABS field.
    fields:
      # Add our own tab
      compatibility:
        type: tab
        title: Compatibility
        fields:
          # Fields should be prefixed with object, collection etc..
          object.compat.events:
            type: toggle
            toggleable: true
            label: Admin event compatibility
            help: Enables onAdminSave and onAdminAfterSave events for plugins
            highlight: 1
            default: 1
            options:
              1: PLUGIN_ADMIN.ENABLED
              0: PLUGIN_ADMIN.DISABLED
            validate:
              type: bool

TIP: These configuration options can be modified in Configuration section of the Flex Directory Administration.

NOTE: Currently the only used configuration options are inside the cache section. For your custom settings, you need to add logic to use them by yourself.