Fi.php
Fi lets you query a collection of text files, as if the folder of files were a database (well, almost)., (*1)
Fi (rhymes with pie) is designed to be used as part of a static site generator., (*2)
Super quick start
There is a documented, runnable example you can play with:, (*3)
$ git clone https://github.com/yuanqing/fi
$ cd fi
$ composer install
$ php example/example.php
There are also tests., (*4)
Quick start
Suppose we have organised our text files into neat date-based folders like so:, (*5)
data/
|-- _defaults.md
`-- 2014/
|-- 01/
| |-- _defaults.md
| |-- 01-foo.md
| |-- 02-bar.md
| `-- ...
|-- 02/
| `-- ...
`-- ...
Each text file contains YAML frontmatter and content. The file 01-foo.md might be something like:, (*6)
---
title: foo title
---
foo content
We would query our data directory like so:, (*7)
$dataDir = 'data';
$filePathFormat = '{{ date.year: 4d }}/{{ date.month: 2d }}/{{ date.day: 2d }}-{{ title: s }}.md';
$collection = Fi::query($dataDir, $filePathFormat); #=> Collection object
Every file that matches the given $filePathFormat is a Document. A Collection, then, is simply an Iterator over a set of Documents:, (*8)
foreach ($collection as $document) {
$document->getFilePath(); #=> 'data/2014/01/01-foo.md', ...
$document->getField('title'); #=> 'foo title', ...
$document->getField('date'); #=> ['year' => 2014, 'month' => 1, 'day' => 1], ...
$document->getContent(); #=> 'foo content', ...
}
We can also access a Document directly by index:, (*9)
$document = $collection->getDocument(0); #=> Document object
$document->getFilePath(); #=> 'data/2014/01/01-foo.md'
$document->getField('title'); #=> 'foo title'
$document->getField('date'); #=> ['year' => 2014, 'month' => 1, 'day' => 1]
$document->getContent(); #=> 'foo content'
Map, filter, sort
Fi also supports map, filter, and sort operations over our Collection of Documents:, (*10)
# set the date to a DateTime object
$collection->map(function($document) {
$date = DateTime::createFromFormat('Y-m-d', implode('-', $document->getField('date')));
return $document->setField('date', $date);
});
# filter out Documents with date 2014-01-01
$collection->filter(function($document) {
return $document->getField('date') != DateTime::createFromFormat('Y-m-d', '2014-01-01');
});
# sort by date in descending order
$collection->sort(function($document1, $document2) {
return $document1->getField('date') < $document2->getField('date');
});
Default values
A text file will inherit default values (for fields or content) from any _defaults.md file found in the same directory, or in a parent directory. Defaults are said to cascade; _defaults.md files found further down the file hierarchy will overwrite those higher up the hierarchy., (*11)
API
Fi
Makes a Collection object., (*12)
$dataDir = './data';
$filePathFormat = '{{ year: 4d }}/{{ month: 2d }}/{{ date: 2d }}-{{ title: s }}.md';
$collection = Fi::query($dataDir, $filePathFormat);
-
$dataDir is the directory where Fi will look for text files that match the $filePathFormat.
-
$filePathFormat is specified using a Regex-like syntax; see Extract.php.
-
$defaultsFileName is the name of the text file that Fi will look for when resolving defaults.
-, (*13)
Collection
map ( callable $callback )
Applies the $callback to each Document in the Collection. Returns the Collection object., (*14)
# sets the title of all Documents to 'foo'
$collection->map(function($document) {
$document->setField('title', 'foo');
return $document;
}); #=> Collection
-
$callback takes a single argument of type Document. It must return an object of type Document.
filter ( callable $callback )
Filter out Documents in the Collection using the $callback. Returns the Collection object., (*15)
# filters out Documents with the title 'foo'
$collection->filter(function($document) {
return $document->getField('title') !== 'foo';
}); #=> Collection
-
$callback takes a single argument of type Document. Return false to exclude that Document from the Collection.
sort ( callable $callback )
Sorts the Collection using the $callback. Returns the Collection object., (*16)
# sorts by title in ascending order
$collection->sort(function($document1, $document2) {
return strnatcasecmp($document1->getField('title'), $document2->getField('title'));
}); #=> Collection
-
$callback takes two arguments of type Document. Return 1 if the first Document argument is to be ordered before the second, else return -1.
sort ( mixed $fieldName [, int $sortOrder = Fi::ASC ] )
Sorts the Collection by the $fieldName in the specified $sortOrder. Returns the Collection object., (*17)
# sorts by title in ascending order
$collection->sort('title', Fi::ASC); #=> Collection
# sorts by title in descending order
$collection->sort('title', Fi::DESC); #=> Collection
-
$sortOrder must be either Fi::ASC or Fi::DESC.
toArr ( )
Gets all the Documents in the Collection as an array., (*18)
$collection->toArr(); #=> [Document, Document, ...]
-, (*19)
Document
getFilePath ( )
Gets the file path of the text file (relative to the $dataDir) that corresponds to the Document., (*20)
$document->getFilePath(); #=> 'data/2014/01/01-foo.md'
getFields ( )
Gets all the fields of the Document., (*21)
$document->getFields(); #=> ['title' => 'foo', 'date' => ['year' => 2014, 'month' => 1, 'day' => 1]]
hasField ( mixed $fieldName )
Checks if the Document has a field with the specified $fieldName., (*22)
$document->hasField('title'); #=> true
getField ( mixed $fieldName )
Gets the value of the specified $fieldName., (*23)
$document->getField('title'); #=> 'foo'
setField ( mixed $fieldName, mixed $fieldValue )
Sets the field with $fieldName to the specified $fieldValue. Returns the Document object., (*24)
$document->setField('title', 'bar'); #=> Document
hasContent ( )
Checks if the Document content is non-empty., (*25)
$document->hasContent(); #=> true
getContent ( )
Gets the Document content., (*26)
$document->getContent(); #=> 'bar'
setContent ( string $content )
Sets the Document content to the specified $content. Returns the Document object., (*27)
$document->setContent('baz'); #=> Document
-, (*28)
Requirements
Fi requires at least PHP 5.3 or HHVM, and Composer., (*29)
Installation
-
Install Composer., (*30)
-
Install the Composer package:, (*31)
$ composer require yuanqing/fi ~0.2
-
In your PHP file, require the Composer autoloader:, (*32)
require_once __DIR__ . '/vendor/autoload.php';
Testing
You need PHPUnit to run the tests:, (*33)
$ git clone https://github.com/yuanqing/fi
$ cd fi
$ composer install
$ phpunit
License
MIT license, (*34)