# Nettrine ORM

Doctrine/ORM to Nette Framework.

# Content

# Setup

Install package

composer require nettrine/orm
1

Register extension

extensions:
  nettrine.orm: Nettrine\ORM\DI\OrmExtension
1
2

# Relying

Take advantage of enpowering this package with 3 extra packages:

  • doctrine/dbal
  • doctrine/cache
  • symfony/console

# doctrine/dbal

This package relies on doctrine/dbal, use prepared nettrine/dbal integration.

composer require nettrine/dbal
1
extensions:
  nettrine.dbal: Nettrine\DBAL\DI\DbalExtension
1
2

Doctrine ORM needs Doctrine DBAL to be configured. If you register nettrine/dbal extension it will detect it automatically.

Doctrine DBAL provides powerful database abstraction layer with many features for database schema introspection, schema management and PDO abstraction.

# doctrine/cache

This package relies on doctrine/cache, use prepared nettrine/cache integration.

composer require nettrine/cache
1
extensions:
  nettrine.cache: Nettrine\Cache\DI\CacheExtension
1
2

Doctrine ORM needs Doctrine Cache to be configured. If you register nettrine/cache extension it will detect it automatically.

CacheExtension sets up cache for all important parts: queryCache, resultCache, hydrationCache, metadataCache and secondLevelCache.

This is the default configuration, it uses the autowired driver.

extensions:
  nettrine.orm: Nettrine\ORM\DI\OrmExtension
  nettrine.orm.cache: Nettrine\ORM\DI\OrmCacheExtension
1
2
3

You can also specify a single driver or change the nettrine.orm.cache.defaultDriver for all of them.

nettrine.orm.cache:
  defaultDriver: App\DefaultOrmCacheDriver
  queryCache: App\SpecialDriver
  resultCache: App\SpecialOtherDriver
  hydrationCache: App\SpecialDriver('foo')
  metadataCache: @cacheDriver
1
2
3
4
5
6

secondLevelCache uses autowired driver (or defaultDriver, if specified) for CacheConfiguration setup, but you can also replace it with custom CacheConfiguration.

nettrine.orm.cache:
  secondLevelCache: @cacheConfigurationFactory::create('bar')
1
2

# symfony/console

This package relies on symfony/console, use prepared contributte/console integration.

composer require contributte/console
1
extensions:
  console: Contributte\Console\DI\ConsoleExtension(%consoleMode%)

  nettrine.orm: Nettrine\ORM\DI\OrmExtension
  nettrine.orm.console: Nettrine\ORM\DI\OrmConsoleExtension(%consoleMode%)
1
2
3
4
5

Since this moment when you type bin/console, there'll be registered commands from Doctrine DBAL.

Console Commands

# Configuration

Schema definition

nettrine.orm:
 configuration:
   proxyDir: <path>
   autoGenerateProxyClasses: <boolean>
   proxyNamespace: <string>
   metadataDriverImpl: <service>
   entityNamespaces: <mixed[]>
   customStringFunctions: <mixed[]>
   customNumericFunctions: <mixed[]>
   customDatetimeFunctions: <mixed[]>
   customHydrationModes: <string[]>
   classMetadataFactoryName: <string>
   defaultRepositoryClassName: <string>
   namingStrategy: <class>
   quoteStrategy: <class>
   entityListenerResolver: <class>
   repositoryFactory: <class>
   defaultQueryHints: <mixed[]>
   filters:
     <string>:
       class: <string>
       enabled: <boolean>

 entityManagerDecoratorClass: <class>
 configurationClass: <class>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

Under the hood

Minimal configuration could look like this:

nettrine.orm:
  configuration:
    autoGenerateProxyClasses: %debugMode%
1
2
3

Take a look at real Nettrine ORM configuration example at Nutella Project.

Side notes

  1. The compiler extensions would be so big that we decided to split them into more separate files / compiler extensions.

  2. At this time we support only 1 connection, the default connection. If you need more connections (more databases?), please open an issue or send a PR. Thanks.

  3. Are you looking for custom types? You can register custom types in DBAL, see Nettrine DBAL.

  4. You have to configure entity mapping (see below), otherwise you will get It's a requirement to specify a Metadata Driver error.

# Mapping

Doctrine ORM needs to know where your entities are located and how they are described (mapping).

Additional metadata provider needs to be registered. We provide bridges for these drivers:

  • annotations (Nettrine\ORM\DI\OrmAnnotationsExtension)
  • xml (Nettrine\ORM\DI\OrmXmlExtension)

# Annotations

Are you using @annotations in your entities?

<?php

namespace App\Model\Database;

/**
 * @ORM\Entity
 */
class Category
{

    /**
     * @ORM\Column(type="string", length=32, unique=true, nullable=false)
     */
    protected $username;

    /**
     * @ORM\Column(type="string", columnDefinition="CHAR(2) NOT NULL")
     */
    protected $country;

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

This feature relies on doctrine/annotations, use prepared nettrine/annotations integration.

composer require nettrine/annotations
1
extensions:
  nettrine.annotations: Nettrine\Annotations\DI\AnnotationsExtension
1
2

You will also appreciate ORM => Annotations bridge, use OrmAnnotationsExtension. This is the default configuration, it uses an autowired cache driver. Please note that OrmAnnotationsExtension must be registered after AnnotationsExtension. Ordering is crucial!

extensions:
  # Common
  nettrine.annotations: Nettrine\Annotations\DI\AnnotationsExtension

  # ORM
  nettrine.orm: Nettrine\ORM\DI\OrmExtension
  nettrine.orm.annotations: Nettrine\ORM\DI\OrmAnnotationsExtension

nettrine.orm.annotations:
  mapping: [
    namespace: path
  ]
  excluded: []
1
2
3
4
5
6
7
8
9
10
11
12
13

Example configuration for entity located at app/model/Database folder.

nettrine.orm.annotations:
  mapping:
   App\Model\Database: %appDir%/model/database
1
2
3

# XML

Are you using XML mapping for your entities?

<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
                          https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">

    ...

</doctrine-mapping>
1
2
3
4
5
6
7
8

You will also appreciate ORM => XML bridge, use OrmXmlExtension. This is the default configuration:

extensions:
  nettrine.orm: Nettrine\ORM\DI\OrmExtension
  nettrine.orm.xml: Nettrine\ORM\DI\OrmXmlExtension

nettrine.orm.xml:
  mapping: [
    namespace: path
  ]
  fileExtension: .dcm.xml
  simple: false
1
2
3
4
5
6
7
8
9
10

Using simple you will enable SimplifiedYamlDriver.

# YAML

Are you using YAML mapping for your entities?

# Doctrine.Tests.ORM.Mapping.User.dcm.yml
Doctrine\Tests\ORM\Mapping\User:
  type: entity
  repositoryClass: Doctrine\Tests\ORM\Mapping\UserRepository
  table: cms_users
  schema: schema_name
  readOnly: true
  indexes:
    name_index:
      columns: [ name ]
  id:
    id:
      type: integer
      generator:
        strategy: AUTO
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

You will also appreciate ORM => YAML bridge, use OrmYamlExtension. This is the default configuration:

extensions:
  nettrine.orm: Nettrine\ORM\DI\OrmExtension
  nettrine.orm.yaml: Nettrine\ORM\DI\OrmYamlExtension

nettrine.orm.yaml:
  mapping: [
    namespace: path
  ]
  fileExtension: .orm.yml
1
2
3
4
5
6
7
8
9

# Helpers

MappingHelper

You can use the predefined MappingHelper helper class in your compiler extensions. Be careful, you have to call it in beforeCompile phase.

use Nette\DI\CompilerExtension;
use Nettrine\ORM\DI\Helpers\MappingHelper;

class CategoryExtension extends CompilerExtension
{

  public function beforeCompile(): void
  {
    MappingHelper::of($this)
        ->addAnnotation('App\Model\Database', __DIR__ . '/../app/Model/Database')
        ->addAnnotation('Forum\Modules\Database', __DIR__ . '/../../modules/Forum/Database')
        ->addXml('Gallery1\Modules\Database', __DIR__ . '/../../modules/Gallery1/Database')
        ->addXml('Gallery2\Modules\Database', __DIR__ . '/../../modules/Gallery2/Database', $simple = TRUE)
        ->addYaml('Users\Modules\Database', __DIR__ . '/../../modules/Users/Database');
  }

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# Examples

# 1. Manual example

composer require nettrine/annotations nettrine/cache nettrine/migrations nettrine/fixtures nettrine/dbal nettrine/orm
1
# Extension > Nettrine
# => order is crucial
#
extensions:
  # Common
  nettrine.annotations: Nettrine\Annotations\DI\AnnotationsExtension
  nettrine.cache: Nettrine\Cache\DI\CacheExtension
  nettrine.migrations: Nettrine\Migrations\DI\MigrationsExtension
  nettrine.fixtures: Nettrine\Fixtures\DI\FixturesExtension

  # DBAL
  nettrine.dbal: Nettrine\DBAL\DI\DbalExtension
  nettrine.dbal.console: Nettrine\DBAL\DI\DbalConsoleExtension

  # ORM
  nettrine.orm: Nettrine\ORM\DI\OrmExtension
  nettrine.orm.cache: Nettrine\ORM\DI\OrmCacheExtension
  nettrine.orm.console: Nettrine\ORM\DI\OrmConsoleExtension
  nettrine.orm.annotations: Nettrine\ORM\DI\OrmAnnotationsExtension
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 2. Example projects

We've made a few starter projects with preconfigured Nettrine nad Contributte packages.

# 3. Example playground

You can find more examples in planette playground repository.

# Other

This repository is inspired by these packages.

Thank you guys.