Contributing Code

A PHP library designed to simplify interaction with the dotCMS Page API. This SDK provides a clean, object-oriented interface for retrieving and working with dotCMS pages and their components.

PHP Code Quality Checks

Requirements#


  • PHP 8.2 or higher
  • Composer

Installation#


Install the SDK using Composer:

composer require dotcms/php-sdk

Configuration#


The SDK requires configuration to connect to your dotCMS instance:

use Dotcms\PhpSdk\Config\Config;

// Create a configuration for the client
$config = new Config(
    host: 'https://your-dotcms-instance.com',
    apiKey: 'YOUR_API_KEY',
    clientOptions: [
        'timeout' => 30
    ]
);

Configuration Options#

Required Parameters#

  • host: Your dotCMS instance URL
  • apiKey: Your dotCMS API key

Optional Parameters#

  • clientOptions: Guzzle HTTP client options

    • headers: Custom HTTP headers
    • verify: SSL verification (boolean)
    • timeout: Request timeout in seconds
    • connect_timeout: Connection timeout in seconds
    • http_errors: Whether to throw exceptions for HTTP errors
    • allow_redirects: Whether to follow redirects
  • logConfig: Logging configuration

    • level: Log level (DEBUG, INFO, NOTICE, WARNING, ERROR, CRITICAL, ALERT, EMERGENCY)
    • console: Whether to output logs to console
    • handlers: Array of custom Monolog handlers

Basic Usage#


Creating a Client#

use Dotcms\PhpSdk\DotCMSClient;

// Create the dotCMS client
$client = new DotCMSClient($config);

Fetching a Page#

try {
    // Create a page request for a specific page
    $pageRequest = $client->createPageRequest('/', 'json');
    
    // Get the page
    $pageAsset = $client->getPage($pageRequest);
    
    // Access page information
    echo "Page title: " . $pageAsset->page->title . "\n";
    echo "Page URL: " . $pageAsset->page->pageUrl . "\n";
    echo "Template name: " . $pageAsset->template->title . "\n";
    
    // Check if page has vanity URL
    if ($pageAsset->vanityUrl !== null) {
        echo "Vanity URL: " . $pageAsset->vanityUrl->url . "\n";
        echo "Forward to: " . $pageAsset->vanityUrl->forwardTo . "\n";
    }
    
} catch (\Exception $e) {
    echo "Error: " . $e->getMessage() . "\n";
}

Fetching Navigation#

try {
    // Create a navigation request
    $navRequest = $client->createNavigationRequest('/about-us', 2);
    
    // Get the navigation
    $nav = $client->getNavigation($navRequest);
    
    // Access navigation information
    echo "Navigation title: " . $nav->title . "\n";
    echo "Navigation URL: " . $nav->href . "\n";
    
    // Access children if available
    if ($nav->hasChildren()) {
        foreach ($nav->getChildren() as $child) {
            echo "- " . $child->title . " (" . $child->href . ")\n";
        }
    }
    
} catch (\Exception $e) {
    echo "Error: " . $e->getMessage() . "\n";
}

Asynchronous Requests#

// Create a page request
$asyncPageRequest = $client->createPageRequest('/', 'json');

// Get the page asynchronously
$promise = $client->getPageAsync($asyncPageRequest);

// Add callbacks for success and failure
$promise->then(
    function ($asyncPage) {
        echo "Async page title: " . $asyncPage->page->title . "\n";
        if ($asyncPage->vanityUrl !== null) {
            echo "Vanity URL: " . $asyncPage->vanityUrl->url . "\n";
        }
    },
    function (\Exception $e) {
        echo "Error: " . $e->getMessage() . "\n";
    }
);

// Wait for the promise to complete
$promise->wait();

Asynchronous Navigation Requests#

// Create a navigation request
$asyncNavRequest = $client->createNavigationRequest('/', 2);

// Get the navigation asynchronously
$promise = $client->getNavigationAsync($asyncNavRequest);

// Add callbacks for success and failure
$promise->then(
    function ($nav) {
        echo "Navigation title: " . $nav['title'] . "\n";
        if ($nav->hasChildren()) {
            foreach ($nav->getChildren() as $child) {
                echo "- " . $child['title'] . "\n";
            }
        }
    },
    function (\Exception $e) {
        echo "Error: " . $e->getMessage() . "\n";
    }
);

// Wait for the promise to complete
$promise->wait();

Advanced Usage#


Customizing Page Requests#

The PageRequest class provides several methods to customize your page requests:

$pageRequest = $client->createPageRequest('/about-us', 'json');

// Set the language ID for the request
$pageRequest = $pageRequest->withLanguageId(1);

// Set the mode (LIVE, WORKING, EDIT_MODE)
$pageRequest = $pageRequest->withMode('WORKING');

// Set the depth of the content to retrieve (0-3)
$pageRequest = $pageRequest->withDepth(2);

// Set personalization options
$pageRequest = $pageRequest->withPersonaId('persona_id');

// Set whether to fire rules
$pageRequest = $pageRequest->withFireRules(true);

// Set the host ID (Site ID)
$pageRequest = $pageRequest->withHostId('48190c8c-42c4-46af-8d1a-0cd5db894797');

Note that each method returns a new instance with the updated value, so you need to reassign the result.

Customizing Navigation Requests#

The NavigationRequest class allows you to customize your navigation requests:

// Create a navigation request with custom parameters
$navRequest = $client->createNavigationRequest(
    path: '/about-us',  // The root path to begin traversing
    depth: 2,           // The depth of the folder tree to return (1-3)
    languageId: 2       // The language ID for content (e.g., 2 for Spanish)
);

// Get the navigation with the custom parameters
$nav = $client->getNavigation($navRequest);

Working with Page Components#

Once you have a page, you can access its components:

// Access site information
echo "Site hostname: " . $page->site->hostname . "\n";

// Access template information
echo "Template title: " . $page->template->title . "\n";

// Access layout information
echo "Layout header: " . $page->layout->header . "\n";

// Access vanity URL if present
if ($page->vanityUrl !== null) {
    echo "Vanity URL pattern: " . $page->vanityUrl->pattern . "\n";
    echo "Forward to: " . $page->vanityUrl->forwardTo . "\n";
    echo "Response code: " . $page->vanityUrl->response . "\n";
    echo "Is temporary redirect: " . ($page->vanityUrl->temporaryRedirect ? 'Yes' : 'No') . "\n";
}

// Access containers and contentlets
foreach ($page->containers as $containerId => $container) {
    echo "Container ID: " . $containerId . "\n";
    echo "Max Contentlets: " . $container->maxContentlets . "\n";
    
    if (!empty($container->contentlets)) {
        foreach ($container->contentlets as $uuid => $contentlets) {
            foreach ($contentlets as $contentlet) {
                echo "Contentlet type: " . $contentlet->contentType . "\n";
                echo "Contentlet title: " . ($contentlet->title ?? 'N/A') . "\n";
                
                // Access additional fields using object properties
                foreach ($contentlet->getAdditionalProperties() as $fieldName => $fieldValue) {
                    if (is_scalar($fieldValue)) {
                        echo "$fieldName: $fieldValue\n";
                    }
                }
            }
        }
    }
}

Working with Navigation Items#

The NavigationItem class provides array access to its properties:

// Check if the navigation item is a folder
if ($nav->isFolder()) {
    echo "This is a folder\n";
}

// Check if the navigation item is a page
if ($nav->isPage()) {
    echo "This is a page\n";
}

// Access navigation properties
echo "Title: " . $nav->title . "\n";
echo "URL: " . $nav->href . "\n";
echo "Type: " . $nav->type . "\n";
echo "Target: " . $nav->target . "\n"; // e.g., "_self", "_blank"
echo "Order: " . $nav->order . "\n";

// Recursively process navigation tree
function processNavigation($navItem, $level = 0) {
    $indent = str_repeat("  ", $level);
    echo $indent . "- " . $navItem->title . " (" . $navItem->href . ")\n";
    
    if ($navItem->hasChildren()) {
        foreach ($navItem->getChildren() as $child) {
            processNavigation($child, $level + 1);
        }
    }
}

processNavigation($nav);

Using SDK Utilities#

The SDK includes a DotCmsHelper class with common functions for rendering and working with DotCMS content:

use Dotcms\PhpSdk\Utils\DotCmsHelper;
use Dotcms\PhpSdk\Model\Content\Contentlet;

// Generate HTML attributes from an associative array
$attrs = [
    'class' => 'my-class',
    'data-id' => '123',
    'disabled' => true
];
$htmlAttrs = DotCmsHelper::htmlAttributes($attrs);

// Generate simple HTML for a contentlet
$contentlet = new Contentlet(
    identifier: 'abc123',
    inode: 'inode123',
    title: 'My Content',
    contentType: 'Banner'
);
$html = DotCmsHelper::simpleContentHtml($contentlet->jsonSerialize());

// Extract accept types from container structures
$acceptTypes = DotCmsHelper::extractAcceptTypes($containerStructures);

// Extract contentlets from container page
$contentlets = DotCmsHelper::extractContentlets($containerPage, $uuid);

These utilities help with common tasks like:

  • Generating HTML attributes safely
  • Rendering contentlets with basic HTML
  • Working with container structures and contentlets
  • Extracting data from container pages

Data Access Patterns#


The SDK provides two ways to access data: object notation and array access. Here's when to use each:

Object Notation (->)#

Use object notation for accessing standard properties of these classes:

// Page and Site properties
$page->title
$page->pageUrl
$site->hostname

// Container properties
$container->identifier
$container->title
$container->maxContentlets

// Contentlet properties
$contentlet->identifier
$contentlet->title
$contentlet->contentType

// Navigation properties
$nav->title
$nav->href
$nav->type

Array Access ([])#

Use array access for:

  1. Additional properties not explicitly defined in the class
  2. Accessing container contentlets by UUID
  3. Accessing rendered content by UUID
// Additional properties
$contentlet['customField']
$page['metadata']

// Container contentlets
$container->contentlets['uuid-123']

// Rendered content
$container->rendered['uuid-123']

Classes That Support Both#

These classes support both object and array access:

  • Page
  • Site
  • Contentlet
  • Container
  • Any class extending AbstractModel

Classes That Only Support Object Access#

These classes only support object notation:

  • PageAsset
  • ContainerPage
  • NavigationItem
  • Layout
  • Template
  • VanityUrl

API Reference#


DotCMSClient#

The main client for interacting with the dotCMS API.

MethodDescriptionParameters
__constructCreate a new client instanceConfig $config
getPageFetch a page synchronouslyPageRequest $request
getPageAsyncFetch a page asynchronouslyPageRequest $request
createPageRequestCreate a new page requeststring $pagePath, string $format = 'json'
getNavigationFetch navigation items synchronouslyNavigationRequest $request
getNavigationAsyncFetch navigation items asynchronouslyNavigationRequest $request
createNavigationRequestCreate a new navigation requeststring $path = '/', int $depth = 1, int $languageId = 1

PageRequest#

Represents a request to the dotCMS Page API.

MethodDescriptionParameters
__constructCreate a new page requeststring $pagePath, string $format = 'json'
withLanguageIdSet the language ID for the requestint $languageId
withModeSet the mode (LIVE, WORKING, EDIT_MODE)string $mode
withDepthSet the depth of the content to retrieve (0-3)int $depth
withPersonaIdSet the persona ID for personalizationstring $personaId
withHostIdSet the host ID (Site ID)string $hostId
withFireRulesSet whether to fire rulesbool $fireRules
buildPath(Internal) Build the API path for the requestNone
buildQueryParams(Internal) Build the query parameters for the requestNone

Represents a request to the dotCMS Navigation API.

MethodDescriptionParameters
__constructCreate a new navigation requeststring $path = '/', int $depth = 1, int $languageId = 1
getPathGet the pathNone
getDepthGet the depthNone
getLanguageIdGet the language IDNone
buildPath(Internal) Build the API path for the requestNone
buildQueryParams(Internal) Build the query parameters for the requestNone

PageAsset#

Represents a complete page asset from dotCMS.

PropertyTypeDescription
pagePageThe Page object
siteSiteThe Site object
templateTemplateThe Template object
layoutLayoutThe Layout object
containersarrayArray of ContainerPage objects
urlContentMapContentlet|nullContent map for generated pages
viewAsViewAsVisitor context information
vanityUrlVanityUrl|nullOptional vanity URL configuration

ContainerPage#

Represents a container page from dotCMS.

PropertyTypeDescription
containerContainerThe Container object
containerStructuresarrayArray of ContainerStructure objects
renderedarray<string, string>Rendered content keyed by UUID
contentletsarray<string, array>Contentlets keyed by UUID

Contentlet#

Represents a content item from dotCMS.

PropertyTypeDescription
identifierstringThe content identifier
inodestringThe content inode
titlestringThe content title
contentTypestringThe content type
additionalPropertiesarray<string, mixed>Additional content properties
MethodDescriptionReturn Type
getAdditionalPropertiesGet additional propertiesarray<string, mixed>
jsonSerializeConvert to array for JSON serializationarray<string, mixed>

DotCmsHelper#

Utility class for common DotCMS operations.

MethodDescriptionParametersReturn Type
htmlAttributesGenerate HTML attributesarray<string, mixed>string
simpleContentHtmlGenerate simple HTML for contentarray<string, mixed>string
extractAcceptTypesExtract accept types from structuresarray<ContainerStructure>string
extractContentletsExtract contentlets from containerContainerPage, stringarray<Contentlet>

Error Handling#


The SDK provides several exception classes for error handling:

ExceptionDescription
DotCMSExceptionBase exception class for all SDK exceptions
ConfigExceptionThrown when there's an issue with the configuration
HttpExceptionThrown when there's an HTTP error
ResponseExceptionThrown when there's an issue with the response

Example error handling:

try {
    $pageAsset = $client->getPage($pageRequest);
} catch (ConfigException $e) {
    echo "Configuration error: " . $e->getMessage() . "\n";
} catch (HttpException $e) {
    echo "HTTP error: " . $e->getMessage() . "\n";
    echo "Status code: " . $e->getStatusCode() . "\n";
} catch (ResponseException $e) {
    echo "Response error: " . $e->getMessage() . "\n";
} catch (DotCMSException $e) {
    echo "dotCMS error: " . $e->getMessage() . "\n";
} catch (\Exception $e) {
    echo "General error: " . $e->getMessage() . "\n";
}

Examples#


Basic Page Example#

<?php

require_once __DIR__ . '/vendor/autoload.php';

use Dotcms\PhpSdk\Config\Config;
use Dotcms\PhpSdk\DotCMSClient;
use Dotcms\PhpSdk\Model\Page\PageAsset;
use Dotcms\PhpSdk\Model\Page\VanityUrl;

// Create configuration
$config = new Config(
    host: 'https://demo.dotcms.com',
    apiKey: 'YOUR_API_KEY'
);

// Create client
$client = new DotCMSClient($config);

// Create page request
$pageRequest = $client->createPageRequest('/', 'json');

// Get page
$pageAsset = $client->getPage($pageRequest);

// Display page information
echo "Page title: " . $pageAsset->page->title . "\n";
echo "Page URL: " . $pageAsset->page->pageUrl . "\n";

// Check for vanity URL
if ($pageAsset->vanityUrl !== null) {
    echo "Vanity URL: " . $pageAsset->vanityUrl->url . "\n";
    echo "Forward to: " . $pageAsset->vanityUrl->forwardTo . "\n";
}

Basic Navigation Example#

<?php

require_once __DIR__ . '/vendor/autoload.php';

use Dotcms\PhpSdk\Config\Config;
use Dotcms\PhpSdk\DotCMSClient;
use Dotcms\PhpSdk\Model\Navigation\NavigationItem;

// Create configuration
$config = new Config(
    host: 'https://demo.dotcms.com',
    apiKey: 'YOUR_API_KEY'
);

// Create client
$client = new DotCMSClient($config);

// Create navigation request for the About Us section with depth=2
$navRequest = $client->createNavigationRequest('/about-us', 2);

// Get navigation
$nav = $client->getNavigation($navRequest);

// Display navigation information
echo "Navigation title: " . $nav->title . "\n";

// Display children if available
if ($nav->hasChildren()) {
    echo "Children:\n";
    foreach ($nav->getChildren() as $child) {
        echo "- " . $child->title . " (" . $child->href . ")\n";
    }
}

Integration with Symfony#

The SDK can be easily integrated with Symfony. See the examples/dotcms-symfony directory for a complete example.

We Need Your Feedback!#


The SDK is in active development, and your feedback is crucial to its success. We're particularly interested in:

  • Use cases and real-world scenarios
  • Feature requests and improvements
  • Performance feedback
  • Integration challenges
  • Documentation suggestions

Feel free to:

  • Open issues for bugs or feature requests
  • Join our community discussions
  • Share your implementation experiences
  • Suggest improvements to the API design

Contributing#


We welcome contributions of all kinds! Whether you're fixing bugs, adding features, or improving documentation, your help makes the SDK better for everyone.

How to Contribute#

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Make your changes
  4. Run the test suite (composer check)
  5. Commit your changes (git commit -m 'feat: add amazing feature')
  6. Push to the branch (git push origin feature/amazing-feature)
  7. Open a Pull Request

Pull Requests#

We actively review and merge pull requests. To ensure a smooth process:

  • Follow our coding standards
  • Add tests for new features
  • Update documentation
  • Use conventional commit messages
  • Keep PRs focused and manageable

Development Setup#

  1. Clone the repository
  2. Install dependencies: composer install
  3. Run tests: composer test

Coding Standards#

The project uses PHP-CS-Fixer for code style. Run the following commands:

  • Check code style: composer cs-check
  • Fix code style: composer cs-fix

Static Analysis#

The project uses PHPStan for static analysis:

composer phpstan

Running All Checks#

composer check

What's Next#


The SDK is actively being developed with several exciting features planned:

Template Rendering System#

We're working on a comprehensive template rendering system that will make it easier to integrate DotCMS with popular PHP frameworks:

Twig Templates#

  • Pre-built templates for DotCMS layouts, containers, and content types
  • Twig extensions for common DotCMS operations

Blade Templates#

  • Ready-to-use Blade components for DotCMS content
  • Blade directives for DotCMS-specific functionality
  • Standard layouts for common page structures
  • SEO-friendly markup and metadata handling

Content API Support#

  • Full Content API integration for content management
  • ElasticSearch Support
  • Advanced search capabilities

Logging System#

  • Configurable log levels (DEBUG, INFO, WARNING, ERROR, etc.)
  • Multiple logging handlers (file, console, syslog)
  • Context-aware logging with request/response details

Data Validation Layer#

  • Schema-based validation for content types
  • Custom validation rules
  • Validation error handling
  • Type conversion and normalization
  • Cross-field validation
  • Validation caching

Additional Features#

  • Enhanced caching mechanisms
  • Additional framework integrations
  • Performance optimizations
  • Extended documentation and examples

Stay tuned for updates and feel free to contribute to these upcoming features!

License#


This project is licensed under the MIT License - see the LICENSE file for details.

Source: README.md
Branch: main

Found an issue with this documentation? Report it on GitHub