7
7
What is Magic-query?
8
8
====================
9
9
10
- Magic-query is a PHP library that helps you work with complex queries that require
11
- a variable number of parameters.
10
+ Magic-query is a PHP library that helps you work with complex SQL queries.
12
11
13
- How does it work?
14
- -----------------
12
+ It comes with 2 great features:
15
13
16
- Easy! You write the query with all possible parameters.
14
+ - [ it helps you work with that require a variable number of parameters.] ( #parameters )
15
+ - [ ** MagicJoin** : it writes JOINs for you!] ( #joins )
16
+
17
+ Installation
18
+ ------------
19
+
20
+ Simply use the composer package:
21
+
22
+ ``` json
23
+ {
24
+ "require" : {
25
+ "mouf/magic-query" : " ~1.0"
26
+ },
27
+ "minimum-stability" : " dev" ,
28
+ "prefer-stable" : true
29
+ }
30
+ ```
31
+
32
+ <a name =" parameters " ></a >
33
+ Automatically discard unused parameters
34
+ ---------------------------------------
35
+
36
+ Just write the query with all possible parameters.
17
37
18
38
``` php
19
39
use Mouf\Database\MagicQuery;
@@ -34,78 +54,55 @@ $result2 = $magicQuery->build($sql, []);
34
54
// The whole WHERE condition disappeared because it is not needed anymore!
35
55
```
36
56
37
- Installation
38
- ------------
57
+ Curious to know how this work? <a class =" btn btn-primary " href =" doc/discard_unused_parameters.md " >Check out the complete guide!</a >
39
58
40
- Simply use the composer package:
59
+ <a name =" joins " ></a >
60
+ Automatically guess JOINs with MagicJoin!
61
+ -----------------------------------------
41
62
42
- ``` json
43
- {
44
- "require" : {
45
- "mouf/magic-query" : " ~1.0"
46
- },
47
- "minimum-stability" : " dev" ,
48
- "prefer-stable" : true
49
- }
50
- ```
63
+ Fed up of writing joins in SQL? Let MagicQuery do the work for you!
51
64
52
- Why should I care?
53
- ------------------
65
+ Seriously? Yes! All you have to do is:
54
66
55
- Because it is ** the most efficient way to deal with queries that can have a variable number of parameters** !
56
- Think about a typical datagrid with a bunch of filter (for instance a list of products filtered by name, company, price, ...).
57
- If you have the very common idea to generate the SQL query using no PHP library, your code will look like this:
67
+ - Pass a ** Doctrine DBAL connection** to MagicQuery's constructor. MagicQuery will analyze your schema.
68
+ - In your SQL query, replace the tables with ` magicjoin(start_table) `
58
69
59
- ###Without Magic-query
60
- <div class =" alert " ><strong >You should not do this!</strong ></div >
70
+ Let's assume your database schema is:
61
71
62
- ``` php
63
- // People usually write queries like this:
64
- $sql = "SELECT * FROM products p JOIN companies c ON p.company_id = c.id WHERE 1=1 ";
65
- // They keep testing for parameters, and concatenating strings....
66
- if (isset($params['name'])) {
67
- $sql .= "AND (p.name LIKE '".addslashes($params['name'])."%' OR p.altname LIKE '".addslashes($params['name'])."%')";
68
- }
69
- if (isset($params['company'])) {
70
- $sql .= "AND c.name LIKE '".addslashes($params['company'])."%'";
71
- }
72
- if (isset($params['country'])) {
73
- $sql .= "AND c.country LIKE '".addslashes($params['country'])."%'";
74
- }
75
- // And so on... for each parameter, we have a "if" statement
72
+ ![ Sample database schema] ( doc/images/schema1.png )
73
+
74
+ Using MagicJoin, you can write this SQL query:
75
+
76
+ ``` sql
77
+ SELECT users.* FROM MAGICJOIN(users) WHERE groups .name = ' Admins' AND country .name = ' France' ;
76
78
```
77
79
78
- Concatenating SQL queries is ** dangerous** (especially if you forget to protect parameters).
79
- You can always use parametrized SQL queries, but you will still have to concatenate the filters.
80
+ and it will automatically be transformed into this:
80
81
81
- ###With Magic-Query
82
+ ``` sql
83
+ SELECT users.* FROM users
84
+ LEFT JOIN users_groups ON users .user_id = users_groups .user_id
85
+ LEFT JOIN groups ON groups .group_id = users_groups .group_id
86
+ LEFT JOIN country ON country .country_id = users .country_id
87
+ WHERE groups .name = ' Admins' AND country .name = ' France' ;
88
+ ```
82
89
83
- ``` php
84
- // One query with all parameters
85
- $sql = "SELECT * FROM products p JOIN companies c ON p.company_id = c.id WHERE
86
- (p.name LIKE :name OR p.altname LIKE :name)
87
- AND c.name LIKE :company
88
- AND c.country LIKE :country";
90
+ And the code is so simple!
89
91
90
- $magicQuery = new MagicQuery();
91
- $sql = $magicQuery->build($sql, $params);
92
- ```
92
+ ``` php
93
+ use Mouf\Database\MagicQuery;
93
94
94
- ###Other alternatives
95
+ $sql = "SELECT users.* FROM MAGICJOIN(users) WHERE groups.name = 'Admins' AND country.name='France'";
95
96
96
- To avoid concatenating strings, frameworks and libraries have used different strategies. Using a full ORM (like
97
- Doctrine or Propel) is a good idea, but it makes writing complex queries even more complex. Other frameworks like
98
- Zend are building queries using function calls. These are valid strategies, but you are no more typing SQL queries
99
- directly, and let's face it, it is always useful to use a query directly.
97
+ // Get a MagicQuery object.
98
+ // $conn is a Doctrine DBAL connection.
99
+ $magicQuery = new MagicQuery($conn);
100
100
101
- How does it work under the hood?
102
- --------------------------------
101
+ $completeSql = $magicQuery->build($sql);
102
+ // $completeSql contains the complete SQL request, with all joins.
103
+ ```
103
104
104
- A lot happens to your SQL query. It is actually parsed (thanks to a modified
105
- version of the php-sql-parser library) and then changed into a tree.
106
- The magic happens on the tree where the node containing unused parameters
107
- are simply discarded. When it's done, the tree is changed back to SQL and
108
- "shazam!", your SQL query is purged of useless parameters!
105
+ Want to know more? <a class =" btn btn-primary " href =" doc/magic_join.md " >Check out the MagicJoin guide!</a >
109
106
110
107
Is it a MySQL only tool?
111
108
------------------------
@@ -126,9 +123,24 @@ $conn = \Doctrine\DBAL\DriverManager::getConnection($connectionParams, $config);
126
123
$magicQuery = new \Mouf\Database\MagicQuery($conn);
127
124
```
128
125
126
+ What about performances?
127
+ ------------------------
128
+
129
+ MagicQuery does a lot to your query. It will parse it, render it internally as a tree of SQL nodes, etc...
130
+ This processing is time consuming. So you should definitely consider using a cache system. MagicQuery is compatible
131
+ with Doctrine Cache. You simply have to pass a Doctrine Cache instance has the second parameter of the constructor.
132
+
133
+ ``` php
134
+ use Mouf\Database\MagicQuery;
135
+ use Doctrine\Common\Cache\ApcCache();
136
+
137
+ // $conn is a Doctrine connection
138
+ $magicQuery = new MagicQuery($conn, new ApcCache());
139
+ ```
140
+
129
141
Any problem?
130
142
------------
131
143
132
- As we said , a lot happen to your SQL query. In particular, it is parsed using a modified version
144
+ With MagicQuery , a lot happens to your SQL query. In particular, it is parsed using a modified version
133
145
of the php-sql-parser library. If you face any issues with a complex query, it is likely there is a bug
134
146
in the parser. Please open [ an issue on Github] ( https://github.com/thecodingmachine/magic-query/issues ) and we'll try to fix it.
0 commit comments