Cockpit Documentation

repository·develop·Indexed 20 days ago

https://github.com/cockpit-hq/cockpit

A modern, headless Content Management System (CMS) providing content infrastructure via GraphQL and REST APIs. This documentation includes detailed guides on ESQL, a PHP library for database interaction supporting MySQL, PostgreSQL, and SQLite, featuring a fluent query builder, automatic JSON encoding/decoding, transaction management, and safe SQL execution.

Tokens
69.4K
Snippets
242
Records
287
Agent score
71%

What's inside Cockpit

  1. Overview of SwaggerPhp Alternative Analysers

    develop
    The SwaggerPhp alternative tools allow Cockpit to support Swagger annotations via phpstan/phpdoc-parser instead of the deprecated doctrine/annotations. This is primarily used to facilitate OpenAPI specification generation in modules/System/Controller/Api.php.
  2. Understand the ScriptLite security model

    develop

    ScriptLite provides a sandboxed environment designed for executing untrusted user code safely. The sandbox enforces the following restrictions:

    • No Filesystem Access: No require, import, or file I/O.
    • No Network Access: No fetch, XMLHttpRequest, or sockets.
    • No PHP Internals: No eval, exec, system, or access to PHP's global scope.
    • No Ambient Globals: No process, globalThis, window, or document.
    • Explicit Data Boundary: Scripts can only access variables explicitly passed via the $globals parameter.

    Note: While the sandbox prevents unauthorized access, it does not prevent CPU or memory exhaustion. For untrusted input, you should combine ScriptLite with PHP's set_time_limit() and memory_limit to cap resource usage.

  3. Automatic JSON handling in ESQL

    develop

    ESQL provides seamless JSON integration for complex data structures:

    Automatic Encoding (INSERT/UPDATE)

    When passing arrays or objects in the data key of an insert() or update() call, ESQL automatically converts them to JSON strings for storage.

    Automatic Decoding (SELECT)

    When fetching data, ESQL automatically detects and decodes JSON strings back into PHP arrays or objects. You can control the decoding behavior using the jsonDecodeAssoc option in your query:

    • jsonDecodeAssoc => true (default): Decodes JSON into associative arrays.
    • jsonDecodeAssoc => false: Decodes JSON into stdClass objects.
    // Example of automatic encoding during insert
    $db->insert([
        'table' => 'users',
        'data' => [
            'name' => 'John',
            'settings' => ['theme' => 'dark'] // Auto-encoded to JSON
        ]
    ]);
    
    // Example of automatic decoding during select
    $user = $db->selectOne('users', [
        'conditions' => ['id' => 1],
        'jsonDecodeAssoc' => false // Decodes JSON as stdClass objects
    ]);
  4. How IndexHybrid works as a search abstraction layer

    develop

    IndexHybrid is a unified search abstraction layer that provides a consistent interface across multiple search backends. It allows you to switch between backends (like IndexLite or Meilisearch) without changing your application code by providing a unified API for indexing, searching, and faceting.

    Supported Backends

    BackendProtocolFeatures
    IndexLiteindexlite://path/to/dbEnhanced fuzzy, SQLite FTS5, facets, field boosting
    Meilisearchmeilisearch://host:portTypo tolerance, highlights, synonyms, geo search

    Core Workflow

    1. Initialize the Manager: Create a Manager instance using a backend-specific protocol.
    2. Create an Index: Define an index with specific searchable fields.
    3. Add Documents: Populate the index with data.
    4. Search: Use the unified search() method with various options.
    use IndexHybrid\Manager;
    
    // Initialize
    $manager = new Manager('indexlite://storage/search.db');
    
    // Create index
    $manager->createIndex('products', ['title', 'description', 'category', 'price']);
    
    // Get index and add data
    $index = $manager->index('products');
    $index->addDocument('prod1', [
        'title' => 'iPhone 15 Pro',
        'description' => 'Latest Apple smartphone',
        'category' => 'Electronics',
        'price' => 999
    ]);
    
    // Search
    $results = $index->search('phone', ['fuzzy' => true]);
  5. Use enhanced fuzzy search algorithms

    develop

    IndexLite provides several fuzzy matching algorithms to handle typos and variations. You can enable fuzzy search by setting 'fuzzy' => true in the search options and optionally specifying an algorithm via 'fuzzy_algorithm'.

    Available Algorithms:

    • fts5: Standard SQLite FTS5 (default)
    • levenshtein: Best for spelling errors
    • jaro_winkler: Best for names and people
    • trigram: Best for partial matches
    • soundex: Best for pronunciation-based matching
    • hybrid: Combined scoring for best overall results

    Fuzzy Options:

    • fuzzy_algorithm (string): The algorithm to use.
    • fuzzy_threshold (int): The distance threshold (default: 2).
    • fuzzy_min_score (int): Minimum score for the hybrid algorithm.
    // Basic fuzzy search (uses hybrid algorithm)
    $results = $index->search('iphon', ['fuzzy' => true]);
    
    // Algorithm-specific search with threshold
    $results = $index->search('macbok', [
        'fuzzy' => true,
        'fuzzy_algorithm' => 'levenshtein',
        'fuzzy_threshold' => 2
    ]);
    
    // Hybrid algorithm with custom scoring
    $results = $index->search('searh', [
        'fuzzy' => true,
        'fuzzy_algorithm' => 'hybrid',
        'fuzzy_min_score' => 70,
        'fuzzy_threshold' => 2
    ]);
  6. Understand ScriptLite execution backends

    develop

    ScriptLite supports three primary execution modes, each with different performance characteristics:

    1. C Extension (Native): Uses a native C implementation with computed-goto dispatch and zero-copy string interning. This is the fastest mode.
    2. PHP VM (Pure PHP): A stack-based bytecode VM implemented in pure PHP. This is the fallback mode.
    3. PhpTranspiler: Transpiles ECMAScript AST directly into PHP source code, which is then executed via eval() (leveraging OPcache/JIT). This is the fastest mode available if the C extension is not installed.
  7. Handle JSON data automatically in ESQL

    develop

    ESQL features automatic JSON handling for complex data types.

    Automatic Encoding (INSERT/UPDATE)

    When passing an array as a value in insert() or update() calls, ESQL automatically encodes it into a JSON string for storage.

    Automatic Decoding (SELECT)

    When retrieving data, ESQL automatically decodes JSON columns back into PHP arrays.

    Controlling JSON Behavior

    • Global Configuration: You can disable automatic encoding or decoding when instantiating the Client using encodeJson and decodeJson options.
    • Per-Query Control: Use the jsonDecodeAssoc option in select methods to determine if JSON should be decoded as associative arrays (default) or stdClass objects.
    // Decode JSON as stdClass objects instead of associative arrays
    $user = $db->selectOne('users', [
        'conditions' => ['id' => 1],
        'jsonDecodeAssoc' => false
    ]);
    // Insert user with complex preferences (auto-encoded to JSON)
    $db->insert([
        'table' => 'users',
        'data' => [
            'name' => 'John',
            'preferences' => [
                'ui' => ['theme' => 'dark', 'language' => 'en'],
                'notifications' => ['email' => ['newsletters' => true]]
            ]
        ]
    ]);
    
    // Retrieve and work with the data (auto-decoded from JSON)
    $user = $db->selectOne('users', ['conditions' => ['name' => 'John']]);
    // $user['preferences']['ui']['theme'] === 'dark'
  8. Use smart cropping with VIPS

    develop

    If VIPS is enabled, you can use intelligent cropping algorithms to focus on the most important parts of an image using the smartcrop option. This is available via the PHP helper or the REST API.

    Available smartcrop modes:

    • attention - Focuses on areas of visual interest (recommended)
    • entropy - Focuses on high-detail/high-contrast areas
    • centre / center - Crops from the center
    • low - Focuses on low-frequency areas
    • high - Focuses on high-frequency areas
    // Attention-based smart cropping
    $url = $app->helper('asset')->image([
        'src' => '/path/to/image.jpg',
        'width' => 400,
        'height' => 300,
        'mode' => 'thumbnail',
        'smartcrop' => 'attention'
    ]);
  9. Use EventStream for real-time server-to-client communication

    develop

    The eventStream helper allows the server to push real-time events to clients. On the client side, these events are accessible via window.AppEventStream.

    Server-side usage:

    // Add event to stream
    $app->helper('eventStream')->add('notify', [
        'message' => 'Hello World',
        'status' => 'success'
    ], [
        'to' => $userId, // Optional: target specific user
        'sessionId' => $sessionId // Optional: target specific session
    ]);
    
    // Get events since timestamp
    $events = $app->helper('eventStream')->getEvents($timestamp);
    
    // Cleanup old events (automatically called)
    $app->helper('eventStream')->cleanup();

    Client-side usage:

    // Client-side (automatically initialized)
    window.AppEventStream.on('custom-event', function(evt) {
        console.log('Received:', evt.data);
    });

    Built-in event types include notify, alert, and logout.

    // Add event to stream
    $app->helper('eventStream')->add('notify', [
        'message' => 'Hello World',
        'status' => 'success'
    ], [
        'to' => $userId, // Optional: target specific user
        'sessionId' => $sessionId // Optional: target specific session
    ]);
  10. Use the Aggregation Framework Pipeline

    develop

    The aggregate() method allows you to process data through a series of pipeline stages.

    Common Pipeline Stages

    • $match: Filters documents.
    • $group: Groups documents by a key, using accumulators like $sum, $avg, $min, $max, $push, etc.
    • $sort: Sorts results.
    • $project: Reshapes documents (includes/excludes fields).
    • $addFields: Adds new fields to documents.
    • $unwind: Deconstructs an array field into multiple documents.
    • $lookup: Performs left outer joins to other collections.
    • $out / $merge: Exports or merges results into a collection.
    • $geoNear: (Must be first stage) Performs proximity searches.
    $analytics = $collection->aggregate([
        ['$match' => ['status' => 'active']],
        ['$group' => [
            '_id' => '$department',
            'employee_count' => ['$sum' => 1],
            'avg_salary' => ['$avg' => '$salary']
        ]],
        ['$sort' => ['avg_salary' => -1]],
        ['$out' => 'department_analytics']
    ])->toArray();
  11. Optimize MongoLite Query Performance

    develop

    To ensure high performance, leverage the automatic Query Optimizer by using top-level field queries and standard comparison operators.

    Optimized (Fast):

    • Top-level field queries (e.g., ['status' => 'active'])
    • Comparison operators: $eq, $ne, $gt, $gte, $lt, $lte
    • Set operators: $in, $nin
    • Element operators: $exists, $type, $size
    • Logical operators: $and, $or
    • Array containment (scalar values)

    Slower (Falls back to PHP processing):

    • Regex patterns ($regex)
    • Dot-notation for nested fields (meta.rating)
    • Array traversal (users.name)

    Best Practices:

    1. Use Projections: Limit returned fields using find($criteria, ['field' => 1]).
    2. Filter Early: In aggregation pipelines, place $match stages before $group or $sort.
    3. Pagination: Use skip() and limit() to handle large datasets.
    4. Chunking: For very large datasets, use a while loop with skip() and limit() to process data in batches to manage memory.
    // Example of efficient pagination/chunking
    $offset = 0;
    $limit = 1000;
    while (true) {
        $batch = $collection->find($criteria)
            ->skip($offset)
            ->limit($limit)
            ->toArray();
        if (empty($batch)) break;
        // Process batch...
        $offset += $limit;
    }