Skip to content

Commit dc3abbf

Browse files
committed
Fixing CS fixer
1 parent 12e9306 commit dc3abbf

File tree

10 files changed

+280
-262
lines changed

10 files changed

+280
-262
lines changed

Pipfile

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,4 @@ python-dotenv = "*"
1111
[dev-packages]
1212

1313
[requires]
14-
python_version = "3.9"
14+
python_version = ">=3.9"

Pipfile.lock

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/doctrine-dbal-executor-result.md

+17-19
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,28 @@
11
# DoctrineDbalExecutorResult
22

3-
Bundle, by default, provides you with support for executing SQL statements
4-
against a relational database via Doctrine Dbal.
3+
Bundle, by default, provides you with support for executing SQL statements against a relational database via Doctrine
4+
Dbal.
55

66
Result set is provided as instance of
7-
`RunOpenCode\Bundle\QueryResourcesLoader\Executor\DoctrineDbalExecutorResult`,
8-
which is wrapper of Doctrine's Dbal `Doctrine\DBAL\Driver\Statement` implementation
9-
with additional, useful, utility methods that can improve your productivity
10-
when working with SQL queries
11-
(see `RunOpenCode\Bundle\QueryResourcesLoader\Contract\ExecutionResultInterface`):
7+
`RunOpenCode\Bundle\QueryResourcesLoader\Executor\Dbal\DoctrineDbalExecutionResult`, which is wrapper of Doctrine's Dbal
8+
`Doctrine\DBAL\Driver\Result` implementation with additional, useful, utility methods that can improve your productivity
9+
when working with SQL queries.
10+
11+
See [ExecutionResultInterface.php](../src/RunOpenCode/Bundle/QueryResourcesLoader/Contract/ExecutionResultInterface.php)
12+
and [DoctrineDbalExecutionResult.php](../src/RunOpenCode/Bundle/QueryResourcesLoader/Executor/Dbal/DoctrineDbalExecutionResult.php)
13+
for more details.
1214

1315
- `getSingleScalarResult()` - Get single scalar result.
14-
- `getSingleScalarResultOrDefault()` - Get single scalar result or default
15-
value if there are no results of executed SELECT statement.
16-
- `getSingleScalarResultOrNull()` - Get single scalar result or NULL value
17-
if there are no results of executed SELECT statement.
16+
- `getSingleScalarResultOrDefault()` - Get single scalar result or default value if there are no results of executed
17+
SELECT statement.
18+
- `getSingleScalarResultOrNull()` - Get single scalar result or NULL value if there are no results of executed SELECT
19+
statement.
1820
- `getScalarResult()` - Get collection of scalar values.
19-
- `getScalarResultOrDefault()` - Get collection of scalar vales,
20-
or default value if collection is empty.
21-
- `getScalarResultOrNull()` - Get collection of scalar vales, or NULL value
22-
if collection is empty.
21+
- `getScalarResultOrDefault()` - Get collection of scalar vales, or default value if collection is empty.
22+
- `getScalarResultOrNull()` - Get collection of scalar vales, or NULL value if collection is empty.
2323
- `getSingleResult()` - Get single (first) row result from result set.
24-
- `getSingleResultOrDefault()` - Get single (first) row result from result set
25-
or default value if result set is empty.
26-
- `getSingleResultOrNull()` - Get single (first) row result from result set
27-
or NULL value if result set is empty.
24+
- `getSingleResultOrDefault()` - Get single (first) row result from result set or default value if result set is empty.
25+
- `getSingleResultOrNull()` - Get single (first) row result from result set or NULL value if result set is empty.
2826

2927
Note that `ExecutionResultInterface` implements `\Traversable` and `\Countable`.
3028

docs/faq.md

+5-5
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,12 @@ each other.
1111

1212
## Why `dmaicher/doctrine-test-bundle` does not work with queries having transaction statements in it?
1313

14-
First, it is not recommended to have `BEGIN TRANSACTION`, `COMMIT` statements in your queries at all, if you need to
14+
First, it is not recommended to have `START TRANSACTION`, `COMMIT` statements in your queries at all, if you need to
1515
have them, you can use `transactional()` method of `ExecutorInterface`.
1616

17-
That being said, `dmaicher/doctrine-test-bundle`
18-
tracks transactions of `Connection` object. If you use `BEGIN TRANSACTION` statement in your
19-
query, `dmaicher/doctrine-test-bundle` is not able to roll back them, because those are not explicitly tracked
20-
by `Connection` object.
17+
That being said, `dmaicher/doctrine-test-bundle`tracks transactions of `Connection` object. If you use
18+
`START TRANSACTION` statement in your query, `dmaicher/doctrine-test-bundle` is not able to roll back them, because
19+
those are not explicitly tracked by `Connection` object.
20+
2121

2222
[FAQ](faq.md) | [Table of contents](index.md)

docs/introduction.md

+58-61
Original file line numberDiff line numberDiff line change
@@ -1,74 +1,71 @@
11
# Introduction
22

3-
For reporting libraries/modules within typical PHP application
4-
(if stored procedures or views are not used) usual
5-
practice is to hold database query within repository classes, or other class
6-
services.
3+
For, in example, reporting libraries/modules within typical PHP application (if stored procedures or views are not used)
4+
usual practice is to hold database query within repository classes, or other class services.
75

86
Typical example would look like in pseudocode given below:
97

10-
final class MyReportingRepository
8+
```php
9+
declare(strict_types=1);
10+
11+
use Doctrine\DBAL\Connection;
12+
13+
final readonly class MyReportingRepository
14+
{
15+
public function __construct(private Connection $db) {}
16+
17+
public function getInvoicingReportData($year): iterable
1118
{
12-
private $db;
13-
14-
public function getInvocingReportData($year): iterable
15-
{
16-
$sql = 'SELECT
17-
18-
field_1.T as f1,
19-
field_2.T as f2,
20-
21-
...
22-
23-
field_57.X as f57,
24-
25-
...
26-
27-
field_n.N as fn
28-
29-
FROM
30-
31-
table_name T
32-
33-
INNER JOIN table_name_2 T2 ON (T.id = T2.t1_id)
34-
35-
INNER JOIN table_name_3 T3 ON (T2.id = T3.t2_id)
36-
37-
....
38-
39-
[More joins]
40-
41-
WHERE
42-
43-
T.year = :year
44-
45-
[A lot of where statements and so on...]
46-
';
19+
$sql = 'SELECT
20+
21+
field_1.T as f1,
22+
field_2.T as f2,
23+
24+
...
25+
26+
field_57.X as f57,
27+
28+
...
29+
30+
field_n.N as fn
31+
32+
FROM
4733

48-
$this->db->execute($sql, array(
49-
'year' => $year
50-
));
51-
}
34+
table_name T
35+
36+
INNER JOIN table_name_2 T2 ON (T.id = T2.t1_id)
37+
38+
INNER JOIN table_name_3 T3 ON (T2.id = T3.t2_id)
39+
40+
....
41+
42+
[More joins]
43+
44+
WHERE
45+
46+
T.year = :year
47+
48+
[A lot of where statements and so on...]
49+
';
50+
51+
$this->db->execute($sql, array(
52+
'year' => $year
53+
));
5254
}
55+
}
56+
```
5357

58+
Having in mind example given above, here is a short list of identified issues with this kind of approach:
5459

55-
Having in mind example given above, here is a short list of identified
56-
issues with this kind of approach:
57-
58-
- Method size can easily go over 30 lines of code, which is against good
59-
coding practice.
60-
- Consequently, class size can easily go over few hundred lines of code,
61-
also against good coding practice.
62-
- Using RAD tools with some kind of SQL builder which have syntax checker,
63-
autocomplete and testing and executing playground is impossible to use while
64-
building a query statement.
65-
- Mixing of query statements with application code seams wrong, almost like
66-
mixing HTML and PHP together.
67-
- You cannot just send your code to DB expert to help you optimise/write
68-
some complex query if he is not familiar with PHP and Symfony, he will not
69-
be able to work on a query without your assistance.
60+
- Method size can easily go over 30 lines of code, which is against good coding practice.
61+
- Consequently, class size can easily go over few hundred lines of code, also against good coding practice.
62+
- Using RAD tools with some kind of SQL builder which have syntax checker, autocomplete and testing and executing
63+
playground is impossible to use while building a query statement.
64+
- Mixing of query statements with application code seams wrong, almost like mixing HTML and PHP together.
65+
- You cannot just send your code to DB expert to help you optimise/write some complex query if he is not familiar with
66+
PHP and Symfony, he will not be able to work on a query without your assistance.
7067

71-
Naturally, query code should residue in separated files and included in
72-
project with some kind of inclusion statement or service call.
68+
Naturally, query code should residue in separated files and included in project with some kind of inclusion statement or
69+
service call.
7370

7471
[Table of contents](index.md) | [Proposed solution >>](proposed-solution.md)

docs/proposed-solution.md

+44-57
Original file line numberDiff line numberDiff line change
@@ -1,73 +1,60 @@
11
# Proposed solution
22

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.
54

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`).
129

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:
1511

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).
1814
- 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.
2518

2619
## Example
2720

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:
3023

3124
![Project structure with query files](img/file_structure.jpg "Real world example of this bundle usage")
3225

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._
3528

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
4345
{
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+
);
5751
}
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+
7360
[<< Introduction](introduction.md) | [Table of contents](index.md) | [Twig support >>](twig-support.md)

0 commit comments

Comments
 (0)