Styling console applications based on Symfony, Laravel, CakePHP, and other PHP Frameworks!

Entries are the fundamental building-blocks of your project. We are using jekyll like entries format. It means that each entry in the Flextype should contains Entry Front Matter block in valid YAML format at the top of the file and Entry Content marked up using HTML + Markdown + Shortcodes and etc... at the bottom of the file.

Here is a simple entry example:

project/entries/movies/sg-1/season-5/episode-21/entry.md
---
title: Meridian
description: As Jackson suffers from a fatal dose of radiation, he struggles with the value of his life while his friends deal with the emotional and diplomatic repercussions.
director: William Waring
writers: Brad Wright, Jonathan Glassner
stars: Richard Dean Anderson, Michael Shanks, Amanda Tapping
---
SG-1 returns from an off-world mission to P9Y-3C3 with Daniel Jackson suffering from what is likely a fatal dose of radiation. On the planet, they dealt with the country of Kelowna and their representative Jonas Quinn. That country was at the same stage of development as the United States in the 1940s and well on their way to creating an atomic weapon using Goa'uld technology found in an ancient temple. Daniel argued against the Kelownans developing such a weapon and is accused of attempting to sabotage the project. As members of the team sit by his deathbed, Daniel receives an unexpected offer from someone they once met off-world.

Between triple-dashed lines, you can set predefined variables or even create custom ones of your own.

Entries and Urls structure in Flextype

All content entries are located in the project/entries/ folder.

Each entry file entry.md should be placed in its own folder.

Folder names should also be valid slugs. Slugs are entirely lowercase, with accented characters replaced by letters from the Latin alphabet and whitespace characters replaced by a dash or an underscore, to avoid being encoded.

Examples
# Physical Location
project/entries/movies/sg-1/entry.md

# ID (URL)
movies/sg-1

# Slug
sg-1
# Physical Location
project/entries/movies/sg-1/season-5/entry.md

# ID (URL)
movies/sg-1/season-5

# Slug
season-5
# Physical Location
project/entries/movies/sg-1/season-5/episode-21/entry.md

# ID (URL)
movies/sg-1/season-5/episode-21

# Slug
episode-21

Default Variables

There are a number of default entry variables available for each entry and defined in the Front Matter section.

Visibility
Name Default Available values for option
visibility visible visible or draft or hidden

Content visibility is about controlling who can see your entries. Flextype allows you to control the visibility of your entries on an individual basis. By default, all entries are visible.

Examples

---
title: My Entry Title
visibility: draft
---
My entry content here.
Routable
Name Default Available values for option
routable true true or false

By default, all entries are routable. This means that they can be reached by pointing your browser to the URL of the entry. However, you may need to create a specific entry to hold specific content, but it is meant to be called directly by a plugin, other content, or even a theme directly.

Examples

---
title: Commment42
routable: false
---
Content for Commment42
Published at
Name Default Available values for option
published_at Date & Time

This variable allows you to specifically set a published_at date associated with this entry.

Examples

---
title: My Entry Title
published_at: '15-05-2020 06:57'
---
My entry content here.
Published by
Name Default Available values for option
published_by User UUID

This variable allows you to specifically set a published_by User UUID associated with this entry.

Examples

---
title: My Entry Title
published_by: ea7432a3-b2d5-4b04-b31d-1c5acc7a55e2
---
My entry content here.
Created at
Name Default Available values for option
created_at Date & Time

This variable allows you to specifically set a created_at date associated with this entry.

Modified at
Name Default Available values for option
modified_at Date & Time

This variable allows you to specifically set a modified_at date associated with this entry.

Examples

---
title: My Entry Title
modified_at: '15-05-2020 06:57'
---
My entry content here.
Parsers
Name Default Available values for option
parsers A list of parsers with options
parsers:
  markdown:
    enabled: true
    fields: ['content', 'title']
  shortcodes:
    enabled: true
    fields: ['content', 'title', 'description']
Cache
Name Default Available values for option
cache true or false

By default, all entries are stored in the cache if flextype cache is true. But this rule can be changed by setting individual cache for each entry.

Slug
Name Default Available values for option
slug Slug is entirely lowercase, with accented characters replaced by letters from the Latin alphabet and whitespace characters replaced by a dash or an underscore, to avoid being encoded.
Id
Name Default Available values for option
id Entry ID
Entries
Name Default Available values for option
entries
entries:
  fetch:
    posts:
      id: blog
      options:
        collection: true
        find: []
        filter: []
    post:
      id: blog/post-1
      options:
        filter: []
    testimonials:
      id: testimonials
      options:
        method: fetchTestimonials
Media
Name Default Available values for option
media
media:
  files:
    fetch:
      albums:
        id: albums
        options:
          collection: true
          filter: []
      foo:
        id: albums/album-1/foo.jpg
        options:
          filter: []
      other:
        id: other
        options:
          method: fetchFromOtherDB
  folders:
    fetch:
      albums:
        id: albums
        options:
          collection: true
          filter: []
      foo:
        id: albums/album-1/foo.jpg
        options:
          filter: []
      other:
        id: other
        options:
          method: fetchFromOtherDB
Registry
Name Default Available values for option
registry
registry:
  get:
    flextype:
      key: flextype.manifest.name
    author.name:
      key: flextype.manifest.author.name
    license:
      key: flextype.manifest.license

Custom Variables

You can create your own custom entry variables using any valid YAML syntax. These would be entry-specific variable and be available for Rest API and any extension such as plugin, theme and etc...

project/entries/home/entry.md
---
title: My Entry Title
description: My entry description
author:
  twitter: "@getflextype"
---
My entry content here.

Examples

Get variable author.twitter with PHP.

echo flextype('entries')->fetch('home')['author.twitter'];

Get variable author.twitter with Rest API.

GET /api/entries?id=home&token=YOUR_ENTRIES_TOKEN

Get variable author.twitter with TWIG Plugin.

{{ entries.fetch('home').author.twitter }}

Methods

Method Description
fetch Fetch entry or entries collection.
create Create entry
update Update entry
move Move entry
copy Copy entry
delete Delete entry
has Check whether entry exists
getFileLocation Get entry file location
getDirectoryLocation Get entry directory location

Methods Details

fetch

Fetch entry or entries collection.

/**
 * Fetch.
 *
 * @param string $id      Unique identifier of the entry.
 * @param array  $options Options array.
 *
 * @access public
 *
 * @return self Returns instance of The Arrays class.
 */
public function fetch(string $id, array $options = []): Arrays
Fetch single entry

Examples

Fetch single entry movies/sg-1/season-5/episode-21

$data = flextype('entries')->fetch('movies/sg-1/season-5/episode-21');

Fetch singe entry in movies/sg-1/season-5/episode-21 and send $options.

$data = flextype('entries')->fetch('movies/sg-1/season-5', $options);

$options is an array of valid values for filter helper.

$options = [
    'filter' => [
        // Return items.
        // Valid values: all, first, last, next, random, shuffle
        'return' => 'all',

        // Filters the array items by a given condition.
        // key - of the array or object to used for comparison.
        // operator - used for comparison.
        //    operators: in, nin, lt, <, lte,
        //         >, gt, gte, >=, contains, ncontains
        //         >=, <=, like, nlike, regexp, nregexp,
        //         eq, =, neq, !=, starts_with,
        //         ends_with, between, nbetween, older, newer
        // value - Value used for comparison.
        'where' => [
            [
                'key' => '',
                'operator' => '',
                'value' => '',
            ],
            [...],
            [...],
        ],

        // Group by key
        'group_by' => '',

        // Sort by key and direction.
        // Order direction: DESC (descending) or ASC (ascending)
        'sort_by' => [
            'key' => '',
            'direction' => 'ASC'
        ],

        // Extract a slice of the current array with specific offset.
        'offset' => 0,

        // Extract a slice of the current array with offset 0 and specific length.
        'limit' => 10,
    ],
];
Fetch entries collection

Examples

Fetch collections of entries episodes in movies/sg-1/season-5

$data = flextype('entries')->fetch('movies/sg-1/season-5', $options);

Fetch collections of entries in movies/sg-1 and send $options.

$data = flextype('entries')->fetch('movies/sg-1/season-5', $options);

$options is an array of valid values for find and filter helpers.

$options = [
    'collection' => true,

    'find' => [
        // Restrict the depth of traversing
        // https://symfony.com/doc/current/components/finder.html#directory-depth
        'depth' => ['> 1', '< 5'],

        // Restrict by a date range
        // https://symfony.com/doc/current/components/finder.html#file-date
        'date' => ['>= 2018-01-01', '<= 2018-12-31'],

        // Restrict by a size range
        // https://symfony.com/doc/current/components/finder.html#file-size
        'size' => ['>= 1K', '<= 2K'],

        // Exclude directories from matching
        // https://symfony.com/doc/current/components/finder.html#location
        'exclude' => 'directory',

        // Find files by content
        // https://symfony.com/doc/current/components/finder.html#file-contents
        'contains' => '',

        // Find files by content excludes files containing given pattern
        // https://symfony.com/doc/current/components/finder.html#file-contents
        'not_contains' => '',

        // Filter results with your own strategy
        // https://symfony.com/doc/current/components/finder.html#custom-filtering
        'filter' => 'CALLBACK_FUNCTION',

        // Sort results by your own sorting algorithm
        // https://symfony.com/doc/current/components/finder.html#sorting-results
        'sort' => 'CALLBACK_FUNCTION',

        // Find files and directories by path
        // https://symfony.com/doc/current/components/finder.html#path
        'path' => 'data',

        // Sort the files and directories by the last accessed, changed or modified time
        // Values: atime, mtime, ctime
        // https://symfony.com/doc/current/components/finder.html#sorting-results
        'sort_by' => 'atime',
    ],

    'filter' => [
        // Return items.
        // Valid values: all, first, last, next, random, shuffle
        'return' => 'all',

        // Filters the array items by a given condition.
        // key - of the array or object to used for comparison.
        // operator - used for comparison.
        //    operators: in, nin, lt, <, lte,
        //         >, gt, gte, >=, contains, ncontains
        //         >=, <=, like, nlike, regexp, nregexp,
        //         eq, =, neq, !=, starts_with,
        //         ends_with, between, nbetween, older, newer
        // value - Value used for comparison.
        'where' => [
            [
                'key' => '',
                'operator' => '',
                'value' => '',
            ],
            [...],
            [...],
        ],

        // Group by key
        'group_by' => '',

        // Sort by key and direction.
        // Order direction: DESC (descending) or ASC (ascending)
        'sort_by' => [
            'key' => '',
            'direction' => 'ASC'
        ],

        // Extract a slice of the current array with specific offset.
        'offset' => 0,

        // Extract a slice of the current array with offset 0 and specific length.
        'limit' => 10,
    ],
];
create

Create entry.

/**
 * Create entry.
 *
 * @param string $id   Unique identifier of the entry.
 * @param array  $data Data to create for the entry.
 *
 * @return bool True on success, false on failure.
 *
 * @access public
 */
public function create(string $id, array $data = []): bool

Examples

Create new entry episode-22 in movies/sg-1/season-5

$data = [
                'title' => 'Revelations',
                'description' => 'While still dealing with the loss of Daniel Jackson the SGC is contacted by the Asgard who require assistance dealing with Anubis, who seems to have new shield technology that can repel Asgard weapons.',
                'director' => 'Martin Wood',
                'writers' => 'Brad Wright, Jonathan Glassner',
                'stars' => 'Richard Dean Anderson, Michael Shanks, Amanda Tapping',
                'content' => 'Osiris engages in space combat with Thor over a violation of the protected planets treaty. Freyr arrives at the SGC bringing news of Thor\'s death and asking SG-1 to mount a rescue mission to retrieve an Asgard scientist from the planet in question. Upon their arrival Heimdall informs them that Thor still lives and has been taken captive by the Goa\'uld. O\'Neill and Teal\'c transport over to the mothership to rescue him from the clutches of Anubis.'
        ];


flextype('entries')->create('movies/sg-1/season-5/episode-22', $data);
update

Update entry.

/**
 * Update entry
 *
 * @param string $id   Unique identifier of the entry.
 * @param array  $data Data to update for the entry.
 *
 * @return bool True on success, false on failure.
 *
 * @access public
 */
public function update(string $id, array $data): bool

Examples

Update entry episode-22 in movies/sg-1/season-5

$data = ['soundtracks' => 'Joel Goldsmith'];


flextype('entries')->update('movies/sg-1/season-5/episode-22', $data);
move

Move entry.

/**
 * Move entry
 *
 * @param string $id    Unique identifier of the entry.
 * @param string $newID New Unique identifier of the entry.
 *
 * @return bool True on success, false on failure.
 *
 * @access public
 */
public function move(string $id, string $newID): bool

Examples

Move entry episode-22 to episode-23 in movies/sg-1/season-5

flextype('entries')->move('movies/sg-1/season-5/episode-22',
                          'movies/sg-1/season-5/episode-23');
copy

Copy entry.

/**
 * Copy entry.
 *
 * @param string $id    Unique identifier of the entry.
 * @param string $newID New Unique identifier of the entry.
 *
 * @return bool|null True on success, false on failure.
 *
 * @access public
 */
public function copy(string $id, string $newID): ?bool

Examples

Copy entry episode-23 to episode-22 in movies/sg-1/season-5

flextype('entries')->rename('movies/sg-1/season-5/episode-23',
                                       'movies/sg-1/season-5/episode-22');
delete

Delete entry.

/**
 * Delete entry.
 *
 * @param string $id Unique identifier of the entry.
 *
 * @return bool True on success, false on failure.
 *
 * @access public
 */
public function delete(string $id): bool

Examples

Delete entry episode-23 in movies/sg-1/season-5

flextype('entries')->delete('movies/sg-1/season-5/episode-23');
has

Check whether entry exists.

/**
 * Check whether entry exists
 *
 * @param string $id Unique identifier of the entry(entries).
 *
 * @return bool True on success, false on failure.
 *
 * @access public
 */
public function has(string $id): bool

Examples

Check whether entry episode-23 exists in movies/sg-1/season-5

if (flextype('entries')->has('movies/sg-1/season-5/episode-23')) {
    // do something...
}
getFileLocation

Get entry file location

/**
 * Get entry file location
 *
 * @param string $id Unique identifier of the entry(entries).
 *
 * @return string entry file location
 *
 * @access public
 */
public function getFileLocation(string $id): string

Examples

Check whether entry episode-23 exists in movies/sg-1/season-5

$data = flextype('entries')->getFileLocation('movies/sg-1/season-5/episode-23');
getDirectoryLocation

Get entry directory location

/**
 * Get entry directory location
 *
 * @param string $id Unique identifier of the entry(entries).
 *
 * @return string entry directory location
 *
 * @access public
 */
public function getDirectoryLocation(string $id): string

Examples

Get entry episode-23 exists in movies/sg-1/season-5

$data = flextype('entries')->getDirectoryLocation('movies/sg-1/season-5/episode-23');

Extending

Entries are "macroable", which allows you to add additional methods to the Entries API at run time.

For example, the following code adds a fetchRecentPosts() method to the Entries API.

Examples

// Create new macros for fetch recent posts.
flextype('entries')::macro('fetchRecentPosts', function($limit = 10) {
    return flextype('entries')
                ->fetchCollection('blog')
                ->sortBy('publised_at')
                ->limit($limit);
});

// Display recent posts.
foreach (flextype('entries')->fetchRecentPosts(5) as $post) {
    echo $post['title'] . "\n";
}

As you can see, the macro method takes as arguments a name and an anonymous function to call (optionally, you able to add additional arguments, if you need that).

When you call a macro, your code in function would be called from the context of that class (in the example it is Entries API class context), allowing you to execute your code along with Flextype built-in features.

Using mixins

Macros awesome, and you may want to use a lot of them. You may group them with help of mixins. For this approach, you should use a mixin static method on the macroable Entries API class, and pass your mixin class as an argument.

Examples

// Blog Mixin Class.
class BlogMixin {
    public function fetchRecentPosts() {
        return function($limit = 10) {
            return flextype('entries')
                        ->fetchCollection('blog')
                        ->sortBy('publised_at')
                        ->limit($limit);
        }
    }
}

// Create new mixin BlogMixin with it is macros.
flextype('entries')::mixin(new BlogMixin());

// Display recent posts.
foreach (flextype('entries')->fetchRecentPosts(5) as $post) {
    echo $post['title'] . "\n";
}