Festi CLI

Festi CLI is the name of the command-line interface included with Festi Framework. It provides a number of helpful commands for your use while developing your application.

To use CLI tools, you need to install the festi-team/festi-framework-cli package:

{
    "require": {
      "festi-team/festi-framework-cli": "dev-develop"
    }
}

Installer

The Installer tool enables you to install the framework automatically.

If you use a passphrase, you must first add your password to the keychain using /usr/bin/ssh-add -K.

Installation using Composer.

Follow these steps to install the framework:

  1. Create a composer.json file:
{
  "name": "your_company/project_name",
  "description": "Description",
  "repositories": [
    {
      "type": "composer",
      "url": "https://packages.festi.io/"
    }
  ],
  "require": {
    "php": ">=8.0",
    "festi-team/festi-framework-core": "dev-develop",
    "festi-team/festi-framework-database": "dev-develop",
    "festi-team/festi-framework-cli": "dev-develop"
  },
  "minimum-stability": "dev",
  "autoload": {
  "psr-4": {
    "": "src"
    }
  },
  "autoload-dev": {
    "psr-4": {
      "": ["tests"]
    }
  },
  "require-dev": {
    "phpunit/phpunit": "9.*",
    "phpunit/php-code-coverage": "9.*",
    "phan/phan": "4.x",
    "squizlabs/php_codesniffer": "3.*"
  }
}
  1. Run the following command to install dependencies:
composer install
  1. Remove composer.lock
  2. Run the following command to install the essential components for your project:
php ./vendor/bin/festi-install

Installation Types

You can choose from several installation types:

Type Description
dashboard installs the Jimbo system plugin, which is mainly for the administration panel (default).
site installs the Jimbo system plugin and the Contents plugin.
api installs the RESTful system plugin and sets up the framework to work as a RESTful API
rpc installs the Rpc system plugin and sets up the framework to work as a RPC API.
async installs the Festi Async Framework for creating asynchronous services for IoT, Game, Data Streaming, etc.

During installation, you will be prompted to install demo content. If you agree, basic settings and routing for login/registration will be created. In most projects, this is required, so it is recommended to agree.

Host Configuration

To properly configure the domain, it should either:

  1. Point directly to [PROJECT_NAME]/src/[dashboard|api|site|service|rpc], or
  2. Be set as a symbolic link to the appropriate directory.

Use the following command to create a symbolic link for the domain:

ln -s /path/to/your_project/src/dashboard /home/[USER_NAME]/my-domain.siter.festi.dev

or in the home directory:

ln -s your_project/src/dashboard my-domain.siter.festi.dev

Example Directory Structure

If your virtual host is configured to point to /home/[USER_NAME]/my-domain.siter.festi.dev, the directory structure should look like this:

/home/[USER_NAME]/
│── your_project/
│   ├── dumps/
│   ├── src/
│   │   ├── dashboard/
│   │   ├── api/
│   │   ├── site/
│   │   ├── service/
│   │   ├── rpc/
│   ├── ...
│── my-domain.siter.festi.dev -> your_project/src/dashboard

Install via console with options

Use the following command to install the framework via the console with options:

php vendor/bin/festi-install  --db_username [USERNAME] --db_password [PASSWORD] --db_name [NAME] --install_path [PATH]

Here are some available options:

Option Description
--db_username the database username.
--docker set to y to install with generate docker files.
--force is used to force the installation of the framework.
--install_path path to folder where you do want to install a project.
--install_type this option determines the type of installation to perform.
--db_host the hostname of the database server.
--db_username the username to use when connecting to the database.
--db_password the password to use when connecting to the database.
--db_name the name of the database to use.
--db_type the type of database to use, such as mysql or pgsql.
--db_port the port number to use when connecting to the database.
--timezone the timezone to use for the PHP installation.
--is_install_demo set to y to install basic settings and routing for login/registration .
--site_host the hostname of the site.
--dashboard_base_http the base URL of the dashboard.
--scm_host the hostname of the SCM repository.
--verbose a boolean value indicating whether or not to enable verbose output during installation.
--docker_php_version the version of PHP to use when installing with Docker.
--docker_server the server to use when installing with Docker.
--docker_swoole_version the version of Swoole to use when installing with Docker.
--docker_service_host the service host for async type of project when installing with Docker.
--docker_service_port the service port for async type of project when installing with Docker.

Override parameters vie environment variables

You can override parameters using environment variables. For example, you can set:

MYSQL_PATH - path to mysql client
export MYSQL_PATH=/usr/local/opt/mysql-client/bin/mysql

DSG Converter

Enables conversion of a database table to DGS (XML/Array (JSON)) and vice versa.

Usage

./vendor/bin/festi-dgs

Just answer the questions and get the result.

If you need to run with a different version of PHP:

/opt/php80/bin/php ./vendor/bin/festi-dgs

You can also launch it by specifying options:

./vendor/bin/festi-dgs --name users --path [PATH_TO_PROJECT] --definition-path [PATH_TO_DEFINITION_DIR] --type dgs --format xml

This will give you a dgs file [PATH_TO_DEFINITION_DIR]/users.xml created from the table with the name users.

./vendor/bin/festi-dgs --name active_users --definition-path [PATH_TO_DEFINITION_DIR] --type table

This will create a table with the name specified in the name option, using the DGS definition file [PATH_TO_DEFINITION_DIR]/active_users.xml to obtain the schema of the table.

Options Summary

Option Description
name table name
definition-path path to create or retrieve DGS definition file
path path to the project root (optional parameter, if not specified, the file will be searched for in the project root).
config path to the project config.php (optional parameter, if not specified, the file will be searched for in the project root).
type what to generate:
  • table - get table in database from XML
  • dgs - get XML/Array from an existing table
format output file format (xml/array) (optional parameter, defaults to xml). Only works when using dgs type.
primary-key column name for default primary key. Default value is id.

You can specify either an absolute path (e.g., /home/user/project) or a path relative to the project root (e.g., path/to/project).

Plugin Manager

The Plugin Manager allows creating plugins and their methods (including routing).

Modes

Mode Description
create Creates a folder for the plugin and everything necessary for it.
url Adds a method to the plugin and entries in the festi_url_rules and festi_url_rules2areas tables.
dgs Creates DGS, adds a method for displaying DGS to the plugin and entries in the festi_url_rules and festi_url_rules2areas tables.

Options Summary

Option Description
mode mode
name method's name or table/XML name
plugin plugin's name
config path to the project config.php (optional parameter, if not specified, the file will be searched for in the project root).
pattern RegExp expression for URL
type method type (default, json, ajax)
area the name of the route work area (pulled from festi_url_areas)

create mode

In this mode, a folder will be created for the plugin and everything necessary for it:

  • plugins/[PLUGIN_NAME]/[PLUGIN_NAME]Plugin.php
  • plugins/[PLUGIN_NAME]/[PLUGIN_NAME]Object.php
  • plugins/[PLUGIN_NAME]/init.php
  • plugins/[PLUGIN_NAME]/templates/
  • plugins/[PLUGIN_NAME]/tblDefs/

Examples

./vendor/bin/festi-plugin
- Enter the mode name - create - Enter the desired plugin name - Expenses

As a result, the following files will be obtained:

  • plugins/Expenses/ExpensesPlugin.php
  • plugins/Expenses/ExpensesObject.php
  • plugins/Expenses/init.php
  • plugins/Expenses/templates/
  • plugins/Expenses/tblDefs/

Settings can also be specified in launch parameters:

./vendor/bin/festi-plugin --mode create --name Expenses

In addition, the corresponding entry will be added to the festi_plugins table.

url mode

In this mode, will be created DGS, a method will be added to the plugin and entries in the festi_url_rules and festi_url_rules2areas tables.

Method types: - default - onDisplay[Name] - ajax - onAjax[Name] - json - onJson[Name]

Examples

./vendor/bin/festi-plugin
- Enter the mode name - url - Enter the plugin name - Incomes - Enter the URL rule - ~^/income/([0-9]+)/$~ - Enter the desired method name - Income - Enter the route work area - backend - Enter the method type - default

As a result, the plugin will receive a method:


    /**
     * @urlRule ~^/income/([0-9]+)/$~
     * @section none
     * @area backend
     * @userType user
     */
    public function onDisplayIncome(Response &$response)
    {
        // code ...

        return true;
    }

Parameters can also be specified in the launch arguments:

./vendor/bin/festi-plugin --mode url --plugin Incomes --pattern "~^/income/([0-9]+)/$~" --name Income --area backend --type default

dgs mode

In this mode, a method for displaying DGS will be added to the plugin and entries in the festi_url_rules and festi_url_rules2areas tables.

If the XML file is not available, it will be automatically generated from the database table using the DSG Converter.

Examples

./vendor/bin/festi-plugin
- Enter the mode name - dgs - Enter the table (DGS) name - users - Enter the plugin name - Users - Enter the desired URL - ~/admin/users/~

As a result, we will get a file: - plugins/Users/tblDefs/user.xml

And in the plugin, we will have a method:


    /**
     * @urlRule ~/admin/users/~
     * @section none
     * @area backend
     * @userType user
     */
    public function onDisplayUsers(Response &$response)
    {
        $store = $this->createStoreInstance("users");

        $store->onRequest($response);

        return true;
    }

Connecting to the database

By default, the config.php file located in the project root is used to establish a database connection. If you need to use a different file, you need to run the script with the config parameter:

./vendor/bin/festi-plugin --config="cron/config.php"

Database Migration

To migrate the database, follow these steps:

  1. Create a folder for dumps in the root of the project, for example, dump:
/dump/init.sql
/dump/updates1.sql
/dump/updates2.sql
/dump/updatesN.sql
  1. Use the ./vendor/bin/festi-migrate command:
./vendor/bin/festi-migrate

If the config.php file is not located in the root directory of the repository:

./vendor/bin/festi-migrate --path ./src/admin/
./vendor/bin/festi-migrate --path ./src/admin/ --dump ./dump/
./vendor/bin/festi-migrate --path ./src/admin/ --dump ./dump/ --backup ./backups/

If you need to update the crontab, create a file in the following format:

# CRONTAB
*/5 * * * * %PHP% %PROJECT_PATH%/crons/email_worker.php --id 2
*/5 * * * * %PHP% %PROJECT_PATH%/plugins/Queues/queues.php --id 3 --name Balance
*/5 * * * * %PHP% %PROJECT_PATH%/plugins/Queues/queues.php --id 4 --name Tasks

Then, run the migration with parameters for the crontab:

./vendor/bin/festi-migrate --crontab ./dump/crontab.txt --crontab-user user

You can also update the version of the project's static content (festi_settings->js_version) during the migration by using the --up-static-version option.

Using PHP Scripts for Database Migration

Sometimes pure SQL is insufficient for writing migration queries, especially when data needs to be corrected in production. For such cases, you can create an updatesN.php file containing a class named UpdatesN inherited from core\util\MigrationUpdates:

use core\util\MigrationUpdates;

class Updates2 extends MigrationUpdates
{
    protected function onStart(): void
    {
        $core = Core::getInstance();

        $search = array(
            'type' => 'catalog'
        );

        $sql = "SELECT * FROM contents";

        $catalogs = $core->db->select($sql, $search);

        $removeIDs = array();
        foreach ($catalogs as $row) {
            if (!empty($row['path']) && !file_exists($row['path'])) {
                $removeIDs[] = $row['id'];
            }
        }

        if ($removeIDs) {
            $search = array(
                'id&IN' => $removeIDs
            );

            $core->db->delete("contents", $removeIDs);
        }
    }
}

Merge Migrations Files

The festi-merge tool simplifies the process of combining multiple migration files into fewer, larger files. This is particularly helpful for improving the speed of database migrations during CI/CD deployments and unit testing.

Usage

To merge migration files, use the following command:

./vendor/bin/festi-merge --path ../../dumps

Options

  • --path: (Required) The path to the folder containing migration files.
  • --output: (Optional) The path where the merged files will be stored. If not specified, a merged folder will be created in the input folder.

By merging migration files: - Faster CI/CD Deployments: Consolidated files reduce execution time for database migrations. - Optimized Testing: Accelerates database setup during unit tests. - Improved Development Workflow: Reduces overhead in managing large numbers of migration files.

Utils

CliUtils

Helper class that supports printing messages to the console with a color scheme.

Usage

$tableName = CliUtils::cin("Table Name:");
CliUtils::i("Information");
$type = CliUtils::cin("What do you want to create?", array("a", "b"), "b");

Sometimes you need to mock output/input for unit tests:


CliUtils::$outputCallback = function ($message) {
};

CliUtils::$inputCallback = function (string $label, ?array $enum = null, string $default = '') {
    return 'test';
};

FAQ

PHP Version Error

If you encounter PHP version errors such as:

PHP Fatal error:  Composer detected issues in your platform: Your Composer dependencies require a PHP version ">= 8.0.2". You are running 5.4.16. in ...

There are two ways to resolve this:

  1. Update the PHP version on your server to meet the requirements.
  2. Use an environment variable to specify the path to the required PHP version:
export PHP_PATH="/php_path"

Unit Tests

Local

export DB_HOST=127.0.0.1
cd tests/
../vendor/bin/phpunit Tools/DgsConverterTest.php

Docker

cd tests/docker
docker-compose up -d --build
docker-compose run -e DB_HOST=festi-mysql-db php-cli /var/www/vendor/bin/phpunit -c /var/www/tests/phpunit.xml

SSH Key for docker
  1. Generate new SSH Key:
    cd tests/docker
    ssh-keygen -t rsa -b 2048 -C "[Ident]"
  2. Don't set passphrase.
  3. Add public key to Gitlab (https://gitlab.varteq.com/-/profile/keys)
  4. Add private key to docker build:
    php util_get_ssh_string.php
    SSH_PRIVATE_KEY="[KEY]" docker-compose up -d --build
  5. Run test:
    docker-compose run  -e DB_HOST=festi-mysql-db php-cli /var/www/vendor/bin/phpunit -c /var/www/tests/phpunit.xml /var/www/tests/Tools/DgsConverterTest.php

React Manager

React Manager is a utility that simplifies project creation and deployment workflows. It provides a set of commands that you can use to quickly create new projects from scratch, customize project settings, and deploy your code.

Modes

React Manager has two modes:

Mode Description
create This mode creates everything that is necessary for a new project, such as project directories, configuration files, and initial code.
deploy This mode deploys the project to target environment.

Options Summary

React Manager has several options that you can use to customize its behavior. Here is a summary of the available options:

Option Description
mode The mode that React Manager should run in (create or deploy).
path Specifies the path to the root of the project that React Manager should operate on. This is an optional parameter; if not specified, React Manager will search for the project in the current working directory.
name Specifies the name of the project.
config Specifies the path to the project's config.php file. This is an optional parameter; if not specified, React Manager will search for the file in the project root.
plugin Specifies the name of the plugin where necessary code will be appended.

Example

./vendor/bin/festi-react --mode deploy --name app --path [PATH_TO_PROJECT_DIR]

create mode

This mode creates everything necessary for the project and allows you to append the necessary data to the plugin and database to run the project in the browser.

Examples

To use this mode, run the following command:

./vendor/bin/festi-react

This will prompt you for the following information:

  • Enter the mode name - create
  • Enter the full project path. If you don't specify a path, the utility will use the current directory - /path/where/create/project/
  • Enter the project name - app
  • Enter y to initialize the project in the plugin and database - y
  • Enter the path to the config.php file - ../../../config.php
  • Enter the plugin name - Services
  • Enter the method name - Deafult
  • Enter the pattern URL - ~/services/~
  • Enter the area URL - backend
  • Enter the type of method - json

After you enter all the necessary information, run the following command to install the project dependencies:

npm install

Now you're ready to start working on your project!

deploy mode

This mode deploys the project. Your project should be builded.

Examples

To use this mode, run the following command:

./vendor/bin/festi-react

This will prompt you for the following information:

  • Enter the mode name - deploy
  • Enter the project path. If you don't specify a path, the utility will use the current directory - /path/where/create/project/
  • Enter the project name - app

If you created the project using the create mode, you can build the project by running the following command:

npm build

Locale Manager

Locale Manager is a command-line utility that simplifies the process of managing localization files for a project. It allows you to easily initiate a new po file and generate a mo file from it.

Modes

Locale Manager has two modes:

Mode Description
init Use this mode to create a new po file for your project. The utility will scan your project files and create a new po file with all the translatable strings it finds.
generate Use this mode to generate a mo file based on an existing po file. The utility will compile the po file into a mo file that can be used in your project.

Options Summary

Option Description
mode Specifies the mode that Locale Manager should run in (init or generate).
path Specifies the path to the root of the project that Locale Manager should operate on. This is an optional parameter; if not specified, Locale Manager will search for the project in the current working directory.
lang Specifies the language you want to create a mo file for. You can specify the language using its ISO 639-1 language code (e.g., en for English, fr for French).

init mode

This mode creates a new po file for your project. The utility will scan your project files with extention php, phtml, xml and create a new po file with all the translatable strings it finds. Also it gets caption from festi_menues and append to po file.

Examples

To use this mode, run the following command:

./vendor/bin/festi-locale --mode=init --path=/path/where/create/project/

This command will initiate a new po file for your project at the specified path at locale folder.

Or you can run the following command:

./vendor/bin/festi-locale

This will prompt you for the following information:

  • Enter the mode name - init
  • Enter the full project path. If you don't specify a path, the utility will use the current directory - /path/where/create/project/

generate mode

This mode generates a mo file based on an existing po file. The utility will compile the po file into a mo file that can be used in your project.

Examples

To use this mode, run the following command:

./vendor/bin/festi-locale --mode=generate --path=/path/where/create/project/ --lang=en

This command will generate a mo file for the English language in your project at the specified path at locale folder.

Or you can run the following command:

./vendor/bin/festi-locale

This will prompt you for the following information:

  • Enter the mode name - generate
  • Enter the full project path. If you don't specify a path, the utility will use the current directory - /path/where/create/project/
  • Enter the language - en