Symfony4 - Doctrine Cross Database присоединяется к конфигурации - PullRequest
0 голосов
/ 03 мая 2018

Мне нужны кросс-отношения с базами данных, я читал об этом Однако я не могу получить то, что хочу, из-за проблемы с отображением. Это моя ситуация

namespace App\Entity\Utility;

use Doctrine\ORM\Mapping as ORM;
use App\Entity\Crm\User;

/**
 * Description of Test
 *
 * @ORM\Table(name="fgel_utility.fgel_test")
 * @ORM\Entity(repositoryClass="App\Repository\Utility\TestRepository")
 */
class Test
{
     /**
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;


    /**
     * 
     * @var User
     * 
     * @ORM\ManyToOne(targetEntity="App\Entity\Crm\User")
     * @ORM\JoinColumn(name="user_cod", referencedColumnName="AUCUT") 
     */
    protected $user = null;

    public function getId()
    {
        return $this->id;
    }

    public function getUser(): User
    {
        return $this->user;
    }

    public function setId($id)
    {
        $this->id = $id;
        return $this;
    }

    public function setUser(User $user)
    {
        $this->user = $utente;
        return $this;
    }
}


namespace App\Entity\Crm;

use Doctrine\ORM\Mapping as ORM;
/**
 * 
 * @ORM\Table(name="crm.USER")
 * @ORM\Entity(repositoryClass="App\Repository\FintelGasDati\AnuteRepository")
 */
class User
{

    /**
     * 
     * @ORM\Id
     * @ORM\Column(name="AUCUT", type="integer", nullable=false)
     */
    protected $codiceCliente;

    # SOME CODE
}

Моя доктрина.yaml

doctrine:
    orm:
        default_entity_manager: default
        entity_managers:
            #################################
            # Update schema only with this em
            #################################
            default:
                connection: mssql_1
                mappings:
                    Utility:
                        type:     "annotation"    
                        # The directory for entity (relative to bundle path)
                        dir:      '%kernel.project_dir%/src/Entity/Utility'   
                        prefix:   'App\Entity\Utility'
                        alias: Utility
            mssql_crm:
                connection: mssql_1
                mappings:
                    Crm:
                        type: "annotation" 
                        # The directory for entity (relative to bundle path)
                        dir: '%kernel.project_dir%/src/Entity/Crm'   
                        prefix: 'App\Entity\Crm'
                        alias: Crm

Таким образом, они используют одно и то же соединение (но разные). Пользователь соединений имеет права на чтение / запись обеих баз данных (но только для изменения схемы в базе данных fgel_utility. Обе базы данных хранятся в SQL Server 2008. Когда я пытаюсь выполнить

php bin/console doctrine:schema:update --dump-sql

Я получаю эту ошибку

Класс 'App \ Entity \ Crm \ User' не найден в настроенной цепочке Пространства имен App \ Entity \ Utility, FOS \ UserBundle \ Model

Ответы [ 2 ]

0 голосов
/ 17 июня 2019

На самом деле вы можете обмануть Doctrine для выполнения запросов к MySQL / MariaDB для соединения между базами данных, просто добавив префикс имени базы данных в аннотации ORM \ Table ваших объектов:

// src/Entity/User.php
@ORM\Table(name="dbname.users")

Это будет использоваться Doctrine во всех операторах SELECT, JOIN.

То, что было сказано, используя это решение, DB_NAME из DATABASE_URL или любые другие значения ваших env-файлов не будут использоваться, что может привести к путанице (поскольку имя базы данных должно быть связано с соединением, а не с сущностью) .

Поскольку вы не можете разрешить динамическое значение в ваших сопоставлениях ORM, таких как "@ORM \ Table (name =% env (DBNAME)%. Users"), но ниже приведен пример использования LoadClassMetadata. событие из Doctrine для динамического выполнения этой работы.

Конструктор класса принимает пространство имен Entities в качестве первого аргумента и имя базы данных в качестве второго аргумента.

Когда Doctrine запускает загрузку метаданных, он запускает метод обратного вызова с классом метаданных для каждой сущности, для которого вы можете динамически обрабатывать и устанавливать имя таблицы из этих значений.

// src/DatabasePrefixer.php
class DatabasePrefixer implements EventSubscriber
{
    private $namespace;
    private $tablePrefix;

    /**
    * @param $namespace string The fully qualified entity namespace to add the prefix
    * @param $tablePrefix string The prefix
    */
    public function __construct($namespace, $tablePrefix)
    {
        $this->namespace = $namespace;
        $this->tablePrefix = $tablePrefix;
    }

    public function getSubscribedEvents()
    {
        return ['loadClassMetadata'];
    }

    public function loadClassMetadata(LoadClassMetadataEventArgs $eventArgs)
    {
        $classMetadata = $eventArgs->getClassMetadata();

        if ($this->namespace == $classMetadata->namespace) {
          $classMetadata->setTableName(sprintf('%s.%s', $this->tablePrefix, $classMetadata->table['name']));
        }
    }
}

Предположим, что у вас есть переменная env DB_NAME, настройте класс в качестве службы в вашем config / services.yml, используя функции разрешения yaml в Symfony и пометив события для прослушивания правильного события Doctrine:

    // config/services.yaml
    services:
    [...]
    dbname.prefixer:
    class: App\DatabasePrefixer
    arguments:
        $namespace:   'App\Entity'
        $tablePrefix: '%env(DB_NAME)%'
        tags:
            - { name: doctrine.event_listener, event: loadClassMetadata, lazy: true }
0 голосов
/ 03 мая 2018

В соответствии с этим https://github.com/doctrine/doctrine2/issues/6350 перекрестные объединения баз данных между разными менеджерами сущностей (одинаковые соединения) не поддерживаются.

...