Skip to content

Import remote functions

In addition to loading functions locally from your filesystem, Castor can also import external functions remote resources. This document explains how to achieve this.

Warning

Remote imports is in an experimental state and may change in the future.

Installing remote packages

When importing functions from a remote resource, Castor will use Composer to download the packages and store them in .castor/vendor/.

To import functions, you need to create a castor.composer.json file next to the castor.php file (either at the root of your project or in the .castor/ directory).

This also can be done by running the castor composer init command.

See the Composer documentation for more information about the composer.json file.

Packages bundled with Castor

Castor ships its own dependencies (Symfony components, nikic/php-parser, composer/composer, ...) in the phar and in the static binary, and loads them in the same PHP process as the remote packages. A PHP class is loaded once, so a remote package cannot bring its own copy of one of these packages: the process would run a mix of the two versions, and break in unexpected ways.

When running Composer on castor.composer.json, Castor adds a repository of metapackages standing for the packages it ships, at their exact version, in front of the other repositories. Their versions are the only ones Composer knows for these packages: your packages are resolved against them, nothing is installed a second time in .castor/vendor/ (a metapackage has no files), and a package requiring a version Castor does not ship is refused:

$ castor my-task
...
  Problem 1
    - Root composer.json requires nikic/php-parser ^4.0, it is satisfiable by nikic/php-parser[v4.0.0, ..., v4.19.5] from composer repo (https://repo.packagist.org) but nikic/php-parser[v5.8.0] from the packages bundled with Castor v1.8.0 has higher repository priority. The packages from the higher priority repository do not match your constraint and are therefore not installable. ...

Set "extra.castor.bundled-packages" to false in castor.composer.json to ignore the packages bundled with Castor, at the risk of breaking it at runtime (see the documentation about remote imports).

The packages Castor ships appear in castor.composer.lock as metapackages, marked with extra.castor.bundled, and castor composer show lists the ones your packages use. When you update Castor, the next time it runs in the project it checks that the versions it now ships still satisfy the constraints of your packages, and only updates these entries of the lock when they do not, or when it starts or stops shipping a package. The version recorded for a metapackage is thus the one of the Castor that wrote it, and castor composer update refreshes it.

Castor itself, jolicode/castor, is part of the list, so a remote package requiring it is checked against the running version instead of installing a second Castor in .castor/vendor/.

If you really need to install your own copy of a package Castor ships, because a package you need has a constraint Castor does not satisfy for instance, opt out in castor.composer.json:

{
    "extra": {
        "castor": {
            "bundled-packages": false
        }
    }
}

Your packages are then resolved against Packagist only, and Castor may break at runtime, when a class is loaded from the wrong copy.

Importing file from a remote package

Third party functions may not be autoloaded by Composer, as they may be optional. To import them, you can use the import() function.

import('composer://vendor/package/', file: 'functions.php');

The file argument is optional. When not provided, Castor will look for a castor.php file in the package.

Manipulating castor composer file

Castor provides a composer command to manipulate the castor.composer.json file.

For example, you can use it to add a package to the file:

castor composer require 'vendor/package'

Or you can use it to update packages:

castor composer update

Preventing remote imports

Remote packages are code downloaded from Packagist (or the repositories declared in castor.composer.json) and executed on your machine, like the castor.php file itself. They are installed the first time Castor runs in the project, whatever the command (castor list included), except during a shell completion, which never downloads anything.

In case you have trouble with the imported functions (or if you don't trust them), you can prevent Castor from importing and running any of them. Add the --no-remote option when calling any Castor tasks:

castor --no-remote my-task

This will trigger a warning to remind you that the remote imports are disabled. Also, any task or configuration using an imported function will trigger an error with Castor complaining about undefined functions.

If you want to disable remote imports every time, you can define the CASTOR_NO_REMOTE environment variable to 1:

export CASTOR_NO_REMOTE=1
castor my-task # will not import any remote functions

Lock file

Like every PHP projects using Composer, it will generate a castor.composer.lock file to lock the versions of the imported packages.

It is recommended to commit this file to your version control system to ensure that everyone uses the same versions of the imported packages.