PHPackages                             rokfor/rokfor-slim - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [API Development](/categories/api)
4. /
5. rokfor/rokfor-slim

ActiveProject[API Development](/categories/api)

rokfor/rokfor-slim
==================

Rokfor CMS: Headless CMS with JSON api

1114[8 issues](https://github.com/Rokfor/rokfor-slim/issues)[8 PRs](https://github.com/Rokfor/rokfor-slim/pulls)PHP

Since Feb 28Pushed 6mo ago2 watchersCompare

[ Source](https://github.com/Rokfor/rokfor-slim)[ Packagist](https://packagist.org/packages/rokfor/rokfor-slim)[ RSS](/packages/rokfor-rokfor-slim/feed)WikiDiscussions redis Synced today

READMEChangelogDependenciesVersions (12)Used By (0)

rokfor-slim
===========

[](#rokfor-slim)

Rokfor build based on [Slim Framework](http://slimframework.com/) for PHP. Rokfor is a api-first, data centristic content management. Its logic is based on somthing, that is all around us: Books and Magazines.

Overview
--------

[](#overview)

**Data Structure**

- Basic structure called *Books*, divided into parts, called *Chapters*
- Book exist as (multiple) instances called *Issues*
- Chapters contain data, called *Contributions*
- *Contributions* are collections of fields, defined in *Templates*

**Templates**

- Text: Multi-field arrays, RTF text, Markdown, plain text
- Tables: Dynamic rows and columns
- Numbers: Integer, Float or customizable Dates
- Locations: Including Google Maps and Location Pickers
- Image and Files: Automatically resize to multiple previews, keeping the original
- Select Boxes: Single, Multiple, Sortable. Various data relations (one-to-one, one-to-many based on foreign keys pointing to other Contributions, Books or Chapters)
- Sliders: Either one or two dimensional

**Users**

- Multi user setup
- Roles: Administrator, regular users
- Access to Chapters, Templates and Books defined by access groups.

**Api**

- Read only api with a bearer-key authentification
- Read/Write Api based on JWT Tokens
- CORS settings and IP restriction based on user profiles
- RESTful

**Installation**

- Installable via composer, using grunt and bower as build system
- Runs behind Nginx and Apache
- Uploads stored on the server or on a S3 service, suitable for cloud/load balanced installations
- Requires MySQL and (for best performance) Redis
- Deployable on EC2 instances (tested on Beanstalk), runs within Dokker (tested using Dokku) and Heroku

Rokfor is optimized for speed, although complex search queries over a large database can take quite a while. The problem lays in the nature of relational databases an the complexity of creating many-to-many relations between fields. Simple API calls are fast, since Rokfor implements caching methods on multiple levels:

- Optionally using Redis as key/value storage for repeating queries if no data changes happened.
- Using MySQL Cache tables if to speed up relational queries.

Binary uploads can either be stored locally on the server or pushed on a S3 compatible storage provider.

Rokfor works best with Nginx and supports proxy caching and X-Accel-Headers for fast file downloads.

[![Dashboard](https://github.com/Rokfor/rokfor-slim/raw/gh-pages/rokfor-screenshots/rf-dashboard.png)](https://github.com/Rokfor/rokfor-slim/blob/gh-pages/rokfor-screenshots/rf-dashboard.png)

Rokfor has already a longer history. The [old build](https://github.com/Rokfor/rokfor-cms)was mainly used to create printed matter. In order to make it more useful for the public, we decided to rewrite it completely applying a modern way of writing php applications:

- Composer install system
- AdminLTE backend theme
- Propel ORM

Setup and Installation
----------------------

[](#setup-and-installation)

### 1. Prerequisites

[](#1-prerequisites)

- MySQL Database: Server, username, password and database name
- PHP &gt;= 5.5
- [Composer](https://getcomposer.org)

### 2. Install Dependencies

[](#2-install-dependencies)

Clone the repository and install the dependencies with composer:

```
$ git clone https://github.com/Rokfor/rokfor-slim.git
$ cd rokfor-slim
$ composer install
$ composer update

```

### 3. Configuration

[](#3-configuration)

First, create copies of the database and settings configuration file. Rename or copy the \*.local.php to \*.php files:

```
$ cd config
$ cp database.local.php database.php
$ cp settings.local.php settings.php

```

The options in the **settings.php** file don't need to be changed as long as you keep the directory structure. Talking about **directories**: Make sure, that the webserver has access to the *udb* and *cache* folder:

```
public         _Webserver Document Root_
| index.php
| udb          _Default Storage directory, chmod r/w for the webserver_
| assets
config         _Configuration Files_
locale         _Localization Files, currently only german_
cache          _Template Cache_
src            _Rokfor PHP Runtime Sources_
vendor         _Composer Dependencies_
templates      _Jade Templates_
build          _Css and Javascript Sources_

```

Second, you need to change the database settings in **database.php**. To achieve that, you need to know the User, Password, Database and Server for your MySQL Account. If you enable **versioning** in the configuration file, all changes of contributions are tracked. This is useful in cases you want to keep the editing history. As a downside, it will create a lot of data. If you change the log **level** to \\Monolog\\Logger::DEBUG, all sql queries are logged. The path to the log file can be adjusted in the **log** setting.

```
// Database settings

return [
  'host'      => 'localhost',                     // Server Address
  'user'      => '',                              // User Name
  'pass'      => '',                              // Password
  'dbname'    => '',                              // Database Name
  'log'       => __DIR__ . '/../logs/propel.log', // Log File for Propel
  'level'     => \Monolog\Logger::ERROR,          // Error Level
  'versioning'=> false,                           // Store Versions of
                                                  // Contributions and Data
  //'socket'  => '/tmp/mysql.sock',               // Unix Socket, normally
                                                  // not needed
  //'port'    => 3306,                            // Port, if default not needed
];

```

Running Rokfor
--------------

[](#running-rokfor)

### PHP Server Mode (Debug)

[](#php-server-mode-debug)

```
$ cd rokfor-slim (base directory of the repository)
$ php -S 0.0.0.0:8080 -t public public/index.php

```

Now you should be able to browse to **** and log in with the default user **root** and password **123**.

### Apache

[](#apache)

There are 3 important things to keep in mind when running Rokfor with Apache:

1. Make sure that the webserver has read/write access to both **cache** und **udb** directory
2. The server's document\_root needs to point to the **public** directory. If you can not change this, rename the directory according to your server configuration and reconfigure the settings.php file.
3. **mod\_rewrite** is also necessary to redirect all traffic over **index.html**.

Building Rokfor
---------------

[](#building-rokfor)

Rokfor uses grunt to build and bower to install dependencies. Assuming you have installed node and npm:

```
$ npm install
$ bower install
$ grunt

```

The grunt task minifies the css files and creates the javascript bundles and copies all files into the public directory. Building is only needed if you want to develop and contribute something to Rokfor.

Get some Data: Read Only API
----------------------------

[](#get-some-data-read-only-api)

### Access Key

[](#access-key)

In order to access data, you need to set a user and define a read only api key in the user profile. Adding a user is only possible if you are signed in as root. There are two reasons why we use api keys for read only access. First, you can define which data is published, second, a key is not a password. Even by publishing a key, there's no way to log into the system and edit content.

Sending the key is done via a bearer authentification header or a access\_token query string. Sending a header is probably a better solution since the query string won't be too cluttered and the api key probably does not show up in the server log. The GET-call is probably a little bit more difficult to generate though.

```
GET /api/contributions/1/1?access_token=[key]

$ curl -H "Authorization: Bearer [key]" http://localhost:8080/api/contributions/1/1

```

### Current API Routes

[](#current-api-routes)

**Loading a collection of contributions with options:**

```
GET /api/contributions/:issueid|:issueid-:issueid.../:chapterid|:chapterid-:chapterid...?[options]

Options:

- query=string                                                (default: empty)
- filter=[id|date|sort|templateid[s]]:[lt[e]|gt[e]|eq|like]   (default: [omitted]:like)
- sort=[[id|date|name|sort]|chapter|issue|templateid[s]]:[asc|desc]           (default: sort:asc)
- limit=int                                                   (default: empty)
- offset=int                                                  (default: empty)
- data=[Fieldname|Fieldname|XX]                               (default: empty)
- populate=true|false                                         (default: false)
- verbose=true|false                                          (default: false)
- template=id                                                 (default: empty)
- status=draft|published|both                                 (default: published)

```

- Query: search for a string within the contribution name or the text fields Special queries: date:now is transformed into the current time stamp
- Filter: Applies the search string passed in query to certain fields, to the creation date, the contribution id or sort number. By default (if fields are omitted) the search query is applied to the name of the contribution and its content fields (full text search). Furthermore, the comparison can be defined with equal, less than, greater than or like (eq,lt,lte,gt,gte,like). Less and greater than does automatically cast a string to a number.
- Sort: Sort the results by id, date, name or manual sort number (sort) either ascending or descending. It is also possible to sort by a custom id of a template field. Contributions can also be sorted by chapter or issue. Please note: You need to choose between id, date, name and sort. You can add one custom sort field and the chapter and issue flag. i.E: sort=date|chapter|issue|23 would sort by date, chapter, issue and the custom field 23.
- Limit and Offset: Create pages with a length of \[limit\] elements starting at \[offset\].
- Data: Add additional field infos to the result set of a contributions. For example, you need the title field of a contribution already in the result set to create a multilingual menu. Or you need all images for a slideshow over multiple contributions.
- Populate: Sends all data (true). Equals data=All|Available|Fields
- Verbose: Send complete Information about a dataset. In most cases, this is too much and just slowing down the connection.
- Template: limit to a certain template id
- Status: Including draft contributions, published contributions or both. Open Contributions are never shown.

Examples:

GET /api/contributions/1/14-5?query=New+York

```
Searches for all contributions within issue 1 and chapters 14 and 5 for the String "New York".

```

GET /api/contributions/1/14-5?query=New+York&amp;filter=1|6:eq

```
Searches for all contributions within issue 1 and chapters 14 and 5 for the exact String "New York" within both fields with the template id 1 and 6.

```

GET /api/contributions/1/14-5?query=12&amp;filter=sort:gtlimit=1

```
Searches for all contributions within issue 1 and chapters 14 and 5 with a sort value > 12 and a limitation to 1 item. This represents the next contribution in a manually sorted list, since the list is has a default sort order by 'sort, asc'.

```

GET /api/contributions/1/14-5?query=12&amp;filter=sort:lt&amp;sort=sort:desc&amp;limit=1

```
Searches for all contributions within issue 1 and chapters 14 and 5 with a sort value < 12 and a limitation to 1 item, order descending. This represents the previous contribution in a manually sorted list.

```

GET /api/contributions/12/19?limit=10&amp;offset=20

```
Returns 10 contributions of issue 12 and chapter 19 starting after contribution 20.

```

GET /api/contributions/5-6-7/1-2-3?sort=date:desc&amp;data=Title|Subtitle

```
Returns all contributions of issue 5, 6 and 7 and chapter 1, 2 and 3 ordered by date, descending. Additionally, populates each contribution entry with the content of the fields Title and Subtitle.

```

GET /api/contributions/1/1?populate=true&amp;verbose=true

```
Returns all contributions of chapter 1 and issue 1. Adds all fields to each contribution and additionally prints a lot of information to each field and contribution.

```

GET /api/contributions/1/1?template=12

```
Returns all contributions of chapter 1 and issue 1 based on the template 12

```

**Loading a single contribution:**

```
GET /api/contribution/:id?[options]

Options:

- verbose=true|false                   (default: false)

```

- Verbose: Send complete Information about a dataset. In most cases, this is too much and just slowing down the connection.

Examples:

GET /api/contributions/12?verbose=true

```
Loads all available data from contribution with the id 12

```

**Structural Queries**

```
GET /api/books|issues|chapters/[:id]?[options]

Options:

- data=[Fieldname|Fieldname|XX]        (default: empty)
- populate=true|false                  (default: false)
- verbose=true|false                   (default: false)

```

- Data: Add additional field infos to the result set of a contributions. For example, you need the title field of a contribution already in the result set to create a multilingual menu. Or you need all images for a slideshow over multiple contributions.
- Populate: Sends all data (true). Equals data=All|Available|Fields
- Verbose: Send complete Information about a dataset. In most cases, this is too much and just slowing down the connection.

Examples:

GET /api/books

```
Shows all books available for the current api key

```

GET /api/chapters/3

```
Shows all information about chapter 3

```

GET /api/issue/2?verbose=true&amp;populate=true

```
Shows all information about issue 2. Additionally, raises the verbosity level and populates all data fields if a issue has backreferences to contributions.

```

Roadmap
-------

[](#roadmap)

In the current state, Rokfor is able to store and organize data. On the roadmap there are additional functions which will be implemented:

- Batch functions: Run custom actions over all contributions of a certain chapter.
- Field processors: Run an action when storing data.
- Exporters: Convert data into other formats (i.e. PDF)

Support
-------

[](#support)

[![browserstack](https://camo.githubusercontent.com/3fe5e889c5a848cec5bfa0e26414a9be66a57f6a4ae56adf4d0b56d6830456da/68747470733a2f2f7031342e7a6475736572636f6e74656e742e636f6d2f6174746163686d656e742f313031353938382f47596d626e63725079566b30543573444a314877456c7751683f746f6b656e3d65794a68624763694f694a6b615849694c434a6c626d4d694f694a424d54493451304a444c5568544d6a5532496e302e2e446d3152497538545648704d4561444d3579695136412e44435a7854466c4c72746c634941322d514f6c54794c4232374869384d565757385346724145616d4d67626e464a3041594f524a54646f5f65584c795a7a354d6550416d766a61676e3641744c6f66735470695a477a3136417a733933636d3059783678563472536d645f797663586f64726b4d6357554553353364634b3231744c3065554133316a7637464e593179305f4443517339305031486a6c5638546c656e3638724a4e6158632d4b6f636a3766426e7654696a365f327a47716b50517046387456676346395a79725a3855387241616131425f6e75344b4865777934434f6a726e6864414b325146443157466b676d5045374f694b516775576c4f343536696f7853556e464a686c4f5a44677456654a5170646a78586b452d76586f6a562d767135387354492e7852535a6e5f684a64722d35305659516845545a6677)](//browserstack.com)

Rokfor is using [Browserstack](//browserstack.com/) to test the dashboard code.

###  Health Score

28

—

LowBetter than 52% of packages

Maintenance32

Infrequent updates — may be unmaintained

Popularity10

Limited adoption so far

Community10

Small or concentrated contributor base

Maturity50

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/116976?v=4)[Urs Hofer](/maintainers/urshofer)[@urshofer](https://github.com/urshofer)

---

Top Contributors

[![urshofer](https://avatars.githubusercontent.com/u/116976?v=4)](https://github.com/urshofer "urshofer (757 commits)")

### Embed Badge

![Health badge](/badges/rokfor-rokfor-slim/health.svg)

```
[![Health](https://phpackages.com/badges/rokfor-rokfor-slim/health.svg)](https://phpackages.com/packages/rokfor-rokfor-slim)
```

###  Alternatives

[exsyst/swagger

A php library to manipulate Swagger specifications

35816.3M7](/packages/exsyst-swagger)[hubspot/api-client

Hubspot API client

24015.5M18](/packages/hubspot-api-client)[pocketmine/bedrock-protocol

An implementation of the Minecraft: Bedrock Edition protocol in PHP

172437.8k11](/packages/pocketmine-bedrock-protocol)[botman/driver-telegram

Telegram driver for BotMan

94452.6k6](/packages/botman-driver-telegram)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
