Laravel Forge SDK

repository·4.x·Indexed 20 days ago

https://github.com/laravel/forge-sdk

An expressive PHP interface for interacting with the Laravel Forge API v2. It enables programmatic management of servers, organizations, sites, domains, certificates, deployments, databases, and PHP settings. The SDK includes support for cursor pagination, asynchronous operation timeouts, and resource-specific classes for managing entities like BackupConfiguration, Domain, Recipe, and ScheduledJob.

Tokens
14.8K
Snippets
39
Records
52
Agent score
69%

What's inside laravel-forge-sdk

  1. Introduction to the Laravel Forge SDK

    4.x
    The Laravel Forge SDK is an expressive PHP interface designed for interacting with the Laravel Forge API v2. It allows developers to programmatically manage Laravel Forge servers, organizations, sites, domains, certificates, and deployments.
  2. How pagination works with CursorPaginator

    4.x

    In v4.0+, all list methods return a CursorPaginator instead of a plain array. While it remains iterable and countable (supporting foreach and count()), you must use specific methods for advanced pagination tasks.

    Accessing current page items

    • Use foreach to iterate.
    • Use count($paginator) for the item count on the current page.
    • Use $paginator[0] for index access.
    • Use $paginator->items() to retrieve the underlying plain array.
    • Next Page: Use $paginator->nextPage() to get the next CursorPaginator instance.
    • Check for more: Use $paginator->hasMorePages() to check if subsequent pages exist.
    • Resuming via Cursor: Use $paginator->nextCursor() to get a string cursor. You can resume pagination later by passing this cursor in the query array: ['cursor' => $cursor].

    Iterating all items

    • Lazy Iteration: Use ->lazy() to automatically fetch and iterate through all pages.
    • Page-by-Page: Use ->lazyPages() to iterate through each CursorPaginator instance.
    // Iterating all items across all pages automatically
    foreach ($forge->servers($organizationSlug)->lazy() as $server) {
        // ...
    }
    
    // Resuming pagination from a stored cursor
    $cursor = Cache::get('forge_cursor');
    $page = $forge->servers($organizationSlug, ['cursor' => $cursor]);
    
    // Controlling page size
    $servers = $forge->servers($organizationSlug, ['page' => ['size' => 50]]);
  3. Handling mutation methods that return `void` in v4.0

    4.x

    In v4.0, mutation endpoints that return 202 Accepted with no body now return void in the SDK. Because these actions are asynchronous, you cannot rely on the return value to confirm the change. To inspect the resulting state, you must issue a follow-up GET request once the action is expected to have completed.

    Affected methods include: updateSite, installPhpVersion, createRecipeRun, createBackup, createBackupConfiguration, updateBackupConfiguration, updateBackgroundProcess, updateDatabaseUser, updateComposerCredential, updateNpmCredential, and others.

    // Perform the mutation
    $forge->updateSite($organizationSlug, $serverId, $siteId, ['aliases' => ['foo.com']]);
    
    // Fetch the resource to verify the change
    $site = $forge->site($organizationSlug, $serverId, $siteId);
  4. How CursorPaginator works in v4.0

    4.x

    In v4.0, all list methods that previously returned arrays now return a CursorPaginator instance.

    While CursorPaginator implements Countable, ArrayAccess, and IteratorAggregate (meaning foreach, count(), and $result[0] still work), it is not a plain array. Functions like array_map() or array_filter() will fail when used directly on the paginator.

    To use the underlying array, call $paginator->items(). Alternatively, you can iterate over pages using $paginator->lazy() or $paginator->lazyPages().

    // v3.x
    $servers = $forge->servers(); // returns array
    
    // v4.0
    $servers = $forge->servers($organizationSlug); // returns CursorPaginator
    
    // To get the array back:
    $serverArray = $servers->items();
    
    // To iterate:
    foreach ($servers as $server) { ... }
  5. Handle paginated results with CursorPaginator

    4.x

    Collection methods like servers(), sites(), and recipes() return a Laravel\Forge\CursorPaginator. You can interact with these results in three ways:

    1. Direct Iteration: Use foreach to iterate the current page (note that this hides pagination details).
    2. Lazy Iteration: Use the ->lazy() method to walk every page across the entire collection, fetching the next cursor on demand.
    3. Array Snapshot: Use ->toArray() to convert the current page into a plain array.
    // Iterate the current page
    foreach ($forge->servers($organizationSlug) as $server) {
        echo $server->name;
    }
    
    // Lazily iterate across all pages
    foreach ($forge->servers($organizationSlug)->lazy() as $server) {
        echo $server->name;
    }
    
    // Snapshot the current page as a plain array
    $page = $forge->servers($organizationSlug)->toArray();
  6. Accessing undeclared properties via `$attributes` in v4.0

    4.x

    The Resource base class in v4.0 no longer uses #[\\[AllowDynamicProperties]. This means you can no longer access fields from the API response as dynamic properties if they are not explicitly declared in the class. To access undeclared fields, use the $attributes array.

    // v3.x — dynamic property access worked
    $server->someUndeclaredField;
    
    // v4.0 — use the attributes array
    $server->attributes['some_undeclared_field'];
  7. Organization-scoped endpoints in v4.0

    4.x

    Most resource endpoints in v4.0 now require an organizationSlug as the first parameter. This change applies to almost all endpoints except for global or user-specific ones.

    Endpoints requiring $organizationSlug:

    • servers(), server(), createServer()
    • sites(), site(), createSite() (Note: $forge->sites() is a global method for all sites across organizations)
    • backgroundProcesses(), scheduledJobs(), etc.

    Endpoints that DO NOT require $organizationSlug:

    • $forge->user() / $forge->me()
    • $forge->organizations()
    • $forge->sites() (Global access)
    • $forge->providers() / $forge->providerSizes() / $forge->providerRegions()
    • $forge->permissions() / $forge->predefinedRoles()
    • $forge->forgeRecipes()
    // v3.x
    $forge->servers();
    $forge->server($serverId);
    
    // v4.0
    $forge->servers($organizationSlug);
    $forge->server($organizationSlug, $serverId);
  8. Migrate from v3.x to v4.0

    4.x

    Upgrading to v4.0 involves several breaking changes. Follow this checklist to ensure a successful migration:

    1. Update PHP: Ensure your environment is running PHP 8.2 or higher.
    2. Retrieve Organization Slug: Most methods now require an $organizationSlug. You can retrieve your slugs via $forge->organizations().
    3. Inject Organization Slug: Add the $organizationSlug as the first argument to all resource methods (e.g., $forge->servers($organizationSlug, ...)).
    4. Handle Pagination Changes: List methods no longer return arrays. If you use array functions like array_map() or array_filter(), call ->items() on the result first.
    5. Update Renamed Methods:
      • daemons() $\rightarrow$ backgroundProcesses()
      • jobs() $\rightarrow$ scheduledJobs()
      • allSites() $\rightarrow$ sites()
      • siteNginxConfig() $\rightarrow$ siteNginx()
      • updateSiteNginxConfig() $\rightarrow$ updateSiteNginx()
    6. Verify Resource Properties: Properties are now strictly typed and camelCased. Unknown API fields are moved to the $attributes array and are no longer accessible via dynamic properties.
    // Before (v3.x)
    $names = array_map(fn($s) => $s->name, $forge->servers());
    
    // After (v4.x)
    $names = array_map(fn($s) => $s->name, $forge->servers($org)->items());
  9. Manage asynchronous operations and timeouts

    4.x

    Some methods (like createSite) wait for the action to complete on Forge by periodically checking the resource status. By default, this waits up to 30 seconds.

    • Disable waiting: Pass false as the final argument to the method.
    • Customize timeout: Use the setTimeout(int $seconds) method on the Forge instance before calling the action.
    • Error handling: If the operation exceeds the timeout, a Laravel\Forge\Exceptions\TimeoutException is thrown.
    // This will wait until the site is fully installed (max 30 seconds)
    $site = $forge->createSite($organizationSlug, $serverId, [
        'domain' => 'example.com',
        'type' => 'php',
    ]);
    
    // Don't wait
    $site = $forge->createSite($organizationSlug, $serverId, $data, false);
    
    // Wait up to 2 minutes
    $site = $forge->setTimeout(120)->createSite($organizationSlug, $serverId, $data);
  10. Use consistent service action patterns in v4.0

    4.x

    In v4.0, service actions (like restarting Nginx, MySQL, etc.) follow a unified pattern using perform[Service]Action methods.

    $forge->performNginxAction($organizationSlug, $serverId, ['action' => 'restart']);
    $forge->performMySQLAction($organizationSlug, $serverId, ['action' => 'restart']);
    $forge->performPostgresAction($organizationSlug, $serverId, ['action' => 'restart']);
    $forge->performRedisAction($organizationSlug, $serverId, ['action' => 'restart']);
    $forge->performPHPAction($organizationSlug, $serverId, ['action' => 'restart']);
    $forge->performSupervisorAction($organizationSlug, $serverId, ['action' => 'restart']);
  11. Upgrade from v2.x to v3.0

    4.x

    When upgrading from version 2.x to 3.0, you must perform the following steps to ensure compatibility:

    1. Update Package Name: Change the dependency in your composer.json from the old package name to laravel/forge-sdk.
    2. Update Namespaces: Replace all instances of the ThemSaid\ namespace with Laravel\.
    3. Verify PHP Version: Ensure your environment is running at least PHP 7.2.
    4. Refactor Method Calls: Update deprecated or removed methods as specified in the breaking changes section.