Develop Your First Package

Follow the guide below to gain a base understanding of Apex, and within minutes be up and running with your first published Apex package on your new SVN repository.

Install Apex

If Apex is not already installed, you may either use the standard installation guide, or simply use the four step Apex install by running the below commands. Please note, this does not require PHP to be installed on your machine.

git clone https://github.com/apexpl/apex
cd apex && mv install_example.yml install.yml
sudo docker-compose up -d
sudo docker-compose exec apex apex

That's it! Your new fully featured administration panel with various base packages can now be found at http://127.0.0.1/admin/

Various places in the below guide will ask you to run apex commands. If using Docker, you may access your container's bash prompt with the following command:

sudo docker-compose exec apex bash

Create and Configure Package

Let's develop out a quick package that provides random advice to our visitors, and saves the advice to the database. Run the command:

apex package create advisor

This will create the base structure and directories for the new package. In a text editor open the newly created file at ~/etc/Advisor/package.yml, and replace it with the following contents:

general:
  description: Random Advice Generator
  access: public
  price: 0

acl:
  branches: public
  releases: maintainers
  trunk: team

config:
  default_term: life

menus:

  admin_menus:
    area: admin
    type: parent
    position: after users
    icon: fa fa-fw fa-chat
    alias: advisor
    name: Advisor
    menus:
      view: View Advice

  admin_settings_page:
    area: admin
    parent: settings
    alias: advisor
    name: Advisor

Save and close the file, and run the command:

apex scan advisor

This will scan the contents of the package.yml file, and update the database accordingly. Refresh your administration panel, and you will notice the new menus that you defined.

Create Settings Page

Let's quickly develop out the new Settings->Advisor menu. Run the command:

apex opus admin-settings advisor admin/settings/advisor

You may now visit the Settings->Advisor menu within your administration panel, where you will be able to define the configuration variables added to the package.yml file. Naturally auto-generated code only goes so far, and the view for this menu can be found at the files:

  • /views/html/admin/settings/advisor.html
  • /views/php/admin/settings/advisor.php

Create Database and Model

We will also want to save all advice obtained to the database. Open the file at /etc/Advisor/install.sql, and enter the following contents:

CREATE TABLE advice (
    id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
    term VARCHAR(100) NOT NULL,
    advice_id INT NOT NULL, 
    advice TEXT NOT NULL,
    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);

Next, execute the SQL code against the database with the command:

apex migration install advisor

Alternatively, you may connect directly to the database and copy and paste the SQL code by running the sql command without any arguments:

apex sql

Next, create the model for the new database table with the command:

apex opus model Advisor/Models/Advice --dbtable advice --magic

Confirm creation of the parent directory when prompted, and this will create a new model class located at /src/Advisor/Models/Advice.php. Open the file, and you can see it's a straight forward PHP class that utilizes constructor property promotion, and has one property for each column in the database table. Due to adding the --magic flag in the above command, all properties can be accessed directly at $obj->prop_name and as you will notice there is no standard get / set methods within the class. If you would prefer to use the standard get / set methods simply omit the --magic flag from the above command, and they will be generated within he model class.

NOTE: Although it is highly recommended you write your database schemas in SQL, Apex does also have full support for Eloquent and Doctrine models and migrations if you prefer to use either of those. You may view full details in the Database section of the documentation.

Add Some Code

The /src/Advisor directory is your blank canvas where you may develop and structure anything you wish, and its root namespace is App\Advisor. For example, add a file to /src/Advisor/ApiClient.php with the following code:

<?php
declare(strict_types = 1);

namespace App\Advisor;

use Apex\Svc\HttpClient;    // PSR-18 compatible http client, defaults to Guzzle with installation.
use App\Advisor\Models\Advice;

class ApiClient
{

    #[Inject(HttpClient::class)]
    private HttpClient $http;

    /**
     * Get advice
     */
    public function getAdvice(string $term):?Advice
    {

        // Send HTTP request to Adviceslip API
        $res = $this->http->get("https://api.adviceslip.com/advice/search/$term");

        // Decode JSON
        if (!$json = json_decode($res->getBody()->getContents(), true)) { 
            throw new \Exception("Did not receive valid JSON as response.");
        }
        $slips = $json['slips'] ?? [];

        // Return null, if no results found
        if (count($slips) == 0) { 
            return null;
        }

        // Get random advice
        $slip = $slips[array_rand($slips)]; 

        // Add to database
        $advice = Advice::insert([
            'term' => $term,
            'advice_id' => $slip['id'],
            'advice' => $slip['advice']
        ]);

        // Return
        return $advice;
    }

}

This class contains one method called getAdvice() that simply sends a request to the free API service to obtain a random piece of advice. It then inserts the advice received into the database, and returns the new model instance created.

Create View

Now that we can get advice, we need to give it. Create a new view with the command:

apex create view advisor advice
echo "<h1>Advice for ~term~</h1> <p>Your advice is ~advice~</p>" > views/html/advice.html

This will create the new view and register it to the advisor package so it's included when publishing the package to the repository. Next, open the file at /boot/routes.yml, and add an additional line to the routes section:

routes:
    default: PublicSite
    "advice/:term": PublicSite

Simply add the new line "advice/:term": PublicSite to the routes.yml file, which signifies one dynamic path parameter is accepted for the /advice path.

Now open the file at /views/php/advice.php, and enter the following contents:

<?php
declare(strict_types = 1);

namespace Views;

use Apex\Svc\{App, View};
use App\Advisor\ApiClient;

/**
 * Render the template.
 */
class advice
{

    /**
     * Render
     */
    public function render(View $view, App $app, ApiClient $client):void
    {

        // Get term
        $default_term = $app->config('advisor.default_term');
        $term = $app->pathParam('term', $default_term);

        // Get advice
        $advice = $client->getAdvice($term);

        // Assign variables to view
        $view->assign('term', $term);
        $view->assign('advice', $advice->advice);
    }

}

That's it, now open your browser to http://127.0.0.1/advice/love or any term you wish to gain some insightful wisdom on!

The above view first retrives the term to search for from the URL being viewed, and if no term is specified, uses the default term as defined within the administration panel. It then makes the API call to retrieve the advice, and assigns the two template variables to display within the web browser.

Publish Your Package

Run the command:

apex commit advisor -m "Initial commit"

This will step you through the initial process to register your Apex account, and create the necessary keys for digital signatures and to access your repositories over SSH. It will only take a couple quick minutes, and upon completion your new repository can be found at:

[data-line=-1]
https://code.apexpl.io/your-username/advisor

Before you can install the package on other Apex systems, create a release with the command:

apex release create advisor 0.1

You will be prompted for your signing password, and upon success you can now instantly install the package on other Apex systems with the command:

apex install username/advisor

Congratulations, you've successfully developed and released your first Apex package! Apex also has full support for commercial and private packages, allowing you to instantly begin earning money from your code, or keep your code private as desired. If running your own repository is preferred, Apex Enduro is also available.

To continue, check out the various other available guides or the full developer documentation. If you ever need any assistance with Apex, you can always ask on the /r/apexpl sub Reddit.