Symfony3:服务无法获取参数

时间:2016-07-22 10:44:57

标签: service dependency-injection model doctrine symfony

我已经提供了一个服务来在我的模型中获取Doctrine连接(不确定它是否是一个很好的方法,但我不想每次都将连接从控制器传递给模型构造函数。)

所以我想说我想要控制器中的产品

public function getProductsAction(Request $request) {
    $product_model = new ProductModel();
    return $product_model->getProducts();
}

我有产品模型,它将访问帮助程序以获取“database_connection”

use AppBundle\Helper\ContainerHelper;

class ProductModel {
    function getProducts() {
        $helper = new ContainerHelper();
        $db = $helper->getDoctrine();

        $query = "SELECT * FROM customer_products;";
        $statement = $db->prepare($query);

        $statement->execute();
        $result = $statement->fetchAll(PDO::FETCH_ASSOC);
        return $result;
    }
}

现在这个助手在src / AppBundle / Helper / ContainerHelper.php中定义

namespace AppBundle\Helper;

use Symfony\Component\DependencyInjection\ContainerInterface as Container;

class ContainerHelper {

    private $container;

    public function __construct(Container $container) {
        $this->container = $container;
    }

    public static function getDoctrine() {
        $database_connection = $this->container->get('database_connection');
        return $database_connection;
    }

}

让我们说这个服务需要“服务容器”,所以在app / config / services.yml

services:
    app.container_helper:
        class: AppBundle\Helper\ContainerHelper
        arguments: ['@service_container']

但它给了我错误:

  

捕获致命错误:参数1传递给   AppBundle \ Helper \ ContainerHelper :: __ construct()必须实现   接口Symfony \ Component \ DependencyInjection \ ContainerInterface,   没有给出,在\ src \ AppBundle \ Model \ ProductModel.php中调用   在第148行并定义

虽然我相信我已经根据http://symfony.com/doc/current/book/service_container.htmlhttp://anjanasilva.com/blog/injecting-services-in-symfony-2/正确实施了它,但我确定我错过了一些东西或者只是得到了一个坏主意。我需要知道这是一个正确的概念还是我错过的

3 个答案:

答案 0 :(得分:2)

虽然@pavlovich正试图修复你现有的代码,但我真的认为你使这个问题变得更加复杂。 ProductModel本身应该是一个注入数据库连接的服务。

class ProductModel {
    public function __construct($conn) {
        $this->conn = $conn;
    }
    public function getProducts() {
        $stmt = $this->conn->executeQuery('SELECT * FROM customer_products');
        return $stmt->fetchAll();
   }

services:
    product_model:
        class: AppBundle\...\ProductModel
        arguments: ['@database_connection']

// controller.php
$productModel = $this->get('product_model'); // Pull from container
$products = $productModel->getProducts();

答案 1 :(得分:1)

我建议使用构造函数注入和自动装配,而不是使用帮助程序。它更安全,面向未来,更容易扩展和测试。

在这种情况下,您必须创建ProductRepositoryProductModel的更常见和标准名称)并将其传递给控制器​​。

1。控制器

<?php

class SomeController
{
    /**
     * @var ProductRepository
     */
    private $productRepository;

    public function __construct(ProductRepository $productRepository)
    {
        $this->productRepository = $productRepository;
    }

    public function getProductsAction()
    {
        return $this->productRepository->getProducts();
    }
}

如果您将控制器注册为服务有困难,请使用Symplify\ControllerAutowire bundle

2。 ProductRepository

// src/AppBundle/Repository/ProductRepository.php

namespace AppBundle\Repository;

class ProductRepository
{
    /**
     * @var Doctrine\DBAL\Connection
     */
    private $connection;

    public function __construct(Doctrine\DBAL\Connection $connection)
    {

        $this->connection = $connection;
    }

    public function fetchAll()
    {
        $query = "SELECT * FROM customer_products;";

        $statement = $this->connection->prepare($query);
        $statement->execute();
        return $statement->fetchAll(PDO::FETCH_ASSOC);
    }
}

3。服务注册

# app/cofig/servies.yml

services:
    product_repository:
        class: AppBundle\Repository\ProductRepository
        autowire: true

有关详情,您可以在此处看到类似的问题及答案:Symfony 3 - Outsourcing Controller Code into Service Layer

答案 2 :(得分:1)

使用新版本的Symfony 3.3,添加了一项新功能(自动连线服务依赖项)

https://symfony.com/doc/current/service_container/autowiring.html https://symfony.com/doc/current/service_container/3.3-di-changes.html

使用此功能,我通过以下方式解决了这个问题:

  1. 添加了一个新目录/ src / AppBundle / Model
  2. 在此目录中添加了我的模型类

    namespace AppBundle\Modal;
    
    use Doctrine\ORM\EntityManagerInterface;
    
    class ProductModal
    {
    
       private $em;
    
       // We need to inject this variables later.
       public function __construct(EntityManagerInterface $entityManager)
       {
           $this->em = $entityManager;
       }
    
       // We need to inject this variables later.
       public function getProducts()
       {
           $statement = $this->em->getConnection()->prepare("SELECT * FROM product WHERE 1");
           $statement->execute();
           $results = $statement->fetchAll();
    
           return $results;
        }
    }
    
  3. 在我的app / config / services.yml

    中添加
    AppBundle\Modal\:
       resource: '../../src/AppBundle/Modal/*'
       public: true
    
  4. 在我的控制器中我可以像

    一样使用它
    $products = $this->get(ProductModal::class)->getProducts();
    
  5. P.S。别忘了在控制器中添加use AppBundle\Entity\Product\Product;