runopencode/query-resources-loader-bundle

提供在项目中“query”目录下将长查询保存在单独文件中的可能性。

8.0.2 2024-08-15 14:28 UTC

README

Packagist Scrutinizer Code Quality Build Status Code Coverage

查询资源加载器的作用是帮助您管理和组织您的大型、长查询,尤其是在处理报告的应用程序中。

功能

  • 将您的查询保存在项目目录或任何其他您想要使用的目录中的单独的 *.sql 文件(或 *sql.twig 文件)中。
  • 使用 RunOpenCode\Bundle\QueryResourcesLoader\Contract\QueryResourcesLoaderInterface 服务加载或执行您的查询。
  • 完全兼容 Doctrine Dbal。您可以将当前查询从存储库类中移动到单独的 SQL 文件,并使用查询加载器来执行它们。执行结果为 Doctrine\DBAL\Driver\Result 实例。当然,还有一些方便的方法可以用来从结果集中获取数据,例如 getSingleScalarResult()getSingleResult()getScalarResult() 等。有关更多详细信息,请参阅 RunOpenCode\Bundle\QueryResourcesLoader\Executor\Dbal\DoctrineDbalExecutionResult 类。
  • 自动将 %kernel.project_dir%/query 目录注册为查询资源目录,以及您束的 Resources 目录中的所有 query 目录。
  • 与 Twig 集成,因此您可以在查询中使用 Twig 语法。您可以使用此功能根据您的应用程序逻辑构建复杂查询。除了控制流语句之外,您还可以使用所有 Twig 过滤器、函数、测试和块。使用 {% include %}{% embed %}{% use %}{% extends %} 语句,您可以重用查询并从较小的查询构建复杂查询。
  • 事务。您可以在事务中执行您的查询。支持 Doctrine Dbal 的 transactional() API。您可以在事务中控制当前语句的事务隔离级别。
  • 分布式事务。您可以在同一事务中对不同数据库执行多个查询。
  • 缓存。您可以缓存查询结果,以便在每次执行时不必从数据库中加载。
  • 中间件。您可以使用中间件在执行之前或执行之后操作查询。如果查询失败,您可以将数据库切换到其他数据库,您还可以添加监控、日志记录、在多个数据库上负载均衡等...

请在此处阅读文档 这里

快速示例

以下是一个示例,说明如何实现一个典型的报告存储库,它包含存储库中的查询字符串

declare(strict_types=1);

namespace App\Repository;

use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Types\Types;

final readonly class MyReportingRepository 
{
    public function __construct(private Connection $connection) { }

    public function getInvoicingReport(\DateTimeInterface $from): iterable
    {
        $sql = 'SELECT 
            
            field_1.T as f1,
            field_2.T as f2,
            
            ...
            
            field_57.X as f57,
            
            ...
            
            field_n.N as fn
            
            FROM 
            
            table_name T
            
            INNER JOIN table_name_2 T2 ON (T.id = T2.t1_id)
            
            INNER JOIN table_name_3 T3 ON (T2.id = T3.t2_id)
            
            ....
            
            [More joins]
            
            WHERE
            
            T.create_at >= :from
            
            [A lot of where statements and so on...]                                           
        ';
        
        return $this->connection->execute($sql, [ 
            'from' => $from 
        ], [
            'from' => Types::DATE_IMMUTABLE        
        ]);            
    }
}

这很糟糕,因为它将 SQL 与 PHP 代码混合在一起,难以维护!

使用此束,您可以将您的查询存储在 %kernel.project_dir%/query 目录中作为标准 .sql 文件(如果您使用 Twig,则为 .sql.twig,或任何其他您查询语言使用的扩展)中,并使用 RunOpenCode\Bundle\QueryResourcesLoader\Contract\QueryResourcesLoaderInterface 服务加载和执行它,从而减少存储库类中的代码量

declare(strict_types=1);

namespace App\Repository;

use RunOpenCode\Bundle\QueryResourcesLoader\Contract\QueryResourcesLoaderInterface;
use RunOpenCode\Bundle\QueryResourcesLoader\Executor\Dbal\DbalParameters;

final readonly class MyReportingRepository 
{
    public function __construct(private QueryResourcesLoaderInterface $loader) { }                 
    
    public function getInvoicingReport(\DateTimeInterface $from): iterable
    {
        return $this->loader->execute('invoicing_report.sql', DbalParameters::create()->dateTimeImmutable('from', $from));      
    }
}

构建复杂查询

有时,您可能需要根据您的应用程序逻辑来构建查询。为此,查询加载器使用Twig,并且您的所有查询资源都使用Twig预先解析,这使得您可以动态地构建查询,例如

# file: my_query.sql.twig
SELECT *
FROM my_table T

WHERE T.field_1 = :some_parameter {% if some_other_parameter is defined %}

    AND T.field_2 = :some_other_parameter 
    
{% endif %}

有关此捆绑包的更多详细信息以及如何使用它的提示,请阅读文档这里

待办事项

  • 为中间件和查询执行添加性能分析。