Getting Started
- What is Flextype?
- Requirements
- Installation
- Configuration
- Folder Structure
- API Reference
- Code of Conduct
- Getting Help
- License
Core Concepts
Console
Rest API
Entries are the fundamental building blocks of your Flextype powered project. Entries are local flat files or external resources that can be represented as a PHP array inside the controllers, templates, etc...
Entries formats
Flextype support several flat files entries formats.
Frontmatter (.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.
For Frontmatter header you may define custom frontmatter header serializer as yaml
, json
, json5
or neon
by adding serializer name after first ---
.
Example:
---json
{
"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.
YAML (.yaml)
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
content: |
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.
NEON (.neon)
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"
content: '''
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.
'''
JSON (.json)
{
"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",
"content": "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."
}
JSON5 (.json5)
{
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",
content: "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."
}
Entries and Urls structure
All project entries are located in the project/entries
folder.
Each entry file should be placed in its idividual 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
movies/sg-1
# Slug
sg-1
# Physical Location
project/entries/movies/sg-1/season-5/entry.md
# ID
movies/sg-1/season-5
# Slug
season-5
# Physical Location
project/entries/movies/sg-1/season-5/episode-21/entry.md
# ID
movies/sg-1/season-5/episode-21
# Slug
episode-21
Fields
visibility
Entries 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.
Name | Default | Available values for option |
---|---|---|
visibility | visible |
visible , draft or hidden |
Example
---
title: My Entry Title
visibility: draft
---
My entry content here.
routable
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 data, but it is meant to be called directly by a plugin, another entry.
Name | Default | Available values for option |
---|---|---|
routable | true |
true or false |
Example
---
title: Commment42
routable: false
---
Content for Commment42
published_at
Allows you to specifically set a published_at
date associated with this entry.
Name | Default | Available values for option |
---|---|---|
published_at | Date & Time |
Examples
---
title: My Entry Title
published_at: '15-05-2020 06:57'
---
My entry content here.
published_by
Allows you to specifically set a published_by
User UUID associated with this entry.
Name | Default | Available values for option |
---|---|---|
published_by | User UUID |
Examples
---
title: My Entry Title
published_by: ea7432a3-b2d5-4b04-b31d-1c5acc7a55e2
---
My entry content here.
created_at
Allows you to specifically set a created_at date associated with this entry.
Name | Default | Available values for option |
---|---|---|
created_at | Date & Time |
modified_at
Allows you to specifically set a modified_at
date associated with this entry.
Name | Default | Available values for option |
---|---|---|
modified_at | Date & Time |
Examples
---
title: My Entry Title
modified_at: '15-05-2020 06:57'
---
My entry content here.
cache
By default, all entries are stored in the cache if flextype cache setting is true
.
But this can be changed by setting individual cache
for each entry.
Name | Default | Available values for option |
---|---|---|
cache | true or false |
slug
The field should be in 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.
Name | Default | Available values for option |
---|---|---|
slug | Entry Slug |
id
Name | Default | Available values for option |
---|---|---|
id | Entry ID |
You can define custom fields.
---
title: My Entry Title
description: My entry description
author:
twitter: "@_flextype"
---
My entry content here, author twitter: ] author.twitter ]
Examples
Get field author.twitter
and field content
in PHP.
//=> @_flextype
echo entries()->fetch('home')['author.twitter'];
//=> My entry content here, author twitter: @_flextype
echo entries()->fetch('home')['content'];
Directives
Directive | Description |
---|---|
shortcodes | Parse shortcodes text inside current field. |
markdown | Parse markdown text inside current field. |
textile | Parse textile text inside current field. |
php | Execute php code inside current field. |
type | Set current field type. |
$[] | Evaluate expression. |
Directives Details
shortcodes
Parse shortcodes text inside current field.
Examples
---
discount: "@shortcodes (strings random)"
---
markdown
Parse markdown text inside current field.
Examples
---
text: "@markdown **bold text here**"
---
textile
Parse textile text inside current field.
Examples
---
text: "@textile **bold text here**"
---
php
Execute php code inside current field.
Examples
---
text: "@php echo 'Hello World';"
---
type
Set current field type.
Available types: int
, integer
, float
, bool
, boolean
, array
, json
, collection
, null
and string
.
Examples
−−−
_vars:
title: "GT Fury"
currency: "USD"
vat: '@type[int] (strings random: "2,1234567890)"'
title: "$[ _vars.title ]"
price: "(calc:'100+$[ _vars.vat ]' )"
price_with_currency: "$[ price ] $[ _vars.currency ]"
−−−
GT Fury content here...
$[ ] @[ ] #[ ]
Evaluate expression.
price: "$[ 100 + var('vat') ]"
message: "$[ field('price') > 100 ? 'Price is greater than 100' : 'Price is less than 100' ]"
content: |
#[ This is comment ]
@[ entries().create('movies/sg-1/season-5/episode-23', {}) ]
Macros
entries
Examples
macros:
entries:
fetch:
posts:
id: blog
options:
collection: true
find: []
filter: []
post:
id: blog/post-1
options:
filter: []
testimonials:
id: testimonials
registry
Examples
macros:
registry:
get:
flextype:
id: flextype.manifest.name
author.name:
id: flextype.manifest.author.name
license:
id: flextype.manifest.license
php
Examples
title: Blog
macros:
php: |
$entry = entries()->registry()->get('methods.fetch');
$entry['result']['posts'] = entries()->fetch('blog', ['collection' => true, 'filter' => ['sort_by' => ['key' => 'date', 'direction' => 'ASC']]])->toArray();
entries()->registry()->set('methods.fetch', $entry);
Expressions
Flextype uses Symfony Expression Language Component, which provides an engine that can compile and evaluate expressions.
The purpose of using this component is to allow developers to use expressions inside entries, configurations, etc.. more complex logic than just flat data.
The idea is to let the developers of Flextype powered projects do some business logic inside entries fields without using PHP or introducing security problems.
Expressions can be seen as a very restricted PHP sandbox and are immune to external injections as you must explicitly declare which variables are available in an expression.
Examples
---
vars:
title: "GT Fury"
currency: "USD"
vat: "@type[int] $[ strings().random(2, 1234567890) ]"
title: "$[ var('title') ]"
price: "$[ 100 + var('vat') ]"
message: "$[ field('price') > 100 ? 'Price is greater than 100' : 'Price is less than 100' ]"
random: "$[ strings().random() ]"
---
### Price
$[ field('price') ]
### Message
$[ field('message') ]
### Random
$[ field('random') ]
Learn more about Symfony Expression Language Component
Functions
Function | Description |
---|---|
actions | Get actions service. |
entries | Get entries service. |
collection | Create a new arrayable collection object from the given elements. |
collectionFromJson | Create a new arrayable collection object from the given JSON string. |
collectionFromString | Create a new arrayable collection object from the given string. |
collectionWithRange | Create a new arrayable object with a range of elements. |
collectionFromQueryString | Create a new arrayable object from the given query string. |
filterCollection | Filter collection. |
const | Get php constant. |
var | Get entry var. |
field | Get entry field. |
csrf | Get csrf hidden input. |
filesystem | Get filesystem instance. |
tr | Returns translation of a string. If no translation exists, the original string will be returned. No parameters are replaced. |
__ | Returns translation of a string. If no translation exists, the original string will be returned. No parameters are replaced. |
parsers | Get parsers service. |
serializers | Get serializers service. |
slugify | Get slugify service. |
strings | Get strings instance. |
registry | Get registry service. |
urlFor | Get the url for a named route. |
fullUrlFor | Get the full url for a named route. |
isCurrentUrl | To determine is current url equal to route name. |
getCurrentUrl | To get current path on given Uri. |
getBasePath | To get the base path. |
getBaseUrl | To get the base url. |
getAbsoluteUrl | To get the absolute url. |
getProjectUrl | To get the project url. |
getUriString | To get the uri string. |
redirect | To create redirect. |
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.
*
* @return mixed Returns mixed results from APIs or default is an instance of The Collection class with founded items.
*
* @access public
*/
public function fetch(string $id, array $options = [])
Fetch single entry
Examples
Fetch single entry movies/sg-1/season-5/episode-21
$data = entries()->fetch('movies/sg-1/season-5/episode-21');
Fetch singe entry in movies/sg-1/season-5/episode-21
and send $options
.
$data = 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 only items.
'only' => [],
// Extract except
'except' => [],
// 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 = entries()->fetch('movies/sg-1/season-5', $options);
Fetch collections of entries in movies/sg-1
and send $options
.
$data = 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.'
];
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'];
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
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
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
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.
*
* @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 (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.
*
* @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 = 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.
*
* @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 = 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.
entries()::macro('fetchRecentPosts', function($limit = 10) {
return entries()
->fetchCollection('blog')
->sortBy('publised_at')
->limit($limit);
});
// Display recent posts.
foreach (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 entries()
->fetchCollection('blog')
->sortBy('publised_at')
->limit($limit);
}
}
}
// Create new mixin BlogMixin with it is macros.
entries()::mixin(new BlogMixin());
// Display recent posts.
foreach (entries()->fetchRecentPosts(5) as $post) {
echo $post['title'] . "\n";
}