PHPackages                             brannow/typo3-dev-springboard - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Framework](/categories/framework)
4. /
5. brannow/typo3-dev-springboard

ActiveLibrary[Framework](/categories/framework)

brannow/typo3-dev-springboard
=============================

Launch into TYPO3 development instantly - ephemeral TYPO3 instances for extension development

09PHP

Since Sep 7Pushed 8mo agoCompare

[ Source](https://github.com/brannow/typo3-dev-springboard)[ Packagist](https://packagist.org/packages/brannow/typo3-dev-springboard)[ RSS](/packages/brannow-typo3-dev-springboard/feed)WikiDiscussions main Synced 1mo ago

READMEChangelogDependenciesVersions (1)Used By (0)

TYPO3 Dev Springboard
=====================

[](#typo3-dev-springboard)

Ephemeral TYPO3 instances for extension development. Resets to clean state on every execution.

Installation
------------

[](#installation)

```
composer require --dev brannow/typo3-dev-springboard
```

Requirements
------------

[](#requirements)

- PHP &gt;=8.1
- ext-pdo
- typo3/minimal ^12.4 || ^13.4
- symfony/filesystem
- symfony/yaml

Architecture Notes
------------------

[](#architecture-notes)

- Features declare dependencies
- Builder resolves dependencies automatically
- Circular dependencies are detected
- Each execution starts fresh (unless `persistCache()`)
- SQLite database by default
- Topological sorting ensures correct execution order

Minimal Start
-------------

[](#minimal-start)

```
use Typo3DevSpringboard\{Builder, Typo3Version};

Builder::make(Typo3Version::TYPO3_13_LTS)
    ->installDir(__DIR__ . '/.Build')
    ->build()
    ->execute();
```

Basic Frontend Page
-------------------

[](#basic-frontend-page)

```
Builder::make(Typo3Version::TYPO3_13_LTS)
    ->installDir(__DIR__ . '/.Build')
    ->withRequest('/')
    ->addDatabasePageRecord([
        'uid' => 1,
        'title' => 'Homepage',
        'slug' => '/'
    ])
    ->addDatabaseContentRecord([
        'pid' => 1,
        'header' => 'Hello',
        'bodytext' => 'World',
        'CType' => 'text'
    ])
    ->addDatabaseTypoScriptTemplate('
page = PAGE
page.10 = TEXT
page.10.value = Hello World
', 1)
    ->build()
    ->execute();
```

Builder Methods
---------------

[](#builder-methods)

### Configuration

[](#configuration)

```
/* composer.json
 the vendor and public dir must be in based in that root directory (in our case ./.Build)

"config": {
        "vendor-dir": ".Build/vendor", // important - same baseDir
        "bin-dir": ".Build/bin",
        "sort-packages": true,
        "allow-plugins": {
            "typo3/class-alias-loader": true,
            "typo3/cms-composer-installers": true
        }
    },
    "extra": {
        "typo3/cms": {
            "cms-package-dir": "{$vendor-dir}/typo3/cms",
            "web-dir": ".Build/public"   // important - same baseDir
        }
    }
 */
->installDir(__DIR__ . '/.Build')  // Required: TYPO3 installation path look in the composer.json example above
->persistCache()                    // Keep cache between executions
```

### Request

[](#request)

```
->withRequest('/')
->withRequest('/page', 'example.local', 'POST', true)  // uri, domain, method, https
```

### Database

[](#database)

```
->addDatabasePageRecord(['title' => 'Page', 'slug' => '/'])
->addDatabaseContentRecord(['pid' => 1, 'CType' => 'text'])
->addDatabaseTypoScriptTemplate($typoscript, $pageId, $root, $name)
```

### Site Configuration

[](#site-configuration)

```
->setSiteRootPageId(1)
->addSiteLanguage(SiteLanguage::EN, SiteLanguage::DE)
->setSiteLanguage(SiteLanguage::DE, 1)  // Force language ID
->setSiteConfig([...])  // Complete override
```

### Execution

[](#execution)

```
->build()           // Prepare system
->execute()         // Run TYPO3
->execute(true)     // Return output instead of printing
```

Custom Tables
-------------

[](#custom-tables)

### Quick Method - GenericTable

[](#quick-method---generictable)

```
$database = $builder->getFeature(\Typo3DevSpringboard\Feature\Database::class);

$genericTable = $database->getTable(\Typo3DevSpringboard\Feature\Database\GenericTable::class)
    ->addTableSchema('tx_extension_table', [
        'uid' => 'INTEGER PRIMARY KEY AUTOINCREMENT',
        'pid' => 'INTEGER DEFAULT 0',
        'title' => 'TEXT'
    ]);

$database->addRowToTable($genericTable, 'tx_extension_table', ['title' => 'Test', 'pid' => 1]);
```

### Custom Table Class

[](#custom-table-class)

```
use Typo3DevSpringboard\Feature\Database\Table;

class ExtensionTable extends Table
{
    public static function getIdentifier(): string
    {
        return 'extension_table';
    }

    protected function getTableSchemas(): array
    {
        return [
            'tx_extension_table' => [
                'uid' => 'INTEGER PRIMARY KEY AUTOINCREMENT',
                'pid' => 'INTEGER DEFAULT 0',
                'title' => 'TEXT'
            ]
        ];
    }
}

$database->getTable(ExtensionTable::class)
    ->addRow(['title' => 'Test', 'pid' => 1], 'tx_extension_table');
```

Custom Features
---------------

[](#custom-features)

### Implement Feature

[](#implement-feature)

```
use Typo3DevSpringboard\Feature\Typo3FeatureInterface;

class CustomFeature implements Typo3FeatureInterface
{
    public static function make(Typo3Version $version): static
    {
        return new static($version);
    }

    public static function getIdentifier(): string
    {
        return 'custom';
    }

    public function requiredFeatureIdentifier(): array
    {
        return [];  // Dependencies
    }

    public function execute(array $features): static
    {
        // Your logic here
        return $this;
    }
}

$builder->addFeature(CustomFeature::make(Typo3Version::TYPO3_13_LTS));
```

### Override Existing Feature

[](#override-existing-feature)

```
class CustomDatabase extends \Typo3DevSpringboard\Feature\Database
{
    // Override methods
}

$builder->addFeature(CustomDatabase::make(Typo3Version::TYPO3_13_LTS));
```

### Anonymous Class - New Feature

[](#anonymous-class---new-feature)

```
$customFeature = new class(Typo3Version::TYPO3_13_LTS) implements Typo3FeatureInterface {
    public function __construct(
        private readonly Typo3Version $version
    ) {}

    public static function make(Typo3Version $version): static
    {
        return new static($version);
    }

    public static function getIdentifier(): string
    {
        return 'anonymous_feature';
    }

    public function requiredFeatureIdentifier(): array
    {
        return ['Database'];
    }

    public function execute(array $features): static
    {
        $database = $features['Database'];
        // Custom logic
        return $this;
    }
};

$builder->addFeature($customFeature);
```

### Anonymous Class - Override Feature

[](#anonymous-class---override-feature)

```
// Override existing Database feature with anonymous class
$customDatabase = new class(Typo3Version::TYPO3_13_LTS) extends \Typo3DevSpringboard\Feature\Database {
    public static function getIdentifier(): string
    {
        return 'Database';  // Same identifier to override
    }

    public function execute(array $features): static
    {
        // Custom database setup
        parent::execute($features);
        // Additional logic
        return $this;
    }
};

$builder->addFeature($customDatabase);
```

### Anonymous Class - Custom Table

[](#anonymous-class---custom-table)

```
$database = $builder->getFeature(Database::class);

$customTable = new class(Typo3Version::TYPO3_13_LTS) extends Table {
    public function __construct(
        private readonly Typo3Version $version
    ) {}

    public static function make(Typo3Version $version): static
    {
        return new static($version);
    }

    public static function getIdentifier(): string
    {
        return 'anonymous_table';
    }

    protected function getTableSchemas(): array
    {
        return [
            'tx_anonymous_table' => [
                'uid' => 'INTEGER PRIMARY KEY AUTOINCREMENT',
                'data' => 'TEXT'
            ]
        ];
    }
};

$database->addTable($customTable);
$customTable->addRow(['data' => 'test'], 'tx_anonymous_table');
```

Feature Access
--------------

[](#feature-access)

```
// Get feature
$database = $builder->getFeature(\Typo3DevSpringboard\Feature\Database::class);
$fileSystem = $builder->getFeature(\Typo3DevSpringboard\Feature\FileSystem::class);
$request = $builder->getFeature(\Typo3DevSpringboard\Feature\Request::class);
$site = $builder->getFeature(\Typo3DevSpringboard\Feature\Site::class);

// Remove feature
$builder->removeFeature(\Typo3DevSpringboard\Feature\Site::class);
```

Core Features
-------------

[](#core-features)

- **Request**: HTTP request simulation
- **FileSystem**: Directory and config file management
- **Site**: Site configuration (config.yaml)
- **Database**: SQLite database and tables

Built-in Tables
---------------

[](#built-in-tables)

- **Pages**: pages table
- **TtContent**: tt\_content table
- **Template**: sys\_template table
- **Caches**: All cache tables
- **GenericTable**: Custom table handler

Testing Example
---------------

[](#testing-example)

```
class ExtensionTest extends \PHPUnit\Framework\TestCase
{
    public function testOutput(): void
    {
        $output = Builder::make(Typo3Version::TYPO3_13_LTS)
            ->installDir(__DIR__ . '/../.Build')
            ->withRequest('/test')
            ->build()
            ->execute(true);

        $this->assertStringContainsString('expected', $output);
    }
}
```

CLI Usage
---------

[](#cli-usage)

```
$uri = $_SERVER['argv'][1] ?? '/';

Builder::make(Typo3Version::TYPO3_13_LTS)
    ->installDir(__DIR__ . '/.Build')
    ->withRequest($uri)
    ->build()
    ->execute();
```

Complex Example
---------------

[](#complex-example)

```
// Custom feature with dependencies
class MyFeature implements Typo3FeatureInterface
{
    public function requiredFeatureIdentifier(): array
    {
        return ['Database', 'FileSystem'];
    }

    public function execute(array $features): static
    {
        $database = $features['Database'];
        $fileSystem = $features['FileSystem'];
        // Use dependencies
        return $this;
    }
}

// Custom table with default values
$genericTable = $database->getTable(GenericTable::class)
    ->addTableSchema('tx_ext_table', [...])
    ->withDefaultDataCallable(function($data, $table) {
        $data['tstamp'] ??= time();
        $data['crdate'] ??= time();
        return $data;
    });

// Multiple languages with specific IDs
$builder
    ->setSiteLanguage(SiteLanguage::EN, 0)
    ->setSiteLanguage(SiteLanguage::DE, 1)
    ->addSiteLanguage(/* custom languages */);

// Custom site configuration
$builder->setSiteConfig([
    'rootPageId' => 1,
    'base' => 'https://example.com/',
    'languages' => [/* custom */]
]);
```

Additional Information
----------------------

[](#additional-information)

[FeatureSystem.md](FeatureSystem.md) a Deepdive into the Feature System and how it works

License
-------

[](#license)

MIT

###  Health Score

17

—

LowBetter than 6% of packages

Maintenance43

Moderate activity, may be stable

Popularity4

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity13

Early-stage or recently created project

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

### Community

Maintainers

![](https://www.gravatar.com/avatar/08917c31f7650fae5b1fadd0b50e1cb992db0249e51ad9817f857af192bf0cae?d=identicon)[brannow](/maintainers/brannow)

---

Top Contributors

[![brannow](https://avatars.githubusercontent.com/u/19426486?v=4)](https://github.com/brannow "brannow (12 commits)")

### Embed Badge

![Health badge](/badges/brannow-typo3-dev-springboard/health.svg)

```
[![Health](https://phpackages.com/badges/brannow-typo3-dev-springboard/health.svg)](https://phpackages.com/packages/brannow-typo3-dev-springboard)
```

###  Alternatives

[laravel/telescope

An elegant debug assistant for the Laravel framework.

5.2k67.8M192](/packages/laravel-telescope)[spiral/roadrunner

RoadRunner: High-performance PHP application server and process manager written in Go and powered with plugins

8.4k12.2M84](/packages/spiral-roadrunner)[nolimits4web/swiper

Most modern mobile touch slider and framework with hardware accelerated transitions

41.8k177.2k1](/packages/nolimits4web-swiper)[laravel/dusk

Laravel Dusk provides simple end-to-end testing and browser automation.

1.9k36.7M259](/packages/laravel-dusk)[laravel/prompts

Add beautiful and user-friendly forms to your command-line applications.

708181.8M596](/packages/laravel-prompts)[cakephp/chronos

A simple API extension for DateTime.

1.4k47.7M121](/packages/cakephp-chronos)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
