Как получить доступ к Doctrine внутри пакета PHP? - PullRequest
0 голосов
/ 05 июня 2019

Я создаю пакет PHP, который будет находиться в каталоге /vendor, и для этого потребуется доступ к базе данных с помощью Doctrine. В моем основном коде Symfony 4.2 я могу получить доступ к базе данных, используя автоматическую разводку в конструкторах, таких как:

public function __construct(EntityManagerInterface $em)

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

Я пытаюсь создать пакет, который будет работать как с Symfony, так и без него, поэтому мне действительно нужен необработанный PHP для получения текущего соединения с базой данных (а не нового соединения) без всякой магии автоматического подключения.

Если пакет работает под управлением Symfony, он должен использовать текущее соединение с базой данных Symfony. Если нет, он должен создать свое собственное соединение.

Например, я могу открыть новое соединение следующим образом:

$conn = \Doctrine\DBAL\DriverManager::getConnection($params, $config)

Это прекрасно работает, но мне нужен способ получить текущее соединение с базой данных Symfony (примерно так):

$conn = \Doctrine\DBAL\DriverManager::getCurrentConnection()

К сожалению, такой функции нет, и я не могу понять, как создать свою собственную версию.

Ответы [ 3 ]

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

Позвольте мне понять вашу проблему, вы ищете пакет для обмена с помощью Doctrine Entity Manager Symfony?поэтому позвольте мне поделиться с вами своим опытом.

Это возможно, и нет решения, видимого для чтения или просмотра, поэтому вам нужно просмотреть некоторые пакеты, чтобы понять, как они решают проблему, пакет, который я рассматривал, былпо этой ссылке этот пакет обеспечивает поддержку не только доктрины, но и других платформ, таких как Mongo, поэтому позвольте мне поделиться с вами тем, как они приняли решение.

Во-первых, вам нужно создатьпакет в bitbucket или github, и сделал этот пакет как "type": "symfony-bundle".Я прочитал комментарии ранее, и вы правы, вам нужно создать файл конфигурации и расширения, чтобы включить ваши пакеты, поэтому в вашем файле расширения вам нужно реализовать Symfony \ Component \ DependencyInjection \ Extension \ PrependExtensionInterface thisПакет позволит вам сделать волшебство.так что вы можете написать несколько строк кода, аналогичных этому, и заменить свое пространство имен:

<?php
namespace NameSpaceBundle\CoreBundle\DependencyInjection;

use Exception;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;

/**
 * Class NameSpaceBundleExtension Configurations of the Core
 * @package NameSpaceBundle\CoreBundle\DependencyInjection
 */
class NameSpaceBundleExtension extends Extension implements PrependExtensionInterface
{
    /**
     * {@inheritdoc}
     * @param array $configs
     * @param ContainerBuilder $container
     * @throws Exception
     */
    public function load(array $configs, ContainerBuilder $container)
    {
        $loader = new YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
        $loader->load('services.yml');
        $loader->load('routing.yml');
        $this->processConfiguration(new Configuration(), $configs);
    }
    /**
     * {@inheritdoc}
     * @param ContainerBuilder $container
     */
    public function prepend(ContainerBuilder $container)
    {
        $configs = $container->getExtensionConfig($this->getAlias());
        $this->processConfiguration(new Configuration(), $configs);
        $doctrineConfig = [];
        $doctrineConfig['orm']['mappings'][] = array(
            'name' => 'NameSpaceBundle',
            'is_bundle' => true,
            'type' => 'annotation',
            'prefix' => 'NameSpaceBundle\CoreBundle\Entity'
        );
        $container->prependExtensionConfig('doctrine', $doctrineConfig);
    }
    /**
     * {@inheritdoc}
     * @return string
     */
    public function getAlias()
    {
        return 'bundelName_core';
    }
}

Просмотрите ваш service.yaml, размещенный в Resouces / config, и теперь вы можете внедрять не только EntityManagerInterface.

services:
  _defaults:
    autowire: false      # Automatically injects dependencies in your services.
    autoconfigure: false # Automatically registers your services as commands, event subscribers, etc.
    public: false

  NameSpaceBundle\CoreBundle\Manager\Company:
    public: false
    class: NameSpaceBundle\CoreBundle\Doctrine\CompanyManager
    arguments:
      - '@doctrine'
      - '\NameSpaceBundle\CoreBundle\Entity\Company'

Также этот пример похож на некоторые пакеты FriendsOfSymfony и пакет, о котором я говорил вам ранее.

PD.Извините за мой английский не мой родной язык

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

После нескольких дней попыток создать пакет Symfony, чтобы все работало «официально», я нашел способ взлома, который получает соединение с Symfony Doctrine и делает то, что мне нужно.Он основан на том факте, что $kernel является глобальным Symfony:

// Singleton to get Doctrine database connection
//
// If we are running on the legacy system, it will open a new database connection.
//
// If we are running under Symfony, it will use the existing Doctrine
// connection.

class Doctrine
{
     static private $instance = null;
     private $conn;

     // The database connection is established in a private constructor
     private function __construct()
     {
         global $kernel;

         if (class_exists('\config')) {
             // running on legacy system
             $cfg = new \config();

             //
             // set up Doctrine connection
             //
             $params = [
                 'driver'   => 'pdo_mysql',
                 'user'     => $cfg->db_username,
                 'password' => $cfg->db_password,
                 'host'     => $cfg->db_hostname,
                 'dbname'   => $cfg->db_name,
             ];
             $config = new \Doctrine\DBAL\Configuration();

             $this->conn = \Doctrine\DBAL\DriverManager::getConnection($params, $config);
         } else {
             // running on Symfony system
             $this->conn = $kernel->getContainer()->get('doctrine.orm.default_entity_manager')->getConnection();
         }
     }

     static public function getInstance()
     {
         if (!self::$instance) {
             self::$instance = new Doctrine();
         }

         return self::$instance;
     }

     static public function connection()
     {
         return self::getInstance()->getConnection();
     }

     public function getConnection()
     {
         return $this->conn;
     }
 }

Используя этот класс, этот простой оператор получит соединение Doctrine как в Symfony, так и в нашем устаревшем коде:

$conn = Doctrine::connection()

Теперь мы можем использовать одни и те же библиотеки как для Symfony, так и для нашего старого кода.Да, я знаю, что это взлом, но его легче понять и поддерживать, чем 10+ файлов и десятки строк кода, необходимых для создания даже простого пакета Symfony (а устаревшая система не распознает пакет).Я поместил этот класс в закрытый пакет composer, который может использоваться как устаревшими системами, так и Symfony.Это значительно облегчит работу, пока мы не сможем перенести все устаревшие компоненты в Symfony.После того, как это будет сделано, я смогу сделать все правильно.

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

Вы должны определить класс как службу и добавить EntityManager в качестве аргумента:

# vendor/Acme/HelloBundle/Resources/Config/services.yml

services:
    acme_hellp.service_id:
        class: Acme\HelloBundle\Class   
        arguments: ['@doctrine.orm.entity_manager']   

// src/Acme/HelloBundle/DependencyInjection/AcmeHelloExtension.php

namespace Acme\HelloBundle\DependencyInjection;

use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\Extension;

class AcmeHelloExtension extends Extension
{
    public function load(array $configs, ContainerBuilder $container)
    {
        $loader = new XmlFileLoader(
           $container,
           new FileLocator(__DIR__.'/../Resources/config')
        );
        $loader->load('services.xml');
    }
}

Кроме того, ознакомьтесь с документацией на сайте Symfony по загрузке файлов конфигурации: https://symfony.com/doc/current/bundles/extension.html

...