baraja-core / doctrine
Doctrine port to Nette 3.0 with maximal performance.
Installs: 276 692
Dependents: 23
Suggesters: 0
Security: 0
Stars: 12
Watchers: 2
Forks: 4
Open Issues: 5
pkg:composer/baraja-core/doctrine
Requires
- php: ^8.0
- ext-pdo: *
- baraja-core/nette-symfony-console: ^1.0
- baraja-core/network: ^1.0
- baraja-core/url: ^1.1
- doctrine/annotations: ^1.13
- doctrine/orm: ^2.13
- nette/di: ^3.0
- ramsey/uuid: ^4.4
Requires (Dev)
- baraja-core/package-manager: ^3.2
- baraja-core/service-method-invoker: ^2.2
- nette/caching: ^3.0
- phpstan/extension-installer: ^1.1
- phpstan/phpstan: ^1.0
- phpstan/phpstan-deprecation-rules: ^1.0
- phpstan/phpstan-nette: ^1.0
- phpstan/phpstan-strict-rules: ^1.0
- roave/security-advisories: dev-master
- spaze/phpstan-disallowed-calls: ^2.0
- tracy/tracy: ^2.9
- dev-master
- v3.7.5
- v3.7.4
- v3.7.3
- v3.7.2
- v3.7.1
- v3.7.0
- v3.6.0
- v3.5.5
- v3.5.4
- v3.5.3
- v3.5.2
- v3.5.1
- v3.5.0
- v3.4.4
- v3.4.3
- v3.4.2
- v3.4.1
- v3.4.0
- v3.3.1
- v3.3.0
- v3.2.3
- v3.2.2
- v3.2.1
- v3.2.0
- v3.1.0
- v3.0.6
- v3.0.5
- v3.0.4
- v3.0.3
- v3.0.2
- v3.0.1
- v3.0.0
- v2.x-dev
- v2.6.1
- v2.6.0
- v2.5.2
- v2.5.1
- v2.5.0
- v2.4.6
- v2.4.5
- v2.4.4
- v2.4.3
- v2.4.2
- v2.4.1
- v2.4.0
- v2.3.2
- v2.3.1
- v2.3.0
- v2.2.9
- v2.2.8
- v2.2.7
- v2.2.6
- v2.2.5
- v2.2.4
- v2.2.3
- v2.2.2
- v2.2.1
- v2.2.0
- v2.1.1
- v2.1.0
- v2.0.9
- v2.0.8
- v2.0.7
- v2.0.6
- v2.0.5
- v2.0.4
- v2.0.3
- v2.0.2
- v2.0.1
- v2.0.0
- v1.1.0
- v1.0.23
- v1.0.22
- v1.0.21
- v1.0.20
- v1.0.19
- v1.0.18
- v1.0.17
- v1.0.16
- v1.0.15
- v1.0.14
- v1.0.13
- v1.0.12
- v1.0.11
- v1.0.10
- v1.0.9
- v1.0.8
- v1.0.7
- v1.0.6
- v1.0.5
- v1.0.4
- v1.0.3
- v1.0.2
- v1.0.1
- v1.0.0
- dev-dependabot/composer/doctrine/annotations-tw-2.0
- dev-renovate/configure
- dev-env-variable
- dev-em-return-void
- dev-restyled/renovate/configure
- dev-dependabot/add-v2-config-file
This package is auto-updated.
Last update: 2026-01-04 15:59:43 UTC
README
BRJ organisation
Baraja Doctrine Database
A simple and easy to use, maximum performance database layer with connection to Doctrine ORM, which allows you to use all the advantages of OOP and also has full support for Nette 3.
This package automatically installs Doctrine to your project (also sets everything up in the configuration) and runs stably.
Key Features
- Full Doctrine ORM integration with Nette Framework 3.x
- Automatic configuration and setup via DI extensions
- Advanced Tracy debug panel with SQL query profiling
- Built-in UUID and UUID Binary identifier traits
- Custom DQL functions (RAND, ROUND, GEODISTANCE, MATCH AGAINST)
- Multiple caching strategies (APCu, SQLite3, Filesystem)
- Slow query logging and analysis
- Entity inheritance support with discriminator mapping utilities
- Blue Screen exception panels for detailed error debugging
Architecture Overview
+------------------+ +-------------------+ +------------------+
| Nette DI |---->| DatabaseExtension |---->| EntityManager |
| Container | | OrmExtension | | (Doctrine) |
+------------------+ | OrmAnnotations | +------------------+
+-------------------+ |
| v
+-------------------+ +------------------+
| ConnectionFactory |<----| DBAL Connection |
+-------------------+ +------------------+
| |
+-------------------+ v
| Cache Provider | +------------------+
| (APCu/SQLite/FS) | | Tracy QueryPanel |
+-------------------+ +------------------+
Main Components
DI Extensions
| Extension | Purpose |
|---|---|
DatabaseExtension |
Main extension for database connection configuration |
OrmExtension |
Doctrine ORM configuration (proxy classes, naming strategies) |
OrmAnnotationsExtension |
Entity mapping and annotation reader setup |
OrmConsoleExtension |
CLI commands integration |
DbalConsoleExtension |
DBAL CLI commands |
Core Services
| Service | Description |
|---|---|
EntityManager |
Extended Doctrine EntityManager with fluent interface and error handling |
DoctrineHelper |
Utilities for entity inheritance, discriminator mapping, and type remapping |
Repository |
Enhanced base repository with findPairs() and findByConditions() methods |
ConnectionFactory |
Creates and configures DBAL connections with custom types |
Identifier Traits
| Trait | Type | Description |
|---|---|---|
Identifier |
int |
Auto-increment integer ID |
IdentifierUnsigned |
int (unsigned) |
Auto-increment unsigned integer ID |
UuidIdentifier |
string |
UUID v4 stored as string (36 chars) |
UuidBinaryIdentifier |
binary |
UUID v4 stored as binary (16 bytes) for better performance |
Custom DQL Functions
| Function | Description |
|---|---|
RAND() |
Random number generation |
ROUND(value, precision) |
Number rounding |
GEODISTANCE(lat1, lng1, lat2, lng2) |
Geographic distance calculation in km |
MATCH(column) AGAINST(value) |
MySQL fulltext search |
Caching Providers
| Provider | Best For |
|---|---|
ApcuCache |
Production with APCu extension |
SQLite3Cache |
Production without APCu |
FilesystemCache |
Development/fallback |
ArrayCache |
Testing |
📦 Installation
It's best to use Composer for installation, and you can also find the package on Packagist and GitHub.
To install, simply use the command:
$ composer require baraja-core/doctrine
You can use the package manually by creating an instance of the internal classes, or register a DIC extension to link the services directly to the Nette Framework.
Requirements
- PHP 8.0 or higher
- PDO extension
- Nette Framework 3.x
- Optional: APCu extension (recommended for production caching)
- Optional: SQLite3 extension (fallback caching)
Configuration
A model configuration can be found in the common.neon file inside the root of the package.
Basic Database Connection
In the project's common.neon you have to define the database credentials using the baraja.database extension:
baraja.database: connection: host: 127.0.0.1 dbname: sandbox user: root password: root
Connection Options
The following connection options are available:
| Option | Type | Description |
|---|---|---|
url |
string | DSN connection URL |
pdo |
string | Existing PDO instance |
memory |
string | In-memory database |
driver |
string | DBAL driver (default: pdo_mysql) |
driverClass |
string | Custom driver class |
driverOptions |
array | Driver-specific options |
unix_socket |
string | Unix socket path |
host |
string | Database host |
port |
int | Database port |
dbname |
string | Database name |
servicename |
string | Oracle service name |
user |
string | Username |
password |
string | Password |
charset |
string | Character set (default: UTF8) |
portability |
int | Portability mode |
fetchCase |
int | Fetch case mode |
persistent |
bool | Persistent connection |
types |
array | Custom DBAL types |
typesMapping |
array | Type mappings |
wrapperClass |
string | Custom connection wrapper |
serverVersion |
string | Server version hint |
Environment Variable Support
The package supports the DB_URI environment variable for connection configuration:
DB_URI=mysql://user:password@host:3306/dbname
Additionally, you can use DB_NAME to override the database name from the URI.
⚙️ Drivers
In default settings Doctrine uses the MySql driver.
PostgreSQL
You can switch to PostgreSQL by specifying the driver class:
baraja.database: connection: driverClass: Doctrine\DBAL\Driver\PDO\PgSQL\Driver
Other Supported Drivers
pdo_mysql- MySQL (default)pdo_pgsql- PostgreSQLpdo_sqlite- SQLitepdo_sqlsrv- Microsoft SQL Serverpdo_oci- Oracle
Entity Mapping
In order for Doctrine to know which classes are entities and which application logic, it is necessary to set up a mapping.
Configuration
For mapping, it is necessary to set the introductory part of the namespace entities and the directory where they occur:
orm.annotations: paths: App\Baraja\Entity: %rootDir%/app/model/Entity
Excluding Paths
You can exclude specific directories from scanning:
orm.annotations: excludePaths: - %rootDir%/app/model/Entity/Deprecated
Ignoring Annotations
Custom annotations can be ignored:
orm.annotations: ignore: - myCustomAnnotation
Cache Configuration
Configure the annotation cache driver:
orm.annotations: defaultCache: filesystem # Options: apcu, array, filesystem debug: false # Enable for development
Important warning:
The value of the
%rootDir%,%appDir%,%wwwDir%,%vendorDir%and%tempDir%parameters may be corrupted when running schema generation in CLI mode. To resolve this mistake, please install Package Manager and call the command as acomposer dump.
Entity Identifiers
The package provides several traits for entity identification. Insert one trait to define the ID in your entities:
Auto-increment Integer
<?php declare(strict_types=1); namespace App\Entity; use Baraja\Doctrine\Identifier\Identifier; use Doctrine\ORM\Mapping as ORM; #[ORM\Entity] class Article { use Identifier; #[ORM\Column(type: 'string')] private string $title; }
UUID (String)
<?php declare(strict_types=1); namespace App\Entity; use Baraja\Doctrine\UUID\UuidIdentifier; use Doctrine\ORM\Mapping as ORM; #[ORM\Entity] class User { use UuidIdentifier; #[ORM\Column(type: 'string')] private string $email; }
UUID Binary (High Performance)
For better performance, use binary UUID storage:
<?php declare(strict_types=1); namespace App\Entity; use Baraja\Doctrine\UUID\UuidBinaryIdentifier; use Doctrine\ORM\Mapping as ORM; #[ORM\Entity] class Product { use UuidBinaryIdentifier; #[ORM\Column(type: 'string')] private string $name; }
UUID will be generated automatically in PHP using the Ramsey UUID library.
TIP: Read more about UUID binary performance (Czech language)
Generate Database Structure from Entities
This package implements a bridge to automatically execute Doctrine commands.
Update Schema
php www/index.php o:s:u -f --dump-sql
The command o:s:u means orm:schema-tool:update.
Options:
-for--force- Execute changes in SQL--dump-sql- Renders the list of SQL commands that will be executed
Validate Schema
php www/index.php o:v
Available Commands
| Command | Description |
|---|---|
orm:schema-tool:create |
Create database schema |
orm:schema-tool:update |
Update database schema |
orm:schema-tool:drop |
Drop database schema |
orm:validate-schema |
Validate entity mappings |
orm:info |
Show basic information about all mapped entities |
dbal:run-sql |
Execute arbitrary SQL directly |
If everything works fine, the command will create the table core__database_slow_query which is defined in this package and is ready for logging slow queries.
TIP: If you are using Package Manager, you can simply call the
composer dumpcommand.
Working with EntityManager
The package provides an enhanced EntityManager with fluent interface:
<?php use Baraja\Doctrine\EntityManager; class UserService { public function __construct( private EntityManager $entityManager, ) { } public function createUser(string $email): User { $user = new User; $user->setEmail($email); $this->entityManager ->persist($user) ->flush(); return $user; } public function findUser(int $id): ?User { return $this->entityManager->find(User::class, $id); } }
Enhanced Methods
The EntityManager provides better error handling and returns $this for fluent chaining:
$entityManager ->persist($entity1) ->persist($entity2) ->flush();
Event Listeners
Add event listeners directly:
$entityManager->addEventListener(['postPersist'], new MyEventListener());
Repository
The package includes an enhanced Repository class with additional methods:
findPairs()
Get key-value pairs for select boxes:
$repository = $entityManager->getRepository(Category::class); // Returns ['1' => 'Electronics', '2' => 'Books', ...] $pairs = $repository->findPairs('name'); // With custom key column $pairs = $repository->findPairs('name', 'slug');
findByConditions()
Get values with custom conditions:
$repository->findByConditions('id', [ 'e.active = 1', 'e.createdAt > :date', ]);
DoctrineHelper
The DoctrineHelper service provides utilities for working with entity inheritance and metadata:
<?php use Baraja\Doctrine\DoctrineHelper; class ProductService { public function __construct( private DoctrineHelper $doctrineHelper, ) { } public function getProductVariants(string $productClass): array { // Get all discriminator variants of an entity return $this->doctrineHelper->getEntityVariants($productClass); } public function getTableName(string $entityClass): string { // Get real database table name return $this->doctrineHelper->getTableNameByEntity($entityClass); } public function upgradeProductType(Product $product): ?SpecialProduct { // Remap entity to a more specific type return $this->doctrineHelper->remapEntityToBestType($product); } }
Available Methods
| Method | Description |
|---|---|
getEntityVariants() |
Get all discriminator map variants |
getBestOfType() |
Get the most embedded (deepest) entity type |
getTableNameByEntity() |
Get database table name from entity class |
getRootEntityName() |
Get root entity class in inheritance chain |
getDiscriminatorByEntity() |
Get discriminator value for entity |
remapEntityToBestType() |
Elevate entity to best available type |
remapEntity() |
Remap entity from one type to another |
Custom DQL Functions
RAND()
Generate random numbers for sorting:
$query = $entityManager->createQuery(' SELECT e FROM App\Entity\Product e ORDER BY RAND() ');
ROUND()
Round numeric values:
$query = $entityManager->createQuery(' SELECT e, ROUND(e.price, 2) as roundedPrice FROM App\Entity\Product e ');
GEODISTANCE()
Calculate geographic distance between two points (in kilometers):
$query = $entityManager->createQuery(' SELECT e, GEODISTANCE(e.latitude, e.longitude, :lat, :lng) as distance FROM App\Entity\Store e ORDER BY distance ASC ') ->setParameter('lat', 50.0755) ->setParameter('lng', 14.4378);
MATCH AGAINST
MySQL fulltext search:
$query = $entityManager->createQuery(' SELECT e FROM App\Entity\Article e WHERE MATCH(e.title, e.content) AGAINST(:search) > 0 ') ->setParameter('search', 'search term');
Registering Custom Functions
Add your own custom functions:
use Baraja\Doctrine\DatabaseExtension; DatabaseExtension::addCustomNumericFunction('MY_FUNC', MyFunction::class);
Custom Types
Registering Custom Types
Add custom DBAL types:
use Baraja\Doctrine\DatabaseExtension; DatabaseExtension::addCustomType('my_type', MyType::class);
Via Configuration
baraja.database: types: my_type: App\Doctrine\Type\MyType
Built-in Types
| Type | Class |
|---|---|
uuid |
UuidType - UUID as string |
uuid-binary |
UuidBinaryType - UUID as binary |
Caching
The package automatically selects the best available cache:
- APCu (preferred for production)
- SQLite3 (fallback)
- Filesystem (development)
Manual Cache Configuration
baraja.database: cache: apcu # Options: apcu, sqlite, or custom class
Custom Cache Class
baraja.database: cache: App\Cache\MyCustomCache
🐛 Tracy Debug Panel
This package contains the most advanced native tools for debugging your application and SQL queries.
Features
- View all performed SQL queries
- Click directly on the place of query invocation in IDE
- Watch time graphs on the output
- Analyze slow queries
- Write query types displayed separately (SELECT, INSERT, UPDATE, DELETE)
- Transaction highlighting
- Color-coded query duration
Duration Color Coding
| Duration | Color |
|---|---|
| < 5 ms | Default |
| 5-15 ms | Light orange |
| 15-75 ms | Orange |
| 75-150 ms | Dark orange |
| 150-300 ms | Light red |
| 300-500 ms | Red |
| > 500 ms | Dark red |
Blue Screen Integration
The package includes advanced logic for debugging corrupted entities and queries directly through Tracy Bluescreen:
- Driver Exception - Shows SQL query, parameters, and connection troubleshooting
- Query Exception - Displays available fields when accessing non-existent columns
- Mapping Exception - Shows entity file location and annotations
Slow Query Logging
Slow queries are automatically logged to the core__database_slow_query table:
| Column | Type | Description |
|---|---|---|
id |
uuid | Unique identifier |
query |
text | The SQL query |
duration |
float | Execution time in ms |
hash |
string | Query hash for grouping |
inserted_date |
datetime | When the query was logged |
🚀 Performance Best Practices
When Doctrine is used poorly, it can be unnecessarily slow.
For more details (in Czech language): https://ondrej.mirtes.cz/doctrine-2-neni-pomala
Automatic Optimizations
This package uses best-practices to increase the performance:
- Proxy Classes -
autoGenerateProxyClassesis set tofalsefor production - Metadata Caching - Automatic APCu/SQLite3 caching
- Query Caching - DQL query parsing is cached
- Result Caching - Configurable result cache
Manual Optimizations
For maximum performance, consider using Redis:
// See: https://www.doctrine-project.org/projects/doctrine-orm/en/latest/reference/caching.html
UUID Binary Performance
Using UuidBinaryIdentifier instead of UuidIdentifier provides:
- 50% less storage space (16 bytes vs 36 characters)
- Faster indexing and lookups
- Better cache efficiency
ORM Configuration
Advanced ORM settings via orm extension:
orm: proxyDir: %tempDir%/proxies proxyNamespace: App\Proxy autoGenerateProxyClasses: false namingStrategy: Doctrine\ORM\Mapping\UnderscoreNamingStrategy defaultRepositoryClassName: App\Repository\BaseRepository entityNamespaces: App: App\Entity
Available Options
| Option | Default | Description |
|---|---|---|
configurationClass |
Configuration |
Custom configuration class |
entityManagerClass |
EntityManager |
Custom EntityManager class |
proxyDir |
%tempDir%/proxies |
Proxy classes directory |
autoGenerateProxyClasses |
null |
Auto-generate proxy classes |
proxyNamespace |
Baraja\Doctrine\Proxy |
Proxy classes namespace |
metadataDriverImpl |
null |
Custom metadata driver |
entityNamespaces |
[] |
Entity namespace aliases |
customStringFunctions |
[] |
Custom DQL string functions |
customNumericFunctions |
[] |
Custom DQL numeric functions |
customDatetimeFunctions |
[] |
Custom DQL datetime functions |
customHydrationModes |
[] |
Custom hydration modes |
classMetadataFactoryName |
null |
Custom metadata factory |
defaultRepositoryClassName |
null |
Default repository class |
namingStrategy |
UnderscoreNamingStrategy |
Column naming strategy |
quoteStrategy |
null |
Quote strategy |
entityListenerResolver |
null |
Entity listener resolver |
repositoryFactory |
null |
Custom repository factory |
defaultQueryHints |
[] |
Default query hints |
Event Subscribers
Register Doctrine event subscribers via DI:
services: - App\Subscriber\TimestampSubscriber: tags: [doctrine.subscriber]
<?php namespace App\Subscriber; use Doctrine\Common\EventSubscriber; use Doctrine\ORM\Events; class TimestampSubscriber implements EventSubscriber { public function getSubscribedEvents(): array { return [Events::prePersist, Events::preUpdate]; } public function prePersist($args): void { // Set created timestamp } public function preUpdate($args): void { // Set updated timestamp } }
Ignored Annotations
Configure globally ignored annotation names:
baraja.database: propertyIgnoreAnnotations: - sample - endpointName - editable - myCustomAnnotation
Troubleshooting
Connection Refused
Verify your database is running and connection details are correct:
- Check
localhostvs127.0.0.1 - Verify port number (MySQL default: 3306)
- Check firewall settings
Authentication Method Unknown
For MySQL 8.0+, you may need to change the authentication method:
ALTER USER 'myuser' IDENTIFIED WITH mysql_native_password BY 'mypassword';
DigitalOcean Managed Database
When using DigitalOcean managed databases:
- Port must be explicitly defined
- Verify your IP is allowed in the firewall
Schema Out of Sync
Run schema update:
php www/index.php o:s:u -f
Full Configuration Example
extensions: dbal.console: Baraja\Doctrine\DBAL\DI\DbalConsoleExtension orm: Baraja\Doctrine\ORM\DI\OrmExtension orm.console: Baraja\Doctrine\ORM\DI\OrmConsoleExtension orm.annotations: Baraja\Doctrine\ORM\DI\OrmAnnotationsExtension baraja.database: Baraja\Doctrine\DatabaseExtension baraja.database: connection: host: %database.host% dbname: %database.dbname% user: %database.user% password: %database.password% charset: UTF8 cache: apcu propertyIgnoreAnnotations: - sample orm: proxyDir: %tempDir%/proxies namingStrategy: Doctrine\ORM\Mapping\UnderscoreNamingStrategy orm.annotations: paths: App\Entity: %appDir%/model/Entity defaultCache: filesystem debug: %debugMode%
Author
Jan Barasek - https://baraja.cz
📄 License
baraja-core/doctrine is licensed under the MIT license. See the LICENSE file for more details.
