Developing Custom Components with Git Repositories

Use Git Repositories to develop custom Oncord components in your own repository, then import and update them through the dashboard. A component can add its own data, business logic and admin screens to an Oncord website.

This tutorial covers Settings > Git Repositories (GitRepos), from connecting a repository to maintaining a component. The Oncord Real Estate example shows how the pieces fit together.

In this tutorial

Before you start

You will need access to Git Repositories in the Oncord dashboard, a Git repository you can read, and a working knowledge of PHP and Git. Use an Oncord test website while developing and testing changes.

Your repository contains executable PHP. Review the code you connect and give Oncord read access to the repository. Git Repositories pulls code into Oncord; make your changes in your local development checkout, then commit and push them to your Git host.

For a starting point, fork or clone Apps-RealEstate. Connect your own fork when you want to make changes. The reference repository uses the main branch.

git clone https://github.com/OncordSoftware/Apps-RealEstate.git
cd Apps-RealEstate

Connect a Git repository

  1. Open Settings > Git Repositories. The admin URL on your website is /admin/settings/developer/gitrepos/.
  2. Click Connect Git Repository.
  3. Select GitHub, GitLab, Bitbucket or Custom Git URL, then enter the repository URL.
  4. Choose an authentication method and complete the matching steps below.
  5. Enter the Branch you want Oncord to use. The form starts with main; change it if your repository uses a different branch.
  6. Choose whether to enable Auto-update every 6 hours. Leave this off while you want to control each update manually.
  7. Click Save & Import Git Repository. Oncord tests the connection before starting the import.
  8. Wait for the progress screen, then return to the repositories list and check the status. If the repository provides admin pages, open the new section and test it.

For the public reference component, use https://github.com/OncordSoftware/Apps-RealEstate.git, select None (public repository), and set the branch to main. Importing it creates the example component on that website, so use a test website for this walkthrough.

Choose an authentication method

SSH deploy key

SSH deploy key (recommended) is the default in the connection form. Oncord creates a key for the repository and displays its public key after you enter the URL.

  1. Select SSH deploy key (recommended).
  2. Click Copy Public Key.
  3. Open the repository settings link shown in the form. GitHub and GitLab call these deploy keys; Bitbucket calls them access keys.
  4. Add the public key to the repository with read access. Leave write access disabled.
  5. Return to Oncord and save the repository form.

An SSH clone URL looks like git@github.com:YOUR-ORGANISATION/YOUR-REPOSITORY.git. Keep the private key private; the public key displayed by Oncord is the part to add to your Git host. Deploy keys avoid the token expiry issue, but access still depends on the key remaining enabled at your Git host.

Access token

Select Access token and use an HTTPS repository URL. The fields change to match the selected provider:

ProviderWhat to enter
GitHubA fine-grained personal access token in GitHub Personal Access Token. Limit repository access to the required repository and grant Contents: Read-only.
GitLabThe deploy token username and password in Deploy Token Username and Deploy Token Password. The token needs read_repository access.
BitbucketYour Bitbucket username and an API token in Bitbucket Username and API Token. The repository read permission is read:repository:bitbucket.
Custom Git URLThe Git server username and password or access token, with read access to the repository.

Use the provider instructions linked from the Oncord form to create the token. If a token expires or is revoked, replace it by editing the repository in Oncord and saving the form again. Use the SSH option for an SSH URL.

Public repository

Select None (public repository) for a repository that can be cloned without credentials. Use its public HTTPS clone URL. A public repository still needs the correct URL and branch.

Understand the repository structure

Put the Components directory at the repository root. The directory path, PHP namespace, class name and filename must agree, including letter case. Oncord resolves a class to a file named after the final part of the class inside that class's directory.

For example, \Components\RealEstate\Listings lives at Components/RealEstate/Listings/Listings.inc.php, declares namespace Components\RealEstate;, and defines class Listings.

Components/
  RealEstate/
    _admin/
      entity.json
      entity.html
    Listings/
      Listings.inc.php
      _fields/
        realestate_listings.json
      _admin/
        entity.json
        entity.html
        entity.php
        edit/
          entity.json
          entity.html
        delete/
          entity.json
          entity.html
          entity.js

The reference component structure separates the PHP data component, database schema and admin interface. The parent RealEstate/_admin/ directory provides its top-level admin section.

  • _fields/ holds JSON table definitions.
  • _admin/ holds dashboard pages and their sub-routes.
  • _public/ is for assets that may be served to a browser, such as JavaScript, CSS and images.
  • _resources/ is for component resources that should not be directly web-accessible.

Use a namespace and table prefix specific to your organisation or app. When adapting an example, update the class references, table names, schema filename, admin URLs and page dependencies together. Renaming only the folder is not enough.

Build a small data component

A data component extends \Framework\Components\DataABC. The base class provides methods such as get(), getAll(), save() and delete(), as well as the installation lifecycle.

The following independent example stores projects. Create Components/Acme/Projects/Projects.inc.php:

<?php

namespace Components\Acme;

/**
 * @component_entity_type Project
 */
class Projects extends \Framework\Components\DataABC
{
    public static function dbGetTableName()
    {
        return 'acme_projects';
    }

    public static function fieldsGetPrimaryKey()
    {
        return 'project_id';
    }

    public static function fieldsGetPrefix()
    {
        return 'project_';
    }

    public static function getOrder()
    {
        return [['project_title', 'asc']];
    }
}

Create its matching schema at Components/Acme/Projects/_fields/acme_projects.json. The filename and table_id match dbGetTableName(), and the primary index matches fieldsGetPrimaryKey().

{
  "table_id": "acme_projects",
  "table_fields": [
    {
      "field_id": "project_id",
      "field_type": "int",
      "field_length": "11",
      "field_is_null": false,
      "field_default_value": null,
      "field_extra": "auto_increment"
    },
    {
      "field_id": "project_title",
      "field_type": "varchar",
      "field_length": "128",
      "field_is_null": false,
      "field_default_value": "",
      "field_extra": ""
    }
  ],
  "table_indexes": [
    {
      "index_id": "PRIMARY",
      "index_type": "primary",
      "index_fields": [
        "project_id"
      ]
    }
  ],
  "table_engine": "InnoDB",
  "table_collation": "utf8mb4_general_ci"
}

The inherited install() method reads this schema and creates or synchronises the component's table. This two-field example is a starting point for your own component; it does not include an admin interface yet.

After the repository has been imported, PHP can use the component like this:

$iProjectId = \Components\Acme\Projects::save([
    'project_title' => 'First project'
]);

$arrProject = \Components\Acme\Projects::get($iProjectId);

$arrProjects = \Components\Acme\Projects::getAll([
    'order' => [['project_title', 'asc']]
]);

save() returns the record's primary key. Pass that key in a later save to update the existing record. Use component methods for record changes so the framework's save and delete behaviour, including events, can run.

Put shared business rules in the component's _save() method and call parent::_save() when overriding it. Remember that callers can save only some fields of an existing record. The Real Estate Listings class demonstrates defaults, image and HTML field handling, and event handlers for page changes and contact merges.

Add an admin interface

Admin routes follow the component directory structure. For the reference app, Components/RealEstate/Listings/_admin/ provides /admin/realestate/listings/, and its edit/ directory provides /admin/realestate/listings/edit/.

Start from the reference app's admin pages and adapt them to your fields:

  • entity.json defines page metadata. Use "design_id": "-1" for the Oncord admin design. Check the page title, header actions and component dependencies when copying a page.
  • entity.html defines the interface with Oncord templates and controls.
  • entity.php can provide server-side page helpers.
  • entity.css and entity.js provide page-specific styling and behaviour when needed.

The reference edit form binds its form to \Components\RealEstate\Listings and binds individual inputs to columns with datacolumn. It includes property details, images and a contact selector. Its top-level page configuration also demonstrates a dependency on the Listings component.

Adding an admin screen does not automatically design a public listing page. Build your website's presentation separately with templates and the component API. See Forms and Working With PHP for the template and PHP foundations.

Install and update your component

When you import a repository, Oncord adds it to the PHP include paths, discovers component classes from their .inc.php files, calls their install() methods, and refreshes component and admin caches.

Installation runs again during updates. Custom installation code must be safe to run more than once. Call parent::install() when overriding installation for a data component, and guard any initial records or other setup so an update does not duplicate them. Keep the JSON schema in sync with your intended table structure and plan changes to existing data deliberately.

Manual updates

  1. Make and test the change in your development checkout.
  2. Commit and push it to the branch configured in Oncord.
  3. Return to Settings > Git Repositories and click Update beside the repository.
  4. Review the progress output and the repository's Status and Last Updated fields.
  5. Test the affected admin screens, saved records and public pages.

To change the branch, credentials or automatic update setting, open the repository and use Save & Update Git Repository.

Automatic updates

Auto-update every 6 hours schedules periodic updates. It does not deploy immediately when you push a commit. Use the manual Update action when you need to apply a change sooner. Only enable automatic updates on a branch whose changes are ready for that website.

Keep component names stable. The update process compares the component classes before and after the update and attempts to uninstall classes that have been removed. Treat removing or renaming a component as a data migration, and test it with a backup of the affected data.

Troubleshooting

SymptomWhat to check
Could not connect to the Git repositoryCheck the clone URL and repository access. For SSH, confirm the displayed public key was added to the correct repository. For tokens, check the token's access, expiry and provider fields.
The import or update cannot find the branchMake sure the branch exists on the remote repository and that the name in Oncord matches it. A branch that exists only on your computer has not been pushed yet.
The repository imports, but your component is missingCheck the root-level Components/ directory, filename, namespace and class spelling. Review the progress output for PHP errors.
Your admin page is missingCheck its _admin/ route, entity.json, admin design ID and component dependency. After correcting and pushing the files, update the repository and reload the admin page.
Changes have not appearedConfirm you pushed to the configured branch, run Update, and check the repository status. The automatic schedule runs every six hours.
Repository does not exist on the serverThe updater disables automatic updates for a missing repository. Correct the repository setup, verify a successful import or update, then explicitly re-enable automatic updates if required.

The repositories list displays OK or ERROR, with a recorded error message and time where available. Read the error details even if the progress screen says the update has finished. A Git status of OK does not replace testing your component's behaviour.

Removing a repository

Remove is an uninstall operation. Oncord calls the repository components' uninstall() methods, removes their automatic update schedule and deletes the repository checkout. The standard data component uninstaller drops its table and associated tables and removes its custom fields.

The removal dialog warns that component data will be permanently deleted and requires an acknowledgement. Back up any data you need before removing a repository. To pause automatic code changes, turn off Auto-update instead of removing the repository.

Reference material