Skip to content

Commit ac2b449

Browse files
committed
Working on documentation
1 parent 4e09ccd commit ac2b449

File tree

4 files changed

+400
-0
lines changed

4 files changed

+400
-0
lines changed

docs/source/components/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,4 @@ Table of Contents
1818
:titlesonly:
1919

2020
metadata/index
21+
query/index
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
=======
2+
History
3+
=======
4+
5+
.. _runopencode/query-resources-loader-bundle: https://github.com/RunOpenCode/query-resources-loader-bundle/blob/master/docs/introduction.md
6+
.. _Twig: https://twig.symfony.com
7+
8+
To fully leverage raw SQL queries and statements in PHP projects, more then a
9+
decade ago `runopencode/query-resources-loader-bundle`_ was created. General
10+
idea was to separate PHP code from SQL code and to easily load and execute
11+
queries and statements.
12+
13+
For dynamic queries, `Twig`_ is used as a template which enables integrating
14+
business logic into a final query.
15+
16+
During years and years of improvements of the original bundle, some commonly
17+
requested features were lacking. Major rewrite occurred in version 8 where
18+
middleware arhitecture was introduced. However, bundle API was lacking and PHP
19+
improved on itself so requirement for full rewrite was more then obvious.
20+
21+
A goals of the rewrite of the original library
22+
----------------------------------------------
23+
24+
* **Removal of the vendor lock-in** by implementing framework as framework
25+
agnostic library and providing Symfony bundle separately. Since general idea
26+
of the library is valid outside of Symfony's ecosystem as well, separating
27+
library from Symfony would allow library to be used in other frameworks as
28+
well as in plain PHP projects.
29+
* **Improvement of API** by keeping public API footprint extremely small (i.e.
30+
only query/statement is required argument for executor,
31+
``$executor->query('@app/query.sql')``), while through utilization of variadic
32+
arguments every aspect of execution could be configured as needed.
33+
* **Separation of query and statement calls** as they produce different types of
34+
results.
35+
* **Support for common middlewares out-of-the-box**, such as:
36+
* **Caching** of query results with support for static and dynamic tags.
37+
* Redirecting execution to **read replica** with fallback strategy support.
38+
* **Retrying** failed queries and statements due to deadlocks.
39+
* **Type-casting** of records to targeted PHP types.
40+
* **Logging of slow queries** based on developer defined criteria on query
41+
level.
42+
* Improvement of **error handling** and exception model as well.
43+
* Providing better **developer experience** by monitoring and notifying about
44+
errors in execution logic and misconfigurations.
45+
* Decoupling configuration of executor adapter from configuration of transaction
46+
scope.
47+
48+
Bundle ``runopencode/query-resources-loader-bundle`` lacked support for
49+
profiling, which is crucial for getting insight into execution process,
50+
especially when it comes to middleware based arhitecture.
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
===============
2+
Query component
3+
===============
4+
5+
Mixing PHP and SQL code does not seams right. Object oriented approach of
6+
building queries is appropriate for simpler queries, however, when things get
7+
complicated debugging and optimization makes things hard.
8+
9+
.. _Twig: https://twig.symfony.com
10+
11+
This library enables you to execute queries from their own separate SQL files.
12+
With the help of `Twig`_ building complex query is a breeze.
13+
14+
ORM's are not silver bullet, some use cases are better handled by executing raw
15+
SQL. The very purpose of this library is to make utilisation of raw SQLs within
16+
PHP project easy and maintainable, where applicable.
17+
18+
Features
19+
--------
20+
21+
* **Store all your queries in separate** files (``*.sql``, ``*.sql.twig``,
22+
etc.), in your project directory or any other directory or directories that
23+
you want to use.
24+
* **Execute queries with one line of code** simply by invoking
25+
``$executor->query('@app/my_query.sql.twig')``.
26+
* **Full integration with Doctrine Dbal** out of the box, while other adapters
27+
may be added with ease too.
28+
* **Build complex queries using Twig** based on passed variables and parameters
29+
and control structures supported by Twig.
30+
* **Full support for transactions** and distributed transactions as well.
31+
Doctrine Dbal adapter supports specifying isolation level for individual
32+
transaction, query and statement.
33+
* **Caching** supported out of the box with possibility to tag cache items based
34+
on returned resultset.
35+
* **Use database replica** on demand, per example, for queries which generate
36+
various reports. Disable replica in development/test environment.
37+
* **Middleware driven arhitecture** allows you to extend behaviour of this
38+
library and control how your queries are processed and executed.
39+
* **Symfony ready** via dedicated bundle.
40+
41+
Table of Contents
42+
-----------------
43+
44+
.. toctree::
45+
:maxdepth: 1
46+
47+
motivation
48+
history
49+
50+
Quick example
51+
-------------
52+
53+
A simple example of using this library for executing a query is given code
54+
example below.
55+
56+
.. code-block:: php
57+
:linenos:
58+
59+
<?php
60+
61+
namespace App\User\Repository;
62+
63+
use RunOpenCode\Component\Query\Cache\CacheIdentity;
64+
use RunOpenCode\Component\Query\Contract\ExecutorInterface;
65+
use RunOpenCode\Component\Query\Doctrine\Dbal\Options;
66+
use RunOpenCode\Component\Query\Doctrine\Parameters\Named;
67+
use RunOpenCode\Component\Query\Replica\FallbackStrategy;
68+
use RunOpenCode\Component\Query\Replica\Replica;
69+
70+
final readonly class UserRepository
71+
{
72+
public function __construct(private ExecutorInterface $executor)
73+
{
74+
/* noop */
75+
}
76+
77+
public function getReport(Criteria $criteria): iterable
78+
{
79+
return $this->executor->query(
80+
'@user/list_users.sql.twig',
81+
Options::readCommitted(),
82+
new Named()
83+
->string('first_name', $criteria->firstName)
84+
->string('last_name', $criteria->lastName)
85+
->boolean('active', $criteria->active)
86+
->integer('limit', $criteria->limit)
87+
->integer('offset', $criteria->offset),
88+
CacheIdentity::static(
89+
key: $criteria->getCacheKey(),
90+
tags: $criteria->getCacheTags(),
91+
ttl: 3600,
92+
),
93+
new Replica(
94+
connection: 'reporting_database',
95+
fallback: FallbackStrategy::Primary,
96+
)
97+
);
98+
}
99+
}
100+
101+
In example above, we are executing query defined in ``@user/list_users.sql.twig``
102+
file. We are setting connection isolation level to ``READ_COMMITED`` and passing
103+
named parameters to the query.
104+
105+
We want to utilize cache for result set, therefore, we are providing cache
106+
identity to executor with cache key and cache tags built inside criteria object.
107+
Query will be executed if result set is not already in cache.
108+
109+
Instead of using primary connection, we would like to use read replica. However,
110+
if replica fails, we will fallback to primary connection and try again.
111+
112+
113+
114+
115+

0 commit comments

Comments
 (0)