Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

martin-georgiev's avatar

Adding custom DBAL to Laravel 5

Just recently I on-boarded a Laravel 5 project and faced the problem of extending Doctrine DBAL implementation with custom types supported by Postgres. I have to plug in nicely https://github.com/opensoft/doctrine-postgres-types and https://github.com/boldtrn/JsonbBundle into the application configuration. Coming from Symfony2 I was expecting that there will be a smooth way of adding it to Doctrine's configuration (as in http://symfony.com/doc/current/cookbook/doctrine/dbal.html#registering-custom-mapping-types-in-the-schematool). Sadly it doesn't seem to be the case.

I saw the suggestion mentioned in 2013 by betawax in https://github.com/laravel/framework/issues/1675 , also replied by tylorotwell that there are no plans for such kind of support. I don't feel convinced this is the most right way to do it.

Did anyone overcome this obstacle recently?

0 likes
4 replies
jekinney's avatar

Tyler believes in and worked hard on Eloquent and has repeatedly stated he personally will not provide support for doctrine. Just last month he mentioned it again in his podcast.

Obviously every one has their preference but unfortunately unless you support it yourself your probably out of luck.

FYI he mentioned in the podcast that sites that run laravel and eloquent with millions of hit a day along with hundreds of thousand users run fine so he doesn't understand the few in the laravel community that request support for doctrine as an alternative. And in my humble opinion why would someone pick a framework and arguably take the best feature out.

DirkZz's avatar

@jekinney Do you have a link to that podcast perhaps? The only ones I could find are from may last year.

martin-georgiev's avatar
Level 1

After some further research I've created my own package with support of some additional functions and datatypes for PostgreSql 9.4 on Laravel and Symfony. Here is a working solution for my initial question (see original instructions from https://bitbucket.org/martin_georgiev/postgresql-for-doctrine.git ):

The steps below are based on Laravel 5 integration with FoxxMD's fork of mitchellvanw/laravel-doctrine.

  1. Register the functions and datatype mappings:
# Usually part of config/doctrine.php
<?php

return [
    'entity_managers' => [
        'name_of_your_entity_manager' => [
            'dql' => [
                'string_functions' => [
                    // Array data types related functions
                    'ALL' => 'MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\All',
                    'ANY' => 'MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\Any',
                    'ARRAY' => 'MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\Arr',
                    'ARRAY_APPEND' => 'MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\ArrayAppend',
                    'ARE_OVERLAPING_EACH_OTHER' => 'MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\ArrayAreOverlapingEachOther',
                    'ARRAY_CARDINALITY' => 'MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\ArrayCardinality',
                    'ARRAY_CAT' => 'MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\ArrayCat',
                    'ARRAY_PREPEND' => 'MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\ArrayPrepend',
                    'ARRAY_REMOVE' => 'MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\ArrayRemove',
                    'ARRAY_REPLACE' => 'MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\ArrayReplace',
                    'ARRAY_TO_STRING' => 'MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\ArrayToString',
                    'STRING_TO_ARRAY' => 'MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\StringToArray',

                    // Functions and operators used by both array and json(-b) data types
                    'CONTAINS' => 'MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\Contains',
                    'IS_CONTAINED_BY' => 'MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\IsContainedBy',

                    // Json(-b) data type related functions and operators
                    'JSON_GET_FIELD' => 'MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\JsonGetField',
                    'JSON_GET_FIELD_AS_TEXT' => 'MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\JsonGetFieldAsText',
                    'JSON_GET_OBJECT' => 'MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\JsonGetObject',
                    'JSON_GET_OBJECT_AS_TEXT' => 'MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\JsonGetObjectAsText',
                    'JSONB_ARRAY_ELEMENTS' => 'MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\JsonbArrayElements',
                    'JSONB_ARRAY_ELEMENTS_TEXT' => 'MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\JsonbArrayElementsText',
                    'JSONB_ARRAY_LENGTH' => 'MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\JsonbArrayLength',
                    'JSONB_EACH' => 'MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\JsonbEach',
                    'JSONB_EACH_TEXT' => 'MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\JsonbEachText',
                    'JSONB_EXISTS' => 'MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\JsonbObjectKeys',
                    'JSONB_OBJECT_KEYS' => 'MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\JsonbExists',

                    // Basic text search related functions and operators
                    'TO_TSQUERY' => 'MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\ToTsquery',
                    'TO_TSVECTOR' => 'MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\ToTsvector',
                    'TSMATCH' => 'MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\Tsmatch',
                ],
            ],
            'mapping_types' => [
                'jsonb' => 'jsonb',
                '_jsonb' => 'jsonb[]',
                'jsonb[]' => 'jsonb[]',
            ],
  1. Add EventSubscriber for Doctrine
<?php

namespace Acme\Handlers\Events;

use Doctrine\Common\EventSubscriber as Subscriber;
use Doctrine\DBAL\DBALException;
use Doctrine\DBAL\Event\ConnectionEventArgs;
use Doctrine\DBAL\Events;
use Doctrine\DBAL\Types\Type;

class DoctrineEventSubscriber implements Subscriber
{
    /**
     * @return array
     */
    public function getSubscribedEvents()
    {
        return [
            Events::postConnect,
        ];
    }

    /**
     * @param ConnectionEventArgs $args
     * @throws DBALException
     */
    public function postConnect(ConnectionEventArgs $args)
    {
        Type::addType('jsonb', "\MartinGeorgiev\Doctrine\DBAL\Types\Jsonb");
        Type::addType('jsonb[]', "\MartinGeorgiev\Doctrine\DBAL\Types\JsonbArray");
    }
}
  1. Add the EventSubscriber for Doctrine to a ServiceProvider
<?php

namespace Acme\Providers;

use Config;
use Illuminate\Contracts\Events\Dispatcher as DispatcherContract;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
use Doctrine\Common\Persistence\ManagerRegistry as DoctrineManagerRegistry;
use Acme\Handlers\Events\DoctrineEventSubscriber;

/**
 * Class EventServiceProvider
 * @package Quantum\Providers
 */
class EventServiceProvider extends ServiceProvider
{
    /**
     * Register Doctrine Events as well.
     */
    public function register()
    {
        $this->registerDoctrineEvents();
        $this->registerDoctrineTypeMapping();
    }

    /**
     * Register any other events for your application.
     * @param DispatcherContract $events
     * @return void
     */
    public function boot(DispatcherContract $events)
    {
        parent::boot($events);
    }

    /**
     * Register Doctrine events.
     */
    private function registerDoctrineEvents()
    {
        $eventManager = $this->registry()->getConnection()->getEventManager();
        $eventManager->addEventSubscriber(new DoctrineEventSubscriber);
    }

    /**
     * Register any custom Doctrine type mappings
     */
    private function registerDoctrineTypeMapping()
    {
        $databasePlatform = $this->registry()->getConnection()->getDatabasePlatform();
        $entityManagers = Config::get('doctrine.entity_managers');
        foreach ($entityManagers as $entityManager) {
            if (array_key_exists('mapping_types', $entityManager)) {
                foreach ($entityManager['mapping_types'] as $dbType => $doctrineName) {
                    $databasePlatform->registerDoctrineTypeMapping($dbType, $doctrineName);
                }
            }
        }
    }

    /**
     * Get the entity manager registry
     * @return DoctrineManagerRegistry
     */
    function registry()
    {
        return app(DoctrineManagerRegistry::class);
    }
}

Please or to participate in this conversation.