| 
1 | 1 | # Proposed solution  | 
2 | 2 | 
 
  | 
3 |  | -Solution is inspired by Symfony's way of loading templates into a controller  | 
4 |  | -and rendering response.  | 
 | 3 | +Solution is inspired by Symfony's way of loading templates into a controller and rendering response.  | 
5 | 4 | 
 
  | 
6 |  | -Symfony proposes convention where template code is separated (as per MVC)  | 
7 |  | -from application logic and held in `templates` (or `Resources/views`) directory.  | 
8 |  | -Required rendering logic can be coded in templates by using very powerful templating   | 
9 |  | -language Twig. Rendering of templates is executed via dedicated service,  | 
10 |  | -while templates are identified via path or bundle resource locator syntax   | 
11 |  | -(e.g. `@BundleName::template.html.twig`).  | 
 | 5 | +Symfony proposes convention where template code is separated (as per MVC) from application logic and held in  | 
 | 6 | +`templates` (or `Resources/views`) directory. Required rendering logic can be coded in templates by using very powerful  | 
 | 7 | +templating language Twig. Rendering of templates is executed via dedicated service, while templates are identified via  | 
 | 8 | +path or bundle resource locator syntax(e.g. `@BundleName::template.html.twig`).  | 
12 | 9 | 
 
  | 
13 |  | -Inspired with that convention, this bundle proposes similar approach (if   | 
14 |  | -not the same approach):  | 
 | 10 | +Inspired with that convention, this bundle proposes similar approach:  | 
15 | 11 | 
 
  | 
16 |  | -- Your queries are held in separate files in your bundles, in `query` or   | 
17 |  | -`Resources/query` directories (or any other per your desire).   | 
 | 12 | +- Your queries are held in separate files in `query` directory of your application (or `Resources/query` directories for  | 
 | 13 | +  bundles, or any other per your desire).  | 
18 | 14 | - Queries are files where only query code should exist.  | 
19 |  | -- Complex queries with some kind of query building logic can use Twig as   | 
20 |  | -pre-processing script language.  | 
21 |  | -- You can use a dedicated service `runopencode.query_loader` to load query from   | 
22 |  | -its location by using service locator (which is bad practice) or inject the instance  | 
23 |  | -of `RunOpenCode\Bundle\QueryResourcesLoader\Contract\ManagerInterface` into your class   | 
24 |  | -and let dependency injection do its magic (recommended).  | 
 | 15 | +- Complex queries with some kind of query building logic can use Twig as pre-processing script language.  | 
 | 16 | +- You can use a dedicated service `RunOpenCode\Bundle\QueryResourcesLoader\Contract\QueryResourcesLoaderInterface` to  | 
 | 17 | +  load query from its location and execute it.  | 
25 | 18 | 
 
  | 
26 | 19 | ## Example  | 
27 | 20 | 
 
  | 
28 |  | -In image below, a real-world example of directory structure of project  | 
29 |  | -reporting bundle which uses this bundle is presented:  | 
 | 21 | +In image below, a real-world example of directory structure of project reporting bundle which uses this bundle is  | 
 | 22 | +presented:  | 
30 | 23 | 
 
  | 
31 | 24 |   | 
32 | 25 | 
 
  | 
33 |  | -In that matter, in order to execute the query stored within one of those files,  | 
34 |  | -following code can be used for data source/repository class:  | 
 | 26 | +**NOTE**: _This image is from project using Symfony 3, that is how old this bundle is, but it is still actively  | 
 | 27 | +maintained, battle tested and used in production for latest Symfony version._  | 
35 | 28 | 
 
  | 
36 |  | -    // file: ReportingBundle/Repository/ReportingDataSource.php  | 
37 |  | -      | 
38 |  | -    namespace MyApp\ReportingBundle\Repository;  | 
39 |  | -      | 
40 |  | -    use RunOpenCode\Bundle\QueryResourcesLoader\Contract\ManagerInterface;  | 
41 |  | -      | 
42 |  | -    final class ReportingDataSource  | 
 | 29 | +In that matter, in order to execute the query stored within one of those files, following code can be used for data  | 
 | 30 | +source/repository class:  | 
 | 31 | + | 
 | 32 | +```php  | 
 | 33 | +declare(strict_types=1);  | 
 | 34 | + | 
 | 35 | +namespace App\Reporting\Repository;  | 
 | 36 | + | 
 | 37 | +use RunOpenCode\Bundle\QueryResourcesLoader\Contract\QueryResourcesLoaderInterface;  | 
 | 38 | +use RunOpenCode\Bundle\QueryResourcesLoader\Executor\Dbal\DbalParameters;  | 
 | 39 | + | 
 | 40 | +final readonly class ReportingDataSource  | 
 | 41 | +{  | 
 | 42 | +    public function __construct(private QueryResourcesLoaderInterface $loader) { }       | 
 | 43 | + | 
 | 44 | +    public function getLedgerData(Filters $filters): iterable  | 
43 | 45 |     {  | 
44 |  | -        private ManagerInterface $queryLoader;  | 
45 |  | -      | 
46 |  | -        public function __construct(ManagerInterface $queryLoader)  | 
47 |  | -        {  | 
48 |  | -            $this->queryLoader = $queryLoader;  | 
49 |  | -        }  | 
50 |  | -      | 
51 |  | -        public function getLedgerData(array $filters = []): iterable  | 
52 |  | -        {  | 
53 |  | -            return $this->queryLoader->execute('@MyAppReporting/common.ledger.sql', array(  | 
54 |  | -                'year' => !empty($filters['year']) ? $filters['year'] : date('Y')  | 
55 |  | -            ));  | 
56 |  | -        }  | 
 | 46 | +        return $this->loader->execute('common.ledger.sql', DbalParameters::create()  | 
 | 47 | +            ->dateTimeImmutable('from', $filters->getFrom())  | 
 | 48 | +            ->dateTimeImmutable('to', $filters->getTo())  | 
 | 49 | +            ->integer('account', $filters->getAccount())  | 
 | 50 | +        );  | 
57 | 51 |     }  | 
58 |  | -      | 
59 |  | -If you do not use autowiring, you should register your data source class within service  | 
60 |  | -container:  | 
61 |  | - | 
62 |  | -    // file: ReportingBundle/Resources/config/services.yml  | 
63 |  | -      | 
64 |  | -    services:  | 
65 |  | -      | 
66 |  | -        MyApp\ReportingBundle\Repository\ReportingDataSource:  | 
67 |  | -            arguments: [ "@RunOpenCode\Bundle\QueryResourcesLoader\Contract\ManagerInterface" ]  | 
68 |  | -              | 
69 |  | -Note how your code gets cleaner by just omitting query statements from   | 
70 |  | -your PHP code.  | 
71 |  | -              | 
72 |  | -              | 
 | 52 | +}  | 
 | 53 | +```  | 
 | 54 | + | 
 | 55 | +Note how your code gets cleaner by just omitting query statements from your PHP code.  | 
 | 56 | + | 
 | 57 | +Do note that Doctrine query language for fetching entities is not powerful as raw SQL. However, with this bundle, you  | 
 | 58 | +can easily leverage raw SQL queries to fetch identifiers of entities and then fetch entities with Doctrine.  | 
 | 59 | + | 
73 | 60 | [<< Introduction](introduction.md) | [Table of contents](index.md) | [Twig support >>](twig-support.md)  | 
0 commit comments