A CLI code generator for Nette Framework. Scaffold presenters, models, repositories, services, Latte templates, and database migrations with a single command — without touching boilerplate ever again.
| Dependency | Version |
|---|---|
| PHP | >= 7.4 |
| symfony/console | ^5.0 || ^6.0 || ^7.0 |
| nette/php-generator | ^3.5 || ^4.0 |
| nette/neon | ^3.3 || ^4.0 |
| doctrine/inflector | ^2.0 |
Optional:
nette/diis required only when integrating viaMakerExtensionin your Nette DI config.
composer require unquam/nette-makerSince this package is a Composer Plugin, during installation Composer will ask:
Do you trust "unquam/nette-maker" to execute code and wish to enable it now? (writes "allow-plugins" to composer.json) [y,n,d,?]
Press y to allow. The plugin will automatically create two files in your project root:
| File | Purpose |
|---|---|
nette |
Executable PHP runner — run php nette <command> |
nette-maker.neon |
Configuration file (database credentials, migrations path) |
If you pressed n, create the runner manually:
cp vendor/bin/nette-maker nette
chmod +x nette
php nette make:initEdit nette-maker.neon in your project root:
# nette-maker.neon
database:
dsn: 'mysql:host=127.0.0.1;dbname=your_database'
user: root
password: ''
migrations:
directory: db/migrations| Key | Type | Description |
|---|---|---|
database.dsn |
string |
PDO DSN — driver is auto-detected from the prefix (mysql, pgsql, sqlite, sqlsrv) |
database.user |
string |
Database username |
database.password |
string |
Database password |
migrations.directory |
string |
Path relative to the config file where migration files are stored (default: db/migrations) |
All commands are available through the php nette runner or through vendor/bin/nette-maker.
php nette <command> [arguments] [options]| Command | Description |
|---|---|
make:init |
Create the default nette-maker.neon config file |
make:presenter <Name> |
Generate a Presenter class |
make:model <Name> |
Generate a Model class |
make:repository <Name> |
Generate a Repository class |
make:service <Name> |
Generate a Service class |
make:latte <Name> |
Generate a Latte template |
make:migration <name> |
Generate a migration file |
make:module <Name> |
Generate a full module (all of the above) |
migrate |
Run pending migrations |
migrate --rollback |
Roll back all ran migrations |
migrate --status |
Show migration status |
Creates nette-maker.neon in the project root.
php nette make:initIf the file already exists the command exits with a warning and does nothing.
Generates a Presenter class in app/Presentation/<Name>/<Name>Presenter.php.
php nette make:presenter Article
# → app/Presentation/Article/ArticlePresenter.phpGenerated class:
<?php
declare(strict_types=1);
namespace App\Presentation\Article;
use Nette\Application\UI\Presenter;
final class ArticlePresenter extends Presenter
{
public function renderDefault(): void
{
}
}Generates a Model class in app/Model/<Name>.php that uses Nette\Database\Explorer.
php nette make:model Article
# → app/Model/Article.phpGenerated class:
<?php
declare(strict_types=1);
namespace App\Model;
use Nette\Database\Explorer;
final class Article
{
public function __construct(private Explorer $explorer)
{
}
}Generates a Repository class in app/Model/Repositories/<Name>Repository.php.
php nette make:repository Article
# → app/Model/Repositories/ArticleRepository.phpGenerated class includes findAll(): Selection and findById(int $id): mixed methods pre-wired to the correct database table via a private TABLE constant.
Generates a Service class in app/Model/Services/<Name>Service.php, pre-injecting the corresponding Repository.
php nette make:service Article
# → app/Model/Services/ArticleService.phpGenerates an empty Latte template at app/Presentation/<Name>/default.latte.
php nette make:latte Article
# → app/Presentation/Article/default.latteGenerates a timestamped migration file in the configured migrations directory.
php nette make:migration CreateArticlesTable
# → db/migrations/2026_05_18_120000_create_articles_table.phpGenerated migration:
<?php
declare(strict_types=1);
use Unquam\NetteMaker\Migration\TableBuilder;
return new class
{
public function up(TableBuilder $builder): void
{
$builder->create('{{table}}', function (TableBuilder $table): void {
$table->id();
// Available column types:
// $table->string('title');
// $table->string('slug', 191);
// $table->text('body');
// $table->integer('views');
// $table->bigInteger('score');
// $table->boolean('is_active');
// $table->float('rating');
// $table->decimal('price', 10, 2);
// $table->timestamp('published_at');
// $table->timestamps();
// Modifiers (chain after a column):
// $table->string('email')->nullable();
// $table->string('role')->default('user');
// $table->string('email')->unique();
// $table->string('name')->after('id'); // MySQL/MariaDB only
// Indexes:
// $table->index('user_id');
// $table->index(['user_id', 'status']);
// Foreign keys:
// $table->foreign('user_id', 'users')->cascadeOnDelete();
// $table->foreign('user_id', 'users', 'id', null, 'SET NULL', 'RESTRICT');
// Composite primary key:
// $table->primary(['user_id', 'role_id']);
$table->timestamps();
});
}
public function down(TableBuilder $builder): void
{
$builder->drop('{{table}}');
// To alter an existing table instead of dropping:
// $builder->table('{{table}}', function (TableBuilder $table): void {
// $table->dropColumn('email');
// $table->dropIndex('idx_{{table}}_email');
// $table->dropForeign('fk_{{table}}_user_id');
// $table->dropPrimary();
// });
}
};$builder->create('table_name', function (TableBuilder $table): void {
$table->id(); // Auto-increment primary key
$table->string('title'); // VARCHAR(255) NOT NULL
$table->string('slug', 191); // VARCHAR(191) NOT NULL
$table->text('body'); // TEXT NOT NULL
$table->integer('views'); // INT NOT NULL
$table->bigInteger('score'); // BIGINT NOT NULL
$table->boolean('is_published'); // BOOLEAN/TINYINT NOT NULL
$table->float('rating'); // FLOAT NOT NULL
$table->decimal('price', 10, 2); // DECIMAL(10,2) NOT NULL
$table->timestamp('published_at'); // TIMESTAMP NULL
$table->timestamps(); // created_at + updated_at
// Modifiers (chain after a column):
$table->string('email')->nullable();
$table->string('role')->default('user');
$table->string('email')->unique();
$table->string('name')->after('id'); // MySQL/MariaDB only
// Indexes:
$table->index('user_id');
$table->index(['user_id', 'status']);
$table->index(['user_id', 'status'], 'custom_index_name');
// Foreign keys:
$table->foreign('user_id', 'users');
$table->foreign('user_id', 'users')->cascadeOnDelete();
$table->foreign('user_id', 'users', 'id', null, 'SET NULL', 'RESTRICT');
// Composite primary key:
$table->primary(['user_id', 'role_id']);
});
// Alter existing table:
$builder->table('table_name', function (TableBuilder $table): void {
$table->dropColumn('email');
$table->dropIndex('idx_table_email');
$table->dropForeign('fk_table_user_id');
$table->dropPrimary();
});
$builder->drop('table_name');
$builder->dropIfExists('table_name');Supported database drivers: mysql, mariadb, pgsql/postgres, sqlite, sqlsrv/mssql.
Scaffolds a complete module in one command: Presenter, Model, Repository, Service, Migration, and Latte template.
php nette make:module ArticleAll parts are optional. Skip specific ones with --no-* flags:
php nette make:module Article --no-migration --no-latte
php nette make:module Article --no-service --no-repository
php nette make:module Article --no-presenter --no-modelGenerate only specific parts with --only:
php nette make:module Article --only=presenter,model
php nette make:module Article --only=migration
php nette make:module Article --only=presenter,model,repository,serviceComma-separated values accepted: presenter, model, repository, service, migration, latte.
Run all pending migrations:
php nette migrateShow migration status:
php nette migrate --statusRoll back all ran migrations:
php nette migrate --rollbackIf your project uses nette/di, you can register all commands as services and wire them into your Symfony Console application via the DI extension.
extensions:
maker: Unquam\NetteMaker\DI\MakerExtension/** @var \Nette\DI\Container $container */
$app = $container->getByType(\Unquam\NetteMaker\Application::class);
exit($app->run());The extension registers every make:* command and the migrate command as individual DI services. This allows them to participate in standard DI autowiring.
Running the commands creates files in the following locations (all relative to your project root by default, or to the directory containing nette-maker.neon when using the nette runner):
app/
├── Model/
│ ├── Article.php # make:model
│ ├── Repositories/
│ │ └── ArticleRepository.php # make:repository
│ └── Services/
│ └── ArticleService.php # make:service
└── Presentation/
└── Article/
├── ArticlePresenter.php # make:presenter
└── default.latte # make:latte
db/
└── migrations/
└── 2026_05_18_120000_create_articles_table.php # make:migration
Contributions are welcome! Please follow these steps:
- Fork the repository.
- Create a feature branch:
git checkout -b feat/my-feature. - Write tests for any new behaviour in
tests/. - Ensure the test suite passes:
composer test. - Follow PSR-12 coding standards.
- Open a pull request against the
mainbranch.
This package is open-sourced software licensed under the MIT licence.