├── .github
├── CONTRIBUTING.md
├── ISSUE_TEMPLATE.md
└── PULL_REQUEST_TEMPLATE.md
├── .gitignore
├── .scrutinizer.yml
├── CHANGELOG-2.0.md
├── CHANGELOG-2.1.md
├── CHANGELOG-2.2.md
├── CHANGELOG-2.3.md
├── CHANGELOG-2.4.md
├── CHANGELOG-2.5.md
├── LICENSE
├── Makefile
├── README.md
├── UPGRADE-2.1.md
├── UPGRADE-2.2.md
├── UPGRADE-2.3.md
├── UPGRADE-2.4.md
├── agile.sh
├── composer.json
├── composer.lock
├── coverage.sh
├── doc
└── additional-filters.md
├── phpunit.xml
├── runtests.sh
├── src
└── Mado
│ └── QueryBundle
│ ├── Component
│ └── Meta
│ │ ├── DataMapper.php
│ │ ├── Dijkstra.php
│ │ ├── DijkstraWalker.php
│ │ ├── Exceptions
│ │ └── UnInitializedQueryBuilderException.php
│ │ ├── GraphWalker.php
│ │ └── MapBuilder.php
│ ├── DependencyInjection
│ ├── Configuration.php
│ └── MadoQueryExtension.php
│ ├── Dictionary.php
│ ├── Exceptions
│ ├── ForbiddenContentException.php
│ ├── InvalidFiltersException.php
│ ├── MissingFieldsException.php
│ └── MissingFiltersException.php
│ ├── Interfaces
│ ├── AdditionalFilterable.php
│ └── CustomFilter.php
│ ├── MadoQueryBundle.php
│ ├── Objects
│ ├── Filter.php
│ ├── HalResponse.php
│ ├── MetaDataAdapter.php
│ └── PagerfantaBuilder.php
│ ├── Queries
│ ├── AbstractQuery.php
│ ├── AndFilter.php
│ ├── Join.php
│ ├── Objects
│ │ ├── FilterObject.php
│ │ └── Value.php
│ ├── Options
│ │ └── QueryOptionsBuilder.php
│ ├── OrFilter.php
│ ├── QueryBuilderFactory.php
│ └── QueryBuilderOptions.php
│ ├── Repositories
│ └── BaseRepository.php
│ ├── Resources
│ └── config
│ │ └── services.yml
│ └── Services
│ ├── AdditionalFilterExtractor.php
│ ├── Pager.php
│ ├── Router.php
│ └── StringParser.php
└── tests
└── Mado
└── QueryBundle
├── Component
└── Meta
│ ├── DijkstraTest.php
│ ├── DijkstraWalkerTest.php
│ └── MapBuilderTest.php
├── Objects
├── FilterTest.php
├── HalResponseTest.php
├── MetaDataAdapterTest.php
├── PagerfantaBuilderTest.php
├── QueryBuilderFactoryTest.php
├── QueryBuilderOptionsTest.php
└── ValueTest.php
├── Queries
├── Objects
│ ├── FilterObjectTest.php
│ └── QueryOptionsBuilderTest.php
└── QueryBuilderOptionsTest.php
└── Services
├── AdditionalFilterExtractorTest.php
├── PagerTest.php
├── RouterTest.php
└── StringParserTest.php
/.github/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | Contributing
2 | ============
3 |
4 | Changelog
5 | ---------
6 |
7 | * every time new feature is added, new line on CHANGELOG file must be present
8 | in the form
9 |
10 | > feature - feature description
11 |
12 | Branch names
13 | ------------
14 |
15 | The following is just a suggestion and it is not mandatory to follow as naming
16 | convention. According to what the branch represents it can start with the
17 | following prefix:
18 |
19 | - feature/
20 | - refactoring/
21 | - enhancement/
22 | - fix/
23 |
24 | Choose the right branch
25 | -----------------------
26 |
27 | Before open your pull request, you must determine on which branch you need to
28 | work.
29 |
30 | * if it contains a fix, refactoring or simply some code improvements must be
31 | opened against latest minor release branch. If latest stable version is
32 | `v2.2.3`, pull request must be opened starting from branch 2.2;
33 |
34 | * once new branch is merged to version 2.2 a new tag can should be created
35 | in this branch.
36 |
37 | * every time new version is released, that version must be merged to the
38 | upper minor branch (if exists) until master branch. This allow to keep all
39 | version fixed and also the next one;
40 |
41 | * if it contains new features must be opened against master branch;
42 |
43 |
44 | Coding Standards
45 | ----------------
46 |
47 | * every time new class or method is added, `@since` annotation should be
48 | present. Just mark the minor version. `/** @since version x.y */`;
49 |
50 | * always use `yoda` condition;
51 |
52 | * respect `PSR-2` coding standards;
53 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | | Q | A
2 | | -------------------- | -----
3 | | Bug report? | yes/no
4 | | Feature request? | yes/no
5 | | QueryBundle version | x.y
6 |
7 | ---
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | | Q | A
2 | | ------------- | ---
3 | | Branch? | master
4 | | Minor version? | (x.y)
5 | | Hotfix? | yes
6 | | Hotfix? | no
7 | | Refactoring? | yes
8 | | New feature? | yes
9 | | New feature? | no
10 | | BC breaks? | yes/no
11 | | Deprecations? | yes
12 | | Deprecations? | no
13 | | Tests pass? | yes/no
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /vendor/
2 | /html/
3 | /bin/
4 |
--------------------------------------------------------------------------------
/.scrutinizer.yml:
--------------------------------------------------------------------------------
1 | build:
2 | environment:
3 | php:
4 | version: 7.0.8
5 | tests:
6 | override:
7 | -
8 | command: 'bin/phpunit --coverage-clover=some-file'
9 | coverage:
10 | file: 'some-file'
11 | format: 'clover'
12 | filter:
13 | excluded_paths:
14 | - "tests/"
15 |
16 |
--------------------------------------------------------------------------------
/CHANGELOG-2.0.md:
--------------------------------------------------------------------------------
1 | CHANGELOG for 2.0
2 | =================
3 |
4 | This changelog references the relevant changes (bug and security fixes) done
5 | in 2.0 minor versions.
6 |
7 | - feature #55 - add missing phpunit configuration for coverage
8 | - feature #66 - add missing MIT license file
9 | - fix #50 - add pagerfanta in composer
10 | - fix #64 - add installation guidelines
11 |
--------------------------------------------------------------------------------
/CHANGELOG-2.1.md:
--------------------------------------------------------------------------------
1 | CHANGELOG for 2.1
2 | =================
3 |
4 | This changelog references the relevant changes (bug and security fixes) done
5 | in 2.1 minor versions.
6 |
7 | - feature #67 - move all github files inside `.github` folder
8 | - feature #66 - add missing licence
9 | - feature #62 - add additional filter component
10 | - feature #71 - add new `Objects\Value` component to wrap additional filter's value
11 | - fix #68 - add `GraphWalker` to create mocks for testing purpose
12 |
--------------------------------------------------------------------------------
/CHANGELOG-2.2.md:
--------------------------------------------------------------------------------
1 | CHANGELOG for 2.2
2 | =================
3 |
4 | This changelog references the relevant changes (bug and security fixes) done
5 | in 2.2 minor versions.
6 |
7 | - add new [FilterObject] component
8 | - undefined index list
9 | - anonymous method `setFilters` to more explicit `setAndFilters`
10 | - remove `Mado\QueryBundle\Queries\Objects\Operator` statement
11 | - remove variable assignment 'cause its unused
12 | - convert negative limit to PHP_INT_MAX
13 | - add [Services\FilterExtractor] extract additional filters from AdditionalFilterable
14 | - add [Objects\Filter] to read filter value
15 | - add [AdditionalFilterable] interface
16 | - add the possibility to just return the count of query results
17 |
--------------------------------------------------------------------------------
/CHANGELOG-2.3.md:
--------------------------------------------------------------------------------
1 | CHANGELOG for 2.3
2 | =================
3 |
4 | This changelog references the relevant changes (bug and security fixes) done
5 | in 2.3 minor versions.
6 |
7 | - fix - remove deprecated [Queries\Object\Operator] class
8 | - feature - [QueryBuilderFactory] add relation to query builder
9 | - feature - [BaseRepository] get route params directly from request
--------------------------------------------------------------------------------
/CHANGELOG-2.4.md:
--------------------------------------------------------------------------------
1 | CHANGELOG for 2.4
2 | =================
3 |
4 | This changelog references the relevant changes (bug and security fixes) done
5 | in 2.4 minor versions.
6 |
7 | - fix - or filter generate left join instead of inner join
8 | - feature - added operator isnull and isnotnull
9 | - fix - don't adding parameters in filter or if operator is null type
10 | - feature - added operator listcontains
11 | - feature - [BaseRepository] added find all no paginated method
12 | - feature - added possibility to have more or conditions
--------------------------------------------------------------------------------
/CHANGELOG-2.5.md:
--------------------------------------------------------------------------------
1 | CHANGELOG for 2.5
2 | =================
3 |
4 | This changelog references the relevant changes (bug and security fixes) done
5 | in 2.5 minor versions.
6 |
7 | - feature - add new component HalResponse to wrap raw json responses
8 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Studio Mado
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | .QUERYBUNDLE: runtests
2 | runtests: install
3 | php bin/phpunit -c phpunit.xml
4 |
5 | .QUERYBUNDLE: install
6 | install:
7 | composer install
8 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # QueryBundle
2 |
3 | latest stable version [](https://packagist.org/packages/studiomado/query-bundle)
4 |
5 |
6 | | 2.4 (master) | 2.3 | 2.2 |
7 | |----------------|----------|---|
8 | | [](https://scrutinizer-ci.com/g/studiomado/query-bundle/build-status/master) | [](https://scrutinizer-ci.com/g/studiomado/query-bundle/build-status/2.3) | [](https://scrutinizer-ci.com/g/studiomado/query-bundle/build-status/2.2) |
9 | | [](https://scrutinizer-ci.com/g/studiomado/query-bundle/?branch=master) | [](https://scrutinizer-ci.com/g/studiomado/query-bundle/?branch=2.3) | [](https://scrutinizer-ci.com/g/studiomado/query-bundle/?branch=2.2) |
10 | | [](https://scrutinizer-ci.com/g/studiomado/query-bundle/?branch=master) | [](https://scrutinizer-ci.com/g/studiomado/query-bundle/?branch=2.3) | [](https://scrutinizer-ci.com/g/studiomado/query-bundle/?branch=2.2) |
11 |
12 |
13 | ## Run tests
14 |
15 | - `./runtests.sh` run all unit tests
16 | - `./agile.sh` generate testdox documentation
17 | - `./coverage.sh` generate and open html coverage
18 |
19 | # Plain symfony project for query-bundle
20 |
21 | The purpose of this project is to see how studiomado/query-bundle works and can be installed in a plain symfony project.
22 |
23 | - database configuration
24 | - install query-bundle
25 | - create at least one entity
26 |
27 | # Database configuration
28 |
29 | Remember to update parameter.yml file, parameter.yml.dist and config.yml file. In config.yml file also remember that the drive MUST be changed in pdo_sqlite to enable doctrine to work with this database.
30 |
31 | This is just an example: for this example we use sqlite but in production you can use mysql or postgres or any other database supported by doctrine.
32 |
33 | prompt> ./bin/console doctrine:database:create
34 | Created database /path/to/project/var/data/data.sqlite for connection named default
35 |
36 | # Install query-bundle
37 |
38 | prompt> composer require studiomado/query-bundle
39 |
40 | # Create at least one entity
41 |
42 | Create at least one entity ...
43 |
44 | prompt> ./bin/console doctrine:generate:entity
45 |
46 | In this example I created an entity Task following command steps.
47 |
48 | created ./src/AppBundle/Entity/
49 | created ./src/AppBundle/Entity/Task.php
50 | > Generating entity class src/AppBundle/Entity/Task.php: OK!
51 | > > Generating repository class src/AppBundle/Repository/TaskRepository.php: OK!
52 |
53 | ... and update the schema ...
54 |
55 | prompt> ./bin/console doctrine:schema:update
56 | ATTENTION: This operation should not be executed in a production environment.
57 | Use the incremental update to detect changes during development and use
58 | the SQL DDL provided to manually update your database in production.
59 |
60 | The Schema-Tool would execute "1" queries to update the database.
61 | Please run the operation by passing one - or both - of the following options:
62 | doctrine:schema:update --force to execute the command
63 | doctrine:schema:update --dump-sql to dump the SQL statements to the screen
64 |
65 | The schema update works only with force option
66 |
67 | prompt> ./bin/console doctrine:schema:update --force
68 | Updating database schema...
69 | Database schema updated successfully! "1" query was executed
70 |
71 | Just take a look of the database content (that now is simply empty).
72 |
73 | prompt> ./bin/console doctrine:query:dql "select t from AppBundle:Task t"
74 |
75 | The query will return an empty array of result
76 |
77 | array (size=0)
78 | empty
79 |
80 | Just add first task ...
81 |
82 | prompt> ./bin/console doctrine:query:sql "insert into task values (null, 'complete this guide', 'todo') "
83 |
84 | and take a look of the content
85 |
86 | prompt> ./bin/console doctrine:query:dql "select t from AppBundle:Task t"
87 |
88 | array (size=1)
89 | 0 =>
90 | object(stdClass)[507]
91 | public '__CLASS__' => string 'AppBundle\Entity\Task' (length=21)
92 | public 'id' => int 1
93 | public 'description' => string 'complete this guide' (length=19)
94 | public 'status' => string 'todo' (length=4)
95 |
96 |
97 | # Complete installation
98 |
99 | First of all install vendors
100 |
101 | prompt> composer require jms/serializer-bundle
102 | prompt> composer require willdurand/hateoas-bundle
103 | prompt> composer require white-october/pagerfanta-bundle
104 | prompt> composer require friendsofsymfony/rest-bundle
105 |
106 | and then, … add vendors in your app/AppKernel
107 |
108 | new FOS\RestBundle\FOSRestBundle(),
109 | new JMS\SerializerBundle\JMSSerializerBundle(),
110 | new Bazinga\Bundle\HateoasBundle\BazingaHateoasBundle(),
111 |
112 | # Complete configuration and use the bundle
113 |
114 | Once everything is done, you can add new endpoints using the query-bundle to query the database.
115 |
116 | ```
117 | namespace AppBundle\Controller;
118 |
119 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
120 | use Symfony\Bundle\FrameworkBundle\Controller\Controller;
121 | use Symfony\Component\HttpFoundation\Request;
122 | use Symfony\Component\HttpFoundation\Response;
123 |
124 | class DefaultController extends Controller
125 | {
126 | /** @Route("/", name="homepage") */
127 | public function indexAction(
128 | Request $request,
129 | \Doctrine\ORM\EntityManager $em,
130 | \JMS\Serializer\Serializer $serializer
131 | ) {
132 | $data = $em->getRepository('AppBundle:Task')
133 | ->setRequest($request)
134 | ->findAllPaginated();
135 |
136 | $content = $serializer->serialize($data, 'json');
137 |
138 | return new Response($content, 200);
139 | }
140 | }
141 | ```
142 |
143 | # Configure your entity repository
144 |
145 | Now be sure that your repository extends the right BaseRepository.
146 |
147 | ```
148 | namespace AppBundle\Repository;
149 |
150 | class TaskRepository extends \Mado\QueryBundle\Repositories\BaseRepository
151 | {
152 | // to do …
153 | }
154 | ```
155 |
156 | ```
157 | namespace AppBundle\Entity;
158 |
159 | /** @ORM\Entity(repositoryClass="AppBundle\Repository\TaskRepository") */
160 | class Task
161 | {
162 | // to do …
163 | }
164 | ```
165 |
166 | # Customize entity serialization
167 |
168 | Now if you want to customize responses add
169 |
170 | use JMS\Serializer\Annotation as JMS;
171 |
172 | On top of your entities and complete your JMS configurations. See JMS documentation to get all the complete documentation.
173 |
174 | Here some examples:
175 |
176 | - http://127.0.0.1:8000/?filtering[status]=todo
177 | - http://127.0.0.1:8000/?filtering[status|contains]=od
178 | - http://127.0.0.1:8000/?filtering[status|endswith]=gress
179 |
180 | # Find All No Paginated
181 |
182 | Added a new method in **BaseRepository**
183 | When you need results applying filter and sort without pagination
184 | ```
185 | public function findAllNoPaginated();
186 | ```
187 | This feature was needed to create an Excel Report, injecting results into the Excel Report
188 |
189 | Example without pagination
190 | --------------------------
191 | In Controller:
192 | ```
193 | public function getTasksExcelReportAction(Request $request)
194 | {
195 | $tasks = $this->getDoctrine()
196 | ->getRepository('AppBundle:Task')
197 | ->findAllNoPaginated();
198 |
199 | $reportExcel = new TasksReport($tasks);
200 | $reportExcel->createReport();
201 |
202 | $excelContent = $reportExcel->printReport();
203 |
204 | return new Response(
205 | $excelContent,
206 | 200, [
207 | 'Content-Type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
208 | ]
209 | );
210 | }
211 | ```
212 |
213 | Example with pagination
214 | -----------------------
215 | In Controller:
216 | ```
217 | public function getTasksAction(Request $request)
218 | {
219 | return $this->getDoctrine()
220 | ->getRepository('AppBundle:Task')
221 | ->setRequest($request)
222 | ->findAllPaginated();
223 | }
224 | ```
225 |
226 | # Queries
227 |
228 | ## AND Conditions
229 |
230 | If you want to create an AND condition with this library you can create it from the client for example with a simple GET request like this:
231 |
232 | ```
233 | /api/foo?filtering[name|eq]=bar&filtering[surname|eq]=bar
234 | ```
235 |
236 | This request will produce a query like this:
237 |
238 | ```
239 | SELECT f0_.id AS id_0, f0_.name AS name_1, f0_.surname AS surname_2" .
240 | FROM foo f0_" .
241 | WHERE f0_.name = "bar" AND f0_.surname = "bar"
242 | ```
243 |
244 | ## OR Conditions
245 |
246 | If you want to create an OR condition with this library you can create it from the client for example with a simple GET request like this:
247 |
248 | ```
249 | /api/foo?filtering_or[name|eq]=bar&filtering_or[surname|eq]=bar
250 | ```
251 |
252 | This request will produce a query like this:
253 |
254 | ```
255 | SELECT f0_.id AS id_0, f0_.name AS name_1, f0_.surname AS surname_2" .
256 | FROM foo f0_" .
257 | WHERE ((f0_.name = "bar" OR f0_.surname = "bar"))
258 | ```
259 |
260 | Instead, if you want to have more OR conditions separated you can do something like this:
261 |
262 | ```
263 | /api/foo?filtering_or[name|eq|1]=bar&filtering_or[surname|eq|1]=bar&filtering_or[group|contains|2]=baz&filtering_or[role|contains|2]=baz
264 | ```
265 |
266 | This request will produce a query like this:
267 |
268 | ```
269 | SELECT f0_.id AS id_0, f0_.name AS name_1, f0_.surname AS surname_2, f0_.group AS group_3, f0_.role AS role_4" .
270 | FROM foo f0_" .
271 | WHERE (f0_.name = "bar" OR f0_.surname = "bar") AND (f0_.group LIKE "%baz%" OR f0_.role LIKE "%baz%")
272 | ```
273 |
274 | This can be done by using a counter after the operator separated by ```|```
275 |
276 | ## Search into relations
277 |
278 | If you want to search inside an entity where a condition is inside another entity you can do this:
279 |
280 | ```
281 | /api/users?filtering[_embedded.group.name|contains =bar
282 | ```
283 |
284 | This request will produce a query like this:
285 |
286 | ```
287 | SELECT u0_.id AS id_0 u0_.username AS username_1, u0_.group_id AS group_id_2 " .
288 | FROM User u0_
289 | LEFT JOIN Group g1_ ON u0_.group_id = g1_.id " .
290 | WHERE g1_.name LIKE "%bar%"
291 | ```
292 |
293 | To do this you need to add inside the user entity some Hateoas annotations like this:
294 |
295 | ```
296 | * @Hateoas\Relation(
297 | * "groups",
298 | * embedded = @Hateoas\Embedded(
299 | * "expr(object.getGroups())",
300 | * exclusion = @Hateoas\Exclusion(
301 | * excludeIf = "expr(object.getGroups().isEmpty() === true)",
302 | * groups={"groups"},
303 | * maxDepth = 1
304 | * )
305 | * ),
306 | * exclusion = @Hateoas\Exclusion(
307 | * excludeIf = "expr(object.getGroups().isEmpty() === true)",
308 | * groups={"groups"},
309 | * maxDepth = 1
310 | * )
311 | * )
312 |
313 | ```
314 |
315 | If you add Hateoas annotations correctly, you can search deeper than only "one level". Here an example:
316 |
317 | ```
318 | /api/users?filtering[_embedded.profile.location.country.name|contains]=italy
319 | ```
320 |
321 | In this example you search all users that have a profile with a country location name: Italy.
322 | Profile, location and country are entities and name is the field.
323 |
324 | You can use _embedded filter also into filtering_or conditions.
--------------------------------------------------------------------------------
/UPGRADE-2.1.md:
--------------------------------------------------------------------------------
1 | UPGRADE FROM 2.0 to 2.1
2 | =======================
3 |
4 | NestingException
5 | ----------------
6 |
7 | * Notice if some loop is nested too many times.
8 |
9 | UnespectedValueException
10 | ------------------------
11 |
12 | * Throwed whenever parent root entity of a relation not exists.
13 |
14 | UnreachablePathException
15 | ------------------------
16 |
17 | * An exception that's throwed when is not possibile to get the path.
18 |
19 | UndefinedPathException
20 | ----------------------
21 |
22 | * An exception that's throwed when entities path is requested too early.
23 |
24 | MapBuilder
25 | ----------
26 |
27 | * Build a map based on Doctrine's DataMapper.
28 |
29 | DataMapper
30 | ----------
31 |
32 | * An interface to build maps of relations of database entities.
33 |
34 | JsonPathFinder
35 | --------------
36 |
37 | * Build the path of relations between entities.
38 |
39 | ```php
40 | use Mado\QueryBundle\Meta\DataMapper;
41 |
42 | class MyCustomMapper implements DataMapper
43 | {
44 | public function getMap() : array
45 | {
46 | return [
47 | "FooBundle\\Entity\\Start" => [
48 | "relations" => [
49 | "end" => "AppBundle\\Entity\\End",
50 | "foo" => "AppBundle\\Entity\\Foo",
51 | ]
52 | ]
53 | ];
54 | }
55 | };
56 |
57 | $finder = new JsonPathFinder(new MyCustomMapper($entityManager));
58 | $finder->setQueryStartEntity("FooBundle\\Entity\\Start");
59 | $finder->getPathToEntity("AppBundle\\Entity\\End"); // _embedded.start.end
60 | ```
61 |
62 | Dijkstra
63 | --------
64 |
65 | * Navigate the graph to find the minimum spanning tree
66 |
67 | ```php
68 | $dijkstra = new Dijkstra(new MyCustomMapper($entityManager));
69 | $entities = $dijkstra->shortestPaths($from, $to)
70 | ```
71 |
72 | DijkstraWalker
73 | --------------
74 |
75 | * Use Dijkstra to find paths to use in querystring. For example to query all
76 | users with a group that is inside certain category with id 2, 3 or 5 we
77 | need this in query string.
78 |
79 | `filtering[_embedded.groups.category.id|list]=2,3,5`
80 |
81 | If we want to force this filter in queryBundle
82 |
83 | ```php
84 | $walker = new DijkstraWalker(
85 | new \Mado\QueryBundle\Component\Meta\MapBuilder($manager)
86 | new Dijkstra()
87 | );
88 |
89 | $walker->buildPathBetween(
90 | \AppBundle\Entity\Start::class,
91 | \FooBundle\Entity\End:class
92 | );
93 |
94 | $filter = $walker->getPath();
95 |
96 | $repository = $this->getDoctrine()
97 | ->getRepository('AppBundle:User')
98 | ->setRequestWithFilter($request, [
99 | $filter . '.id|list' => '2,3,5'
100 | ]);
101 | ```
102 |
103 | Objects\Value
104 | -------------
105 |
106 | * When a value is not a string, it comes from an additional filter.
107 | Additional filters should be stored as ...
108 |
109 | ```php
110 | {
111 | "filter_name": {
112 | "list" : [23, 666],
113 | "entities" : [
114 | {id:23,foo:"foo",bar:"bar"},
115 | {id:666,foo:"foo",bar:"bar"},
116 | ]
117 | },
118 | "filter_name": {
119 | "list" : [/* array of id */],
120 | "entities" : [
121 | // complete objects
122 | ]
123 | }
124 | }
125 | ```
126 |
--------------------------------------------------------------------------------
/UPGRADE-2.2.md:
--------------------------------------------------------------------------------
1 | UPGRADE FROM 2.1 to 2.2
2 | =======================
3 |
4 | ## Deprecations
5 |
6 | \Dictionary\Operators
7 | ---------------------
8 |
9 | * Marked as deprecated. It will be removed in version 2.3.
10 |
11 | \Queries\Objects\Operator
12 | -------------------------
13 |
14 | * This component is now marked as deprecated and will be removed in version
15 | 2.3.
16 |
17 | ## Enhancements
18 |
19 | \Dictionary
20 | -----------
21 |
22 | * Old Dictionary\Operators is now moved here in `Mado\QueryBundle\Dictionary`.
23 |
24 | * Add `nlist` operator. With this operator is requested a field returned
25 | must not be included in results. For example, to get every records of an
26 | entity except those whose ids are 42, 23 and 44 the query string should be:
27 |
28 | filtering[id|nlist]=42,23,44
29 |
30 | and all other ids will be returned.
31 |
32 | \Queries\Objects\FilterObject
33 | -----------------------------
34 |
35 | * This new component take te responsibility to manage a filtering option. For
36 | example, inside the `filtering[foo|bar]=42` query, FilterObject aims to
37 | manage the `foo|bar` part. It knows field name and operator name.
38 |
--------------------------------------------------------------------------------
/UPGRADE-2.3.md:
--------------------------------------------------------------------------------
1 | UPGRADE FROM 2.2 to 2.3
2 | =======================
3 |
4 | Dictionary\Operators
5 | --------------------
6 |
7 | * The `componet` was removed.
8 |
9 | Queries\QueryBuilderFactory
10 | ---------------------------
11 |
12 | * Use `setAndFilters` instead of `setFilters`
13 |
14 | * `QueryBuilderFactory::setRel()` now accept only arrays and relations are
15 | always stored as array.
16 |
17 | * Deprecate `customQueryStringValues` so is unnecessary to overwrite It inside entities
18 |
--------------------------------------------------------------------------------
/UPGRADE-2.4.md:
--------------------------------------------------------------------------------
1 | UPGRADE FROM 2.3 to 2.4
2 | =======================
3 |
4 | Repositories\BaseRepository
5 | ---------------------------
6 |
7 | * Removed `customQueryStringValues`;
8 |
--------------------------------------------------------------------------------
/agile.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | php bin/phpunit -c phpunit.xml --testdox
3 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "studiomado/query-bundle",
3 | "type": "symfony-bundle",
4 | "authors": [
5 | {
6 | "name": "Simone Gentili",
7 | "email": "sensorario@gmail.com"
8 | }
9 | ],
10 | "autoload": {
11 | "psr-4": {
12 | "": ["src", "tests"]
13 | }
14 | },
15 | "config": {
16 | "platform": {
17 | "php": "7.0.9"
18 | },
19 | "bin-dir": "bin"
20 | },
21 | "require": {
22 | "symfony/dependency-injection": ">=3.3",
23 | "symfony/config": ">=3.3",
24 | "symfony/http-kernel": ">=3.3",
25 | "pagerfanta/pagerfanta": "^1.0",
26 | "willdurand/hateoas": "2.10",
27 | "symfony/console": "~3.4.3",
28 | "symfony/debug": "~3.4.3",
29 | "symfony/event-dispatcher": "~3.4.3",
30 | "symfony/filesystem": "~3.4.3",
31 | "symfony/http-foundation": "~3.4.3"
32 | },
33 | "require-dev": {
34 | "phpunit/phpunit": "^6.3"
35 | },
36 | "extra": {
37 | "branch-alias": {
38 | "dev-master": "2.5-dev"
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/coverage.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | php bin/phpunit -c phpunit.xml --coverage-html=html && open html/index.html
3 |
--------------------------------------------------------------------------------
/doc/additional-filters.md:
--------------------------------------------------------------------------------
1 | # Additional Filters
2 |
3 | Aims to limit information in response, based on predefined rules. Those rule
4 | must be stored inside your application's user.
5 |
6 | ## User
7 |
8 | User must respect `\Mado\QueryBundle\Interfaces\AdditionalFilterable` interface
9 | and implement methods `getAdditionalFilters()`.
10 |
11 | ## Custom Filter
12 |
13 | To work with additional filters, is necessary a custom filter. This should
14 | respect the interface `Mado\QueryBundle\Interfaces\CustomFilter`.
15 |
16 | ### Example
17 |
18 | You can create your custom filter using this syntax.
19 |
20 | ```php
21 | \Bundle\To\EntityClass::class,
29 | ];
30 |
31 | public function __construct(
32 | EntityManagerInterface $manager,
33 | GraphWalker $dijkstraWalker,
34 | RequestStack $requestStack,
35 | LoggerInterface $logger
36 | ) {
37 | $this->manager = $manager;
38 | $this->dijkstraWalker = $dijkstraWalker;
39 | $this->requestStack = $requestStack;
40 | $this->logger = $logger;
41 | }
42 |
43 | public function setUser(AdditionalFilterable $user)
44 | {
45 | $this->additionalFilters = AdditionalFilterExtractor::fromUser($user);
46 | return $this;
47 | }
48 |
49 | public function allItemsTo(string $entity)
50 | {
51 | $this->entity = $entity;
52 | $filters = [];
53 | $translations = [
54 | 'filter_name' => [
55 | 'from' => '_embedded.shops.id',
56 | 'to' => 'id',
57 | ],
58 | ];
59 | foreach ($translations as $filterName => $filterTranslation) {
60 | if ($this->additionalFilters->getFilters($filterName) != '') {
61 | $path = $this->getPathTo($filterName);
62 | $genericAdditionalFilter = Filter::box([
63 | 'ids' => $this->additionalFilters->getFilters($filterName),
64 | 'path' => $path,
65 | ]);
66 | $filterKey = $genericAdditionalFilter->getFieldAndOperator();
67 | if ([] != $filterTranslation) {
68 | if ($filterKey == $filterTranslation['from'] . '|' . $genericAdditionalFilter->getOperator()) {
69 | $filterKey = $filterTranslation['to'] . '|' . $genericAdditionalFilter->getOperator();
70 | $genericAdditionalFilter = $genericAdditionalFilter->withFullPath($filterKey);
71 | }
72 | }
73 | $filtering = $this->requestStack->getCurrentRequest()->query->get('filtering', []);
74 | $haveCheckedAdditionalFilters = false;
75 | $field = $genericAdditionalFilter->getField();
76 | foreach( $filtering as $filterKey => $value) {
77 | $genericQueryStringFilter = Filter::fromQueryStringFilter([
78 | $filterKey => $value
79 | ]);
80 | if ($genericAdditionalFilter->getField() == $genericQueryStringFilter->getField()) {
81 | if (
82 | $genericAdditionalFilter->getOperator() == 'list'
83 | && $genericAdditionalFilter->getOperator() == $genericQueryStringFilter->getOperator()
84 | ) {
85 | $haveCheckedAdditionalFilters = true;
86 | $additionalFiltersIds = explode(',', $genericAdditionalFilter->getIds());
87 | $querystringIds = explode(',', $genericQueryStringFilter->getIds());
88 | $intersection = array_intersect($querystringIds, $additionalFiltersIds);
89 | $ids = join(',', $intersection);
90 | if ($intersection == []) {
91 | throw new ForbiddenContentException(
92 | 'Oops! Forbidden requested id ' . $value
93 | . ' is not available. Available are '
94 | . $genericAdditionalFilter->getIds()
95 | );
96 | }
97 | $filters[$genericAdditionalFilter->getFieldAndOperator()] = $ids;
98 | }
99 | }
100 | }
101 | if (!$haveCheckedAdditionalFilters) {
102 | $ids = $genericAdditionalFilter->getIds();
103 | $filters[$genericAdditionalFilter->getFieldAndOperator()] = $ids;
104 | }
105 | }
106 | }
107 |
108 | return $filters;
109 | }
110 |
111 | public function getPathTo(string $filter)
112 | {
113 | $this->dijkstraWalker->buildPathBetween(
114 | $this->entity,
115 | self::getEntityFromFilter($filter)
116 | );
117 | return $this->dijkstraWalker->getPath();
118 | }
119 |
120 | public static function getEntityFromFilter(string $filterName)
121 | {
122 | return self::$filterMap[$filterName];
123 | }
124 |
125 | public function setEntity(string $entity)
126 | {
127 | $this->entity = $entity;
128 | return $this;
129 | }
130 | }
131 | ```
132 |
--------------------------------------------------------------------------------
/phpunit.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 | src
8 | tests
9 |
10 |
11 |
12 |
13 | src/Mado/QueryBundle/Component
14 | src/Mado/QueryBundle/Dictionary
15 | src/Mado/QueryBundle/Queries
16 | src/Mado/QueryBundle/Objects
17 | src/Mado/QueryBundle/Repositories
18 | src/Mado/QueryBundle/Resources
19 | src/Mado/QueryBundle/Services
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/runtests.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | composer install
3 | php bin/phpunit -c phpunit.xml
4 |
--------------------------------------------------------------------------------
/src/Mado/QueryBundle/Component/Meta/DataMapper.php:
--------------------------------------------------------------------------------
1 | $metaData) {
21 | foreach ($metaData['relations'] as $itemKey => $itemValue) {
22 | $this->map[$nodeName][$itemValue] = 1;
23 | }
24 | }
25 | }
26 |
27 | private function processQueue(array $excluded)
28 | {
29 | $this->ensureMapIsDefined();
30 |
31 | $node = array_search(min($this->visited), $this->visited);
32 |
33 | if (!empty($this->map[$node]) && !in_array($node, $excluded)) {
34 | foreach ($this->map[$node] as $neighbor => $cost) {
35 | if (isset($this->distance[$neighbor])) {
36 | if ($this->distance[$node] + $cost < $this->distance[$neighbor]) {
37 | $this->distance[$neighbor] = $this->distance[$node] + $cost;
38 | $this->prev[$neighbor] = [$node];
39 | $this->visited[$neighbor] = $this->distance[$neighbor];
40 | } elseif ($this->distance[$node] + $cost === $this->distance[$neighbor]) {
41 | $this->prev[$neighbor][] = $node;
42 | $this->visited[$neighbor] = $this->distance[$neighbor];
43 | }
44 | }
45 | }
46 | }
47 |
48 | unset($this->visited[$node]);
49 | }
50 |
51 | private function extractPaths($target)
52 | {
53 | $paths = [[$target]];
54 | while (current($paths) !== false) {
55 | $key = key($paths);
56 | $path = current($paths);
57 | next($paths);
58 | if (!empty($this->prev[$path[0]])) {
59 | foreach ($this->prev[$path[0]] as $prev) {
60 | $copy = $path;
61 | array_unshift($copy, $prev);
62 | $paths[] = $copy;
63 | }
64 | unset($paths[$key]);
65 | }
66 | }
67 | return array_values($paths);
68 | }
69 |
70 | public function shortestPaths($source, $target, array $excluded = array())
71 | {
72 | $this->ensureMapIsDefined();
73 |
74 | $this->distance = array_fill_keys(array_keys($this->map), INF);
75 | $this->distance[$source] = 0;
76 | $this->prev = array_fill_keys(array_keys($this->map), []);
77 | $this->visited = [$source => 0];
78 |
79 | while (!empty($this->visited)) {
80 | $this->processQueue($excluded);
81 | }
82 |
83 | if ($source === $target) {
84 | return [[$source]];
85 | }
86 |
87 | if (empty($this->prev[$target])) {
88 | return [];
89 | }
90 |
91 | return $this->extractPaths($target);
92 | }
93 |
94 | public function ensureMapIsDefined()
95 | {
96 | if (!$this->map) {
97 | throw new \RuntimeException(
98 | 'Oops! Map is not defined'
99 | );
100 | }
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/src/Mado/QueryBundle/Component/Meta/DijkstraWalker.php:
--------------------------------------------------------------------------------
1 | builder = $builder;
24 | $this->dijkstra = $dijkstra;
25 |
26 | $this->init();
27 | }
28 |
29 | public function buildPathBetween($start, $end) : bool
30 | {
31 | $this->builder->rebuildRelationMap();
32 |
33 | $shortestPath = $this->dijkstra->shortestPaths($start, $end);
34 | $prevRelations = $this->map[$start]['relations'];
35 |
36 | $this->path = '_embedded';
37 |
38 | foreach ($shortestPath[0] as $meta) {
39 | if ($relationName = array_search($meta, $prevRelations)) {
40 | $this->path .= '.' . $relationName;
41 | }
42 |
43 | $prevRelations = $this->map[$meta]['relations'];
44 | }
45 |
46 | return true;
47 | }
48 |
49 | public function getPath() : string
50 | {
51 | if (!$this->path) {
52 | throw new \RuntimeException(
53 | 'Oops! path was never builded.'
54 | );
55 | }
56 |
57 | return $this->path;
58 | }
59 |
60 | public function init()
61 | {
62 | $this->dijkstra->setMap(
63 | $this->map = $this->builder->getMap()
64 | );
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/Mado/QueryBundle/Component/Meta/Exceptions/UnInitializedQueryBuilderException.php:
--------------------------------------------------------------------------------
1 | manager = $manager;
20 | }
21 |
22 | public function setMap(array $map) : bool
23 | {
24 | $this->map = $map;
25 |
26 | return true;
27 | }
28 |
29 | public function getMap() : array
30 | {
31 | if ($this->map == []) {
32 | $this->rebuildRelationMap();
33 | }
34 |
35 | return $this->map;
36 | }
37 |
38 | public function forceCache(array $map)
39 | {
40 | $this->map = $map;
41 | }
42 |
43 | /** @codeCoverageIgnore */
44 | public static function relations(ClassMetadata $classMetadata)
45 | {
46 | $encoded = json_encode($classMetadata);
47 | $decoded = json_decode($encoded, true);
48 | $relations = $decoded['associationMappings'];
49 |
50 | $relMap = [];
51 |
52 | foreach ($relations as $name => $meta) {
53 | $relMap[$name] = $meta['targetEntity'];
54 | }
55 |
56 | return $relMap;
57 | }
58 |
59 | public function rebuildRelationMap() : bool
60 | {
61 | $allMetadata = $this->manager
62 | ->getMetadataFactory()
63 | ->getAllMetadata();
64 |
65 | foreach ($allMetadata as $singleEntityMetadata) {
66 | // @codeCoverageIgnoreStart
67 | $this->map[$singleEntityMetadata->getName()]['relations'] = self::relations($singleEntityMetadata);
68 | // @codeCoverageIgnoreEnd
69 | }
70 |
71 | return true;
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/src/Mado/QueryBundle/DependencyInjection/Configuration.php:
--------------------------------------------------------------------------------
1 | root('mado_query');
22 |
23 | // Here you should define the parameters that are allowed to
24 | // configure your bundle. See the documentation linked above for
25 | // more information on that topic.
26 |
27 | return $treeBuilder;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/Mado/QueryBundle/DependencyInjection/MadoQueryExtension.php:
--------------------------------------------------------------------------------
1 | processConfiguration($configuration, $configs);
16 |
17 | $loader = new Loader\YamlFileLoader(
18 | $container,
19 | new FileLocator(__DIR__ . '/../Resources/config')
20 | );
21 |
22 | $loader->load('services.yml');
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/Mado/QueryBundle/Dictionary.php:
--------------------------------------------------------------------------------
1 | [
28 | self::FIELD_LIST,
29 | self::FIELD_NOT_IN_LIST,
30 | self::FIELD_EQUALITY,
31 | self::NUMBER_EQUAL,
32 | self::NUMBER_NOT_EQUAL,
33 | self::NUMBER_GREATER,
34 | self::NUMBER_GREATER_EQUAL,
35 | self::NUMBER_LITTLE,
36 | self::NUMBER_LITTLE_EQUAL,
37 | self::STRING_STARTS_WITH,
38 | self::STRING_CONTAINS,
39 | self::STRING_NOT_CONTAINS,
40 | self::STRING_ENDS_WITH,
41 | 'isnull',
42 | 'isnotnull',
43 | 'listcontains',
44 | ],
45 |
46 | 'fields' => [
47 | self::FIELD_LIST,
48 | self::FIELD_NOT_IN_LIST,
49 | self::FIELD_EQUALITY,
50 | ],
51 |
52 | 'integer' => [
53 | self::NUMBER_EQUAL,
54 | self::NUMBER_NOT_EQUAL,
55 | self::NUMBER_GREATER,
56 | self::NUMBER_GREATER_EQUAL,
57 | self::NUMBER_LITTLE,
58 | self::NUMBER_LITTLE_EQUAL,
59 | ],
60 |
61 | 'string' => [
62 | self::STRING_STARTS_WITH,
63 | self::STRING_CONTAINS,
64 | self::STRING_NOT_CONTAINS,
65 | self::STRING_ENDS_WITH,
66 | ],
67 |
68 | ];
69 |
70 | private static $operatorMap = [
71 |
72 | self::NUMBER_EQUAL => [ 'meta' => ' =' ],
73 | self::NUMBER_NOT_EQUAL => [ 'meta' => '!=' ],
74 | self::NUMBER_GREATER => [ 'meta' => '>' ],
75 | self::NUMBER_GREATER_EQUAL => [ 'meta' => '>=' ],
76 | self::NUMBER_LITTLE => [ 'meta' => '<' ],
77 | self::NUMBER_LITTLE_EQUAL => [ 'meta' => '<=' ],
78 |
79 | self::STRING_STARTS_WITH => [ 'meta' => 'LIKE', 'substitution_pattern' => '{string}%' ],
80 | self::STRING_CONTAINS => [ 'meta' => 'LIKE', 'substitution_pattern' => '%{string}%' ],
81 | self::STRING_NOT_CONTAINS => [ 'meta' => 'NOT LIKE', 'substitution_pattern' => '%{string}%' ],
82 | self::STRING_ENDS_WITH => [ 'meta' => 'LIKE', 'substitution_pattern' => '%{string}' ],
83 |
84 | self::FIELD_LIST => [ 'meta' => 'IN', 'substitution_pattern' => '({string})' ],
85 | self::FIELD_NOT_IN_LIST => [ 'meta' => 'NOT IN', 'substitution_pattern' => '({string})' ],
86 | self::FIELD_EQUALITY => [ 'meta' => '=' ],
87 |
88 | 'isnull' => [
89 | 'meta' => 'IS NULL',
90 | ],
91 |
92 | 'isnotnull' => [
93 | 'meta' => 'IS NOT NULL',
94 | ],
95 |
96 | 'listcontains' => [
97 | 'meta' => 'LIKE',
98 | 'substitution_pattern' => '({string})',
99 | ],
100 |
101 | ];
102 |
103 | public static function getOperators()
104 | {
105 | return self::$operatorMap;
106 | }
107 |
108 | public static function getPublicOperators()
109 | {
110 | return self::$doctrineTypeToOperatorsMap;
111 | }
112 |
113 | public static function getOperatorsFromDoctrineType(string $type)
114 | {
115 | try {
116 | self::ensureTypeIsDefined($type);
117 | return self::$doctrineTypeToOperatorsMap[$type];
118 | } catch (\Exception $e) {
119 | return self::$doctrineTypeToOperatorsMap['default'];
120 | }
121 | }
122 |
123 | public static function ensureTypeIsDefined($type)
124 | {
125 | if (!isset(self::$doctrineTypeToOperatorsMap[$type])) {
126 | throw new \RuntimeException(
127 | 'Oops! Type "'.$type.'" is not yet defined.'
128 | );
129 | }
130 | }
131 | }
132 |
133 |
--------------------------------------------------------------------------------
/src/Mado/QueryBundle/Exceptions/ForbiddenContentException.php:
--------------------------------------------------------------------------------
1 | self::buildRawFilter($path, $operator),
25 | 'ids' => $ids,
26 | 'operator' => $operator,
27 | 'path' => $path,
28 | ]);
29 | }
30 |
31 | private static function buildRawFilter($path, $operator)
32 | {
33 | return $path . '.id|' . $operator;
34 | }
35 |
36 | private function __construct(array $params)
37 | {
38 | $this->rawFilter = $params['raw_filter'];
39 | $this->ids = $params['ids'];
40 | $this->operator = $params['operator'];
41 | $this->path = $params['path'];
42 | }
43 |
44 | public function getFieldAndOperator()
45 | {
46 | return $this->rawFilter;
47 | }
48 |
49 | public function getIds()
50 | {
51 | return $this->ids;
52 | }
53 |
54 | public function getOperator()
55 | {
56 | return $this->operator;
57 | }
58 |
59 | public function getPath()
60 | {
61 | return $this->path;
62 | }
63 |
64 | public function withPath($path)
65 | {
66 | $rawFilter = self::buildRawFilter($path, $this->operator);
67 |
68 | if ($path == '') {
69 | $rawFilter = str_replace('.', '', $rawFilter);
70 | }
71 |
72 | return new self([
73 | 'raw_filter' => $rawFilter,
74 | 'ids' => $this->ids,
75 | 'operator' => $this->operator,
76 | 'path' => $path,
77 | ]);
78 | }
79 |
80 | public function withFullPath($path)
81 | {
82 | $explodedPath = explode('|', $path);
83 |
84 | $path = $explodedPath[0];
85 | $operator = $explodedPath[1];
86 |
87 | return new self([
88 | 'raw_filter' => join('|', $explodedPath),
89 | 'ids' => $this->ids,
90 | 'operator' => $operator,
91 | 'path' => $path,
92 | ]);
93 | }
94 |
95 | public function getField()
96 | {
97 | $explodedPath = explode('|', $this->getFieldAndOperator());
98 |
99 | return $explodedPath[0];
100 | }
101 |
102 | public static function fromQueryStringFilter(array $params)
103 | {
104 | return new self([
105 | 'raw_filter' => key($params),
106 | 'ids' => current($params),
107 | 'operator' => explode('|', key($params))[1],
108 | 'path' => null,
109 | ]);
110 | }
111 |
112 | public function getValue()
113 | {
114 | return $this->ids;
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/src/Mado/QueryBundle/Objects/HalResponse.php:
--------------------------------------------------------------------------------
1 | json = $json;
12 | }
13 |
14 | public static function fromJson(string $json)
15 | {
16 | return self::fromArray(json_decode($json, true));
17 | }
18 |
19 | public static function fromArray(array $json)
20 | {
21 | return new self($json);
22 | }
23 |
24 | public function total()
25 | {
26 | return $this->json['total'];
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/Mado/QueryBundle/Objects/MetaDataAdapter.php:
--------------------------------------------------------------------------------
1 | metadata = $metadata;
14 | }
15 |
16 | public function setEntityName($entityName)
17 | {
18 | $this->entityName = $entityName;
19 | }
20 |
21 | public function getFields()
22 | {
23 | return array_keys($this->metadata->fieldMappings);
24 | }
25 |
26 | public function getEntityAlias()
27 | {
28 | $entityName = explode('\\', strtolower($this->entityName));
29 |
30 | $entityName = $entityName[count($entityName) - 1][0];
31 |
32 | return $entityName[0];
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/Mado/QueryBundle/Objects/PagerfantaBuilder.php:
--------------------------------------------------------------------------------
1 | pagerfantaFactory = $pagerfantaFactory;
18 | $this->ormAdapter = $ormAdapter;
19 | }
20 |
21 | public function create($limit, $page) :Pagerfanta
22 | {
23 | $pager = new Pagerfanta($this->ormAdapter);
24 | $pager->setNormalizeOutOfRangePages(true);
25 | $pager->setMaxPerPage($limit);
26 | $pager->setCurrentPage($page);
27 |
28 | return $pager;
29 | }
30 |
31 | public function createRepresentation($route, $limit, $page)
32 | {
33 | $pager = $this->create(
34 | $limit,
35 | $page
36 | );
37 |
38 | return $this->pagerfantaFactory->createRepresentation($pager, $route);
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/Mado/QueryBundle/Queries/AbstractQuery.php:
--------------------------------------------------------------------------------
1 | manager = $manager;
27 | $this->parser = new StringParser();
28 | }
29 |
30 | public function createSelectAndGroupBy($entityName, $alias, $groupByField)
31 | {
32 | $select = $alias . '.' . $groupByField . ', count(' . $alias . '.id) as num';
33 | $groupBy = $alias . '.' . $groupByField . '';
34 |
35 | $this->entityName = $entityName;
36 | $this->entityAlias = $alias;
37 |
38 | $this->qBuilder = $this->manager->createQueryBuilder()
39 | ->select($select)
40 | ->groupBy($groupBy);
41 |
42 | $this->joinFactory = new Join($this->getEntityName(), $this->entityAlias, $this->manager);
43 | }
44 |
45 | public function createQueryBuilder($entityName, $alias)
46 | {
47 | $this->entityName = $entityName;
48 | $this->entityAlias = $alias;
49 |
50 | $this->qBuilder = $this->manager->createQueryBuilder()
51 | ->select($alias)
52 | ->from($this->entityName, $alias);
53 |
54 | $this->joinFactory = new Join($this->getEntityName(), $this->entityAlias, $this->manager);
55 | }
56 |
57 | public function getEntityName()
58 | {
59 | return $this->entityName;
60 | }
61 |
62 | public function loadMetadataAndOptions(
63 | MetaDataAdapter $metadata,
64 | QueryBuilderOptions $options
65 | ) {
66 | $this->setFields($metadata->getFields());
67 |
68 | $this->setAndFilters($options->getAndFilters());
69 | $this->setOrFilters($options->getOrFilters());
70 | $this->setSorting($options->getSorting());
71 | $this->setRel([$options->getRel()]);
72 | $this->setPrinting($options->getPrinting());
73 | $this->setSelect($options->getSelect());
74 | }
75 |
76 | abstract public function setFields(array $fields = []);
77 | abstract public function setAndFilters(array $andFilters = []);
78 | abstract public function setOrFilters(array $orFilters = []);
79 | abstract public function setSorting(array $sorting = []);
80 | abstract public function setRel(array $rel);
81 | abstract public function setPrinting($printing);
82 | abstract public function setSelect($select);
83 | }
84 |
--------------------------------------------------------------------------------
/src/Mado/QueryBundle/Queries/AndFilter.php:
--------------------------------------------------------------------------------
1 | entityAlias = $entityAlias;
26 | $this->fields = $fields;
27 | $this->join = $join;
28 |
29 | $this->conditions = [];
30 | $this->parameters = [];
31 | $this->parser = new StringParser();
32 | }
33 |
34 | public function createFilter(array $andFilters)
35 | {
36 | foreach ($andFilters as $filter => $value) {
37 | $this->applyFilter(
38 | Objects\FilterObject::fromRawFilter($filter),
39 | $value,
40 | Objects\Value::fromFilter($value)
41 | );
42 | }
43 | }
44 |
45 | private function applyFilter(
46 | Objects\FilterObject $filterObject,
47 | $value,
48 | Objects\Value $filterValue
49 | ) {
50 | $whereCondition = $this->entityAlias . '.' . $filterObject->getFieldName() . ' '
51 | . $filterObject->getOperatorMeta();
52 |
53 | if (in_array($filterObject->getFieldName(), $this->fields)) {
54 | $salt = '_' . random_int(111, 999);
55 |
56 | if ($filterObject->isListContainsType()) {
57 | $fieldName = $this->entityAlias . '.' . $filterObject->getFieldName();
58 | $whereCondition = $this->createWhereConditionForListContains($value, $fieldName, $filterObject->getFieldName(), $salt);
59 | } elseif ($filterObject->isListType()) {
60 | $whereCondition .= ' (:field_' . $filterObject->getFieldName() . $salt . ')';
61 | } elseif ($filterObject->isFieldEqualityType()) {
62 | $whereCondition .= ' ' . $this->entityAlias . '.' . $value;
63 | } elseif ($filterObject->isNullType()) {
64 | $whereCondition .= ' ';
65 | } else {
66 | $whereCondition .= ' :field_' . $filterObject->getFieldName() . $salt;
67 | }
68 |
69 | $this->conditions[] = $whereCondition;
70 |
71 | if ($filterObject->haveOperatorSubstitutionPattern()) {
72 | if ($filterObject->isListContainsType()) {
73 | $value = $this->encapsulateValueForLike($value);
74 | } elseif ($filterObject->isListType()) {
75 | $value = explode(',', $value);
76 | } else {
77 | $value = str_replace(
78 | '{string}',
79 | $value,
80 | $filterObject->getOperatorsSubstitutionPattern()
81 | );
82 | }
83 | }
84 |
85 | if (!$filterObject->isNullType()) {
86 | if ($filterObject->isListContainsType()) {
87 | $this->addMultipleParameters($value, $filterObject->getFieldName(), $salt);
88 | } else {
89 | $param = [];
90 | $param['field'] = 'field_' . $filterObject->getFieldName() . $salt;
91 | $param['value'] = $value;
92 | $this->parameters[] = $param;
93 | }
94 | }
95 | } else {
96 | if (strpos($filterObject->getFieldName(), 'Embedded.') === false) {
97 | $whereCondition .= ' ' . $this->entityAlias . '.' . $value;
98 | $this->conditions[] = $whereCondition;
99 | }
100 | }
101 |
102 | // controllo se il filtro si riferisce ad una relazione dell'entità quindi devo fare dei join
103 | // esempio per users: filtering[_embedded.groups.name|eq]=admin
104 | if (strstr($filterObject->getRawFilter(), '_embedded.')) {
105 | $this->join->join($filterObject->getRawFilter());
106 | $this->relationEntityAlias = $this->join->getRelationEntityAlias();
107 |
108 | $embeddedFields = explode('.', $filterObject->getFieldName());
109 | $embeddedFieldName = $this->parser->camelize($embeddedFields[count($embeddedFields) - 1]);
110 |
111 | $salt = '_' . random_int(111, 999);
112 |
113 | $whereCondition = $this->relationEntityAlias . '.' . $embeddedFieldName . ' '
114 | . $filterObject->getOperatorMeta();
115 |
116 | if ($filterObject->isListContainsType()) {
117 | $fieldName = $this->relationEntityAlias . '.' . $embeddedFieldName;
118 | $whereCondition = $this->createWhereConditionForListContains($value, $fieldName, $embeddedFieldName, $salt);
119 | } elseif ($filterObject->isListType()) {
120 | $whereCondition .= ' (:field_' . $embeddedFieldName . $salt . ')';
121 | } elseif ($filterObject->isNullType()) {
122 | $whereCondition .= ' ';
123 | } else {
124 | $whereCondition .= ' :field_' . $embeddedFieldName . $salt;
125 | }
126 |
127 | $this->conditions[] = $whereCondition;
128 | if ($filterObject->haveOperatorSubstitutionPattern()) {
129 | if ($filterObject->isListContainsType()) {
130 | $value = $this->encapsulateValueForLike($value);
131 | } elseif ($filterObject->isListType()) {
132 | $value = explode(',', $filterValue->getFilter());
133 | } else {
134 | $value = str_replace(
135 | '{string}',
136 | $value,
137 | $filterObject->getOperatorsSubstitutionPattern()
138 | );
139 | }
140 | }
141 |
142 | if (!$filterObject->isNullType()) {
143 | if ($filterObject->isListContainsType()) {
144 | $this->addMultipleParameters($value, $embeddedFieldName, $salt);
145 | } else {
146 | $param = [];
147 | $param['field'] = 'field_' . $embeddedFieldName . $salt;
148 | $param['value'] = $value;
149 | $this->parameters[] = $param;
150 | }
151 | }
152 | }
153 | }
154 |
155 | private function addMultipleParameters($value, $fieldName, $salt)
156 | {
157 | foreach ($value as $key => $val) {
158 | $param = [];
159 | $param['field'] = 'field_' . $fieldName . $salt . $key;
160 | $param['value'] = $val;
161 | $this->parameters[] = $param;
162 | }
163 | }
164 |
165 | private function createWhereConditionForListContains($value, $fieldName, $fieldNameWithoutAlias, $salt) :string
166 | {
167 | $whereCondition = '';
168 | $values = explode(',', $value);
169 | foreach ($values as $key => $val) {
170 | if ($whereCondition == '') {
171 | $whereCondition = ' (';
172 | } else {
173 | $whereCondition .= ' OR ';
174 | }
175 |
176 | $whereCondition .= $fieldName .
177 | ' LIKE :field_' . str_replace('.', '_', $fieldNameWithoutAlias) . $salt . $key;
178 | }
179 |
180 | $whereCondition .= ')';
181 |
182 | return $whereCondition;
183 | }
184 |
185 | private function encapsulateValueForLike(string $value) : array
186 | {
187 | $values = explode(',', $value);
188 | foreach ($values as $key => $val) {
189 | $values[$key] = '%' . $val . '%';
190 | }
191 |
192 | return $values;
193 | }
194 |
195 | public function getConditions() :array
196 | {
197 | return $this->conditions;
198 | }
199 |
200 | public function getParameters() :array
201 | {
202 | return $this->parameters;
203 | }
204 |
205 | public function getInnerJoin() :array
206 | {
207 | return $this->join->getInnerJoin();
208 | }
209 | }
--------------------------------------------------------------------------------
/src/Mado/QueryBundle/Queries/Join.php:
--------------------------------------------------------------------------------
1 | parser = new StringParser();
33 | $this->entityName = $entityName;
34 | $this->entityAlias = $entityAlias;
35 | $this->manager = $manager;
36 | $this->innerJoin = [];
37 | $this->leftJoin = [];
38 | }
39 |
40 | /**
41 | * @param String $relation Nome della relazione semplice (groups.name) o con embedded (_embedded.groups.name)
42 | * @return $this
43 | */
44 | public function join(String $relation, $logicOperator = self::AND_OPERATOR_LOGIC)
45 | {
46 | $relation = explode('|', $relation)[0];
47 | $relations = [$relation];
48 |
49 | if (strstr($relation, '_embedded.')) {
50 | $embeddedFields = explode('.', $relation);
51 | $this->parser->camelize($embeddedFields[1]);
52 |
53 | // elimino l'ultimo elemento che dovrebbe essere il nome del campo
54 | unset($embeddedFields[count($embeddedFields) - 1]);
55 |
56 | // elimino il primo elemento _embedded
57 | unset($embeddedFields[0]);
58 |
59 | $relations = $embeddedFields;
60 | }
61 |
62 | $entityName = $this->entityName;
63 | $entityAlias = $this->entityAlias;
64 |
65 | foreach ($relations as $relation) {
66 | $relation = $this->parser->camelize($relation);
67 | $relationEntityAlias = 'table_' . $relation;
68 |
69 | $metadata = $this->manager->getClassMetadata($entityName);
70 |
71 | if ($metadata->hasAssociation($relation)) {
72 | $association = $metadata->getAssociationMapping($relation);
73 |
74 | $fieldName = $this->parser->camelize($association['fieldName']);
75 |
76 | if ($this->noExistsJoin($relationEntityAlias, $relation)) {
77 | if ($logicOperator === self::AND_OPERATOR_LOGIC) {
78 | $param = [];
79 | $param['field'] = $entityAlias . "." . $fieldName;
80 | $param['relation'] = $relationEntityAlias;
81 | $this->innerJoin[] = $param;
82 | } elseif ($logicOperator === self::OR_OPERATOR_LOGIC) {
83 | $param = [];
84 | $param['field'] = $entityAlias . "." . $fieldName;
85 | $param['relation'] = $relationEntityAlias;
86 | $this->leftJoin[] = $param;
87 | } else {
88 | throw new \Exception('Missing Logic operator');
89 | }
90 |
91 | $this->storeJoin($relationEntityAlias, $relation);
92 | }
93 |
94 | $entityName = $association['targetEntity'];
95 | $entityAlias = $relationEntityAlias;
96 | }
97 |
98 | $this->setRelationEntityAlias($relationEntityAlias);
99 | }
100 |
101 | return $this;
102 | }
103 |
104 | private function storeJoin($prevEntityAlias, $currentEntityAlias)
105 | {
106 | $needle = $prevEntityAlias . '_' . $currentEntityAlias;
107 | $this->joins[$needle] = $needle;
108 | }
109 |
110 | private function noExistsJoin($prevEntityAlias, $currentEntityAlias)
111 | {
112 | if (null === $this->joins) {
113 | $this->joins = [];
114 | }
115 |
116 | $needle = $prevEntityAlias . '_' . $currentEntityAlias;
117 |
118 | return !in_array($needle, $this->joins);
119 | }
120 |
121 | public function getInnerJoin() :array
122 | {
123 | return $this->innerJoin;
124 | }
125 |
126 | public function getLeftJoin() :array
127 | {
128 | return $this->leftJoin;
129 | }
130 |
131 | private function setRelationEntityAlias(string $relationEntityAlias)
132 | {
133 | $this->relationEntityAlias = $relationEntityAlias;
134 | }
135 |
136 | public function getRelationEntityAlias()
137 | {
138 | return $this->relationEntityAlias;
139 | }
140 | }
141 |
--------------------------------------------------------------------------------
/src/Mado/QueryBundle/Queries/Objects/FilterObject.php:
--------------------------------------------------------------------------------
1 | setRawFilter($rawFilter);
28 |
29 | $explodedRawFilter = explode('|', $rawFilter);
30 | if (!isset($explodedRawFilter[self::OPERATOR])) {
31 | $explodedRawFilter[self::OPERATOR] = Dictionary::DEFAULT_OPERATOR;
32 | }
33 |
34 | $fieldName = $explodedRawFilter[self::FIELD];
35 | $parser = new StringParser();
36 | $this->fieldName = $parser->camelize($fieldName);
37 |
38 | $this->operatorName = $explodedRawFilter[self::OPERATOR];
39 |
40 | $position = 0;
41 | if (isset($explodedRawFilter[self::POSITION])) {
42 | $position = $explodedRawFilter[self::POSITION];
43 | }
44 |
45 | $this->position = $position;
46 | }
47 |
48 | public static function fromRawFilter(string $filter) : FilterObject
49 | {
50 | return new self($filter);
51 | }
52 |
53 | public function getFieldName() : string
54 | {
55 | return $this->fieldName;
56 | }
57 |
58 | public function getOperatorName() : string
59 | {
60 | return $this->operatorName;
61 | }
62 |
63 | public function isListType() : bool
64 | {
65 | return in_array(
66 | $this->getOperatorName(),
67 | $listOperators = ['list', 'nlist']
68 | );
69 | }
70 |
71 | public function isFieldEqualityType() : bool
72 | {
73 | return $this->getOperatorName() == 'field_eq';
74 | }
75 |
76 | public function getOperatorMeta() : string
77 | {
78 | return Dictionary::getOperators()[$this->getOperatorName()]['meta'];
79 | }
80 |
81 | public function haveOperatorSubstitutionPattern() : bool
82 | {
83 | $operator = Dictionary::getOperators()[$this->getOperatorName()];
84 |
85 | return isset($operator['substitution_pattern']);
86 | }
87 |
88 | public function getOperatorsSubstitutionPattern() : string
89 | {
90 | $operator = Dictionary::getOperators()[$this->getOperatorName()];
91 |
92 | return $operator['substitution_pattern'];
93 | }
94 |
95 | public function setRawFilter(string $rawFilter)
96 | {
97 | $this->rawFilter = $rawFilter;
98 | }
99 |
100 | public function getRawFilter() : string
101 | {
102 | return $this->rawFilter;
103 | }
104 |
105 | public function getOperator()
106 | {
107 | return $this->operatorName;
108 | }
109 |
110 | public function isNullType() : bool
111 | {
112 | return $this->getOperatorName() === 'isnull' || $this->getOperatorName() === 'isnotnull';
113 | }
114 |
115 | public function isListContainsType() : bool
116 | {
117 | return $this->getOperatorName() === 'listcontains';
118 | }
119 |
120 | public function getPosition()
121 | {
122 | return $this->position;
123 | }
124 | }
125 |
--------------------------------------------------------------------------------
/src/Mado/QueryBundle/Queries/Objects/Value.php:
--------------------------------------------------------------------------------
1 | filter = $filter;
14 | }
15 |
16 | public function getFilter()
17 | {
18 | if ($this->camesFromAdditionalFilters()) {
19 | return $this->filter[$this->getOperator()][0];
20 | }
21 |
22 | return $this->filter;
23 | }
24 |
25 | public function getValues()
26 | {
27 | return $this->filter[$this->getOperator()];
28 | }
29 |
30 | public function getOperator()
31 | {
32 | return key($this->filter);
33 | }
34 |
35 | public static function fromFilter($filter)
36 | {
37 | return new self($filter);
38 | }
39 |
40 | public function camesFromQueryString()
41 | {
42 | return is_string($this->filter);
43 | }
44 |
45 | public function camesFromAdditionalFilters()
46 | {
47 | return !$this->camesFromQueryString();
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/Mado/QueryBundle/Queries/Options/QueryOptionsBuilder.php:
--------------------------------------------------------------------------------
1 | entityAlias = $entityAlias;
16 | }
17 |
18 | public function getEntityAlias()
19 | {
20 | return $this->entityAlias;
21 | }
22 |
23 | public function fromRequest(Request $request = null)
24 | {
25 | $this->ensureEntityAliasIsDefined();
26 |
27 | $requestAttributes = [];
28 | foreach ($request->attributes->all() as $attributeName => $attributeValue) {
29 | $requestAttributes[$attributeName] = $request->attributes->get(
30 | $attributeName,
31 | $attributeValue);
32 | }
33 |
34 | $filters = $request->query->get('filtering', []);
35 | $orFilters = $request->query->get('filtering_or', []);
36 | $sorting = $request->query->get('sorting', []);
37 | $printing = $request->query->get('printing', []);
38 | $rel = $request->query->get('rel', '');
39 | $page = $request->query->get('page', '');
40 | $select = $request->query->get('select', $this->getEntityAlias());
41 | $filtering = $request->query->get('filtering', '');
42 | $limit = $request->query->get('limit', '');
43 |
44 | $filterOrCorrected = [];
45 |
46 | $count = 0;
47 | foreach ($orFilters as $key => $filter) {
48 | if (is_array($filter)) {
49 | foreach ($filter as $keyInternal => $internal) {
50 | $filterOrCorrected[$keyInternal . '|' . $count] = $internal;
51 | $count += 1;
52 | }
53 | } else {
54 | $filterOrCorrected[$key] = $filter;
55 | }
56 | }
57 |
58 | $requestProperties = [
59 | 'filtering' => $filtering,
60 | 'orFiltering' => $filterOrCorrected,
61 | 'limit' => $limit,
62 | 'page' => $page,
63 | 'filters' => $filters,
64 | 'orFilters' => $filterOrCorrected,
65 | 'sorting' => $sorting,
66 | 'rel' => $rel,
67 | 'printing' => $printing,
68 | 'select' => $select,
69 | ];
70 |
71 | $options = array_merge(
72 | $requestAttributes,
73 | $requestProperties
74 | );
75 |
76 | return QueryBuilderOptions::fromArray($options);
77 | }
78 |
79 | public function ensureEntityAliasIsDefined()
80 | {
81 | if (!$this->entityAlias) {
82 | throw new \RuntimeException(
83 | 'Oops! Entity alias is missing'
84 | );
85 | }
86 | }
87 |
88 | public function buildFromRequestAndCustomFilter(Request $request, $filter)
89 | {
90 | $this->ensureEntityAliasIsDefined();
91 |
92 | $filters = $request->query->get('filtering', []);
93 | $orFilters = $request->query->get('filtering_or', []);
94 | $sorting = $request->query->get('sorting', []);
95 | $printing = $request->query->get('printing', []);
96 | $rel = $request->query->get('rel', '');
97 | $page = $request->query->get('page', '');
98 | $select = $request->query->get('select', $this->getEntityAlias());
99 | $filtering = $request->query->get('filtering', '');
100 | $limit = $request->query->get('limit', '');
101 | $justCount = $request->query->get('justCount', 'false');
102 |
103 | $this->ensureFilterIsValid($filters);
104 |
105 | $filters = array_merge($filters, $filter);
106 |
107 | $filterOrCorrected = [];
108 |
109 | $count = 0;
110 | foreach ($orFilters as $key => $filterValue) {
111 | if (is_array($filterValue)) {
112 | foreach ($filterValue as $keyInternal => $internal) {
113 | $filterOrCorrected[$keyInternal . '|' . $count] = $internal;
114 | $count += 1;
115 | }
116 | } else {
117 | $filterOrCorrected[$key] = $filterValue;
118 | }
119 | }
120 |
121 | return QueryBuilderOptions::fromArray([
122 | '_route' => $request->attributes->get('_route'),
123 | '_route_params' => $request->attributes->get('_route_params', []),
124 | 'id' => $request->attributes->get('id'),
125 | 'filtering' => $filtering,
126 | 'limit' => $limit,
127 | 'page' => $page,
128 | 'filters' => $filters,
129 | 'orFilters' => $filterOrCorrected,
130 | 'sorting' => $sorting,
131 | 'rel' => $rel,
132 | 'printing' => $printing,
133 | 'select' => $select,
134 | 'justCount' => $justCount,
135 | ]);
136 | }
137 |
138 | private function ensureFilterIsValid($filters)
139 | {
140 | if (!is_array($filters)) {
141 | throw new InvalidFiltersException(
142 | "Wrong query string exception: "
143 | . var_export($filters, true) . "\n\n"
144 | . "Please check query string should be something like "
145 | . "http://:/?filtering[|]="
146 | );
147 | }
148 | }
149 |
150 | public function buildForOrFilter(Request $request, array $orFilter)
151 | {
152 | $this->ensureEntityAliasIsDefined();
153 |
154 | $filters = $request->query->get('filtering', []);
155 | $orFilters = $request->query->get('filtering_or', []);
156 | $sorting = $request->query->get('sorting', []);
157 | $printing = $request->query->get('printing', []);
158 | $rel = $request->query->get('rel', '');
159 | $page = $request->query->get('page', '');
160 | $select = $request->query->get('select', $this->getEntityAlias());
161 | $filtering = $request->query->get('filtering', '');
162 | $limit = $request->query->get('limit', '');
163 |
164 | $orFilters = array_merge($orFilters, $orFilter);
165 |
166 | $filterOrCorrected = [];
167 |
168 | $count = 0;
169 | foreach ($orFilters as $key => $filter) {
170 | if (is_array($filter)) {
171 | foreach ($filter as $keyInternal => $internal) {
172 | $filterOrCorrected[$keyInternal . '|' . $count] = $internal;
173 | $count += 1;
174 | }
175 | } else {
176 | $filterOrCorrected[$key] = $filter;
177 | }
178 | }
179 |
180 | return QueryBuilderOptions::fromArray([
181 | '_route' => $request->attributes->get('_route'),
182 | '_route_params' => $request->attributes->get('_route_params', []),
183 | 'id' => $request->attributes->get('id'),
184 | 'filtering' => $filtering,
185 | 'limit' => $limit,
186 | 'page' => $page,
187 | 'filters' => $filters,
188 | 'orFilters' => $filterOrCorrected,
189 | 'sorting' => $sorting,
190 | 'rel' => $rel,
191 | 'printing' => $printing,
192 | 'select' => $select,
193 | ]);
194 | }
195 | }
196 |
--------------------------------------------------------------------------------
/src/Mado/QueryBundle/Queries/OrFilter.php:
--------------------------------------------------------------------------------
1 | entityAlias = $entityAlias;
28 | $this->fields = $fields;
29 | $this->join = $join;
30 |
31 | $this->conditions = [];
32 | $this->parameters = [];
33 | $this->parser = new StringParser();
34 | }
35 |
36 | public function createFilter(array $orFilters)
37 | {
38 | foreach ($orFilters as $filter => $value) {
39 | $this->applyFilter(
40 | Objects\FilterObject::fromRawFilter($filter),
41 | $value
42 | );
43 | }
44 | }
45 |
46 | private function applyFilter(Objects\FilterObject $filterObject, $value)
47 | {
48 | $position = $filterObject->getPosition();
49 |
50 | if (!array_key_exists($position, $this->conditions)) {
51 | $this->conditions[$position] = '';
52 | }
53 |
54 | $whereCondition = $this->entityAlias . '.' . $filterObject->getFieldName() . ' '
55 | . $filterObject->getOperatorMeta();
56 |
57 | // controllo se il filtro che mi arriva dalla richiesta è una proprietà di questa entità
58 | // esempio per users: filtering[username|contains]=mado
59 | if (in_array($filterObject->getFieldName(), $this->fields)) {
60 | $salt = '_' . random_int(111, 999);
61 |
62 | if ($filterObject->isListType()) {
63 | $whereCondition .= ' (:field_' . $filterObject->getFieldName() . $salt . ')';
64 | } else if ($filterObject->isFieldEqualityType()) {
65 | $whereCondition .= $this->entityAlias . '.' . $value;
66 | } elseif ($filterObject->isNullType()) {
67 | $whereCondition .= ' ';
68 | } else {
69 | $whereCondition .= ' :field_' . $filterObject->getFieldName() . $salt;
70 | }
71 |
72 | if ('' != $this->conditions[$position]) {
73 | $this->conditions[$position] .= ' OR ' . $whereCondition;
74 | } else {
75 | $this->conditions[$position] = $whereCondition;
76 | }
77 |
78 | if ($filterObject->haveOperatorSubstitutionPattern()) {
79 | if ($filterObject->isListType()) {
80 | $value = explode(',', $value);
81 | } else {
82 | $value = str_replace(
83 | '{string}',
84 | $value,
85 | $filterObject->getOperatorsSubstitutionPattern()
86 | );
87 | }
88 | }
89 |
90 | if (!$filterObject->isNullType()) {
91 | $this->parameters[] = [
92 | 'field' => 'field_' . $filterObject->getFieldName() . $salt,
93 | 'value' => $value
94 | ];
95 | }
96 | } else {
97 | $isNotARelation = 0 !== strpos($filterObject->getFieldName(), 'Embedded.');
98 | if ($isNotARelation) {
99 | $whereCondition .= ' ' . $this->entityAlias . '.' . $value;
100 | if ('' != $this->conditions[$position]) {
101 | $this->conditions[$position] .= ' OR ' . $whereCondition;
102 | } else {
103 | $this->conditions[$position] = $whereCondition;
104 | }
105 | }
106 | }
107 |
108 | // controllo se il filtro si riferisce ad una relazione dell'entità quindi devo fare dei join
109 | // esempio per users: filtering[_embedded.groups.name|eq]=admin
110 | if (strstr($filterObject->getRawFilter(), '_embedded.')) {
111 | $this->join->join($filterObject->getRawFilter(), self::OR_OPERATOR_LOGIC);
112 | $this->relationEntityAlias = $this->join->getRelationEntityAlias();
113 |
114 | $embeddedFields = explode('.', $filterObject->getFieldName());
115 | $embeddableFieldName = $this->parser->camelize($embeddedFields[count($embeddedFields) - 1]);
116 |
117 | $salt = '_' . random_int(111, 999);
118 |
119 | $whereCondition = $this->relationEntityAlias . '.' . $embeddableFieldName . ' '
120 | . $filterObject->getOperatorMeta();
121 |
122 | if ($filterObject->isListType()) {
123 | $whereCondition .= ' (:field_' . $embeddableFieldName . $salt . ')';
124 | } elseif ($filterObject->isNullType()) {
125 | $whereCondition .= ' ';
126 | } else {
127 | $whereCondition .= ' :field_' . $embeddableFieldName . $salt;
128 | }
129 |
130 | if ('' != $this->conditions[$position]) {
131 | $this->conditions[$position] .= ' OR ' . $whereCondition;
132 | } else {
133 | $this->conditions[$position] = $whereCondition;
134 | }
135 |
136 | if ($filterObject->haveOperatorSubstitutionPattern()) {
137 | if ($filterObject->isListType()) {
138 | $value = explode(',', $value);
139 | } else {
140 | $value = str_replace(
141 | '{string}',
142 | $value,
143 | $filterObject->getOperatorsSubstitutionPattern()
144 | );
145 | }
146 | }
147 |
148 | if (!$filterObject->isNullType()) {
149 | $this->parameters[] = [
150 | 'field' => 'field_' . $embeddableFieldName . $salt,
151 | 'value' => $value
152 | ];
153 | }
154 | }
155 | }
156 |
157 | public function getConditions() :array
158 | {
159 | return $this->conditions;
160 | }
161 |
162 | public function getParameters() :array
163 | {
164 | return $this->parameters;
165 | }
166 |
167 | public function getLeftJoin() :array
168 | {
169 | return $this->join->getLeftJoin();
170 | }
171 | }
172 |
--------------------------------------------------------------------------------
/src/Mado/QueryBundle/Queries/QueryBuilderFactory.php:
--------------------------------------------------------------------------------
1 | getValueAvailableFilters());
48 | }
49 |
50 | public function getValueAvailableFilters()
51 | {
52 | return Dictionary::getOperators();
53 | }
54 |
55 | public function setFields(array $fields = [])
56 | {
57 | $this->fields = $fields;
58 |
59 | return $this;
60 | }
61 |
62 | public function getFields()
63 | {
64 | if (null === $this->fields) {
65 | throw new \RuntimeException(
66 | 'Oops! Fields are not defined'
67 | );
68 | }
69 |
70 | return $this->fields;
71 | }
72 |
73 | /** @since version 2.2 */
74 | public function setAndFilters(array $andFilters = [])
75 | {
76 | $this->andFilters = $andFilters;
77 |
78 | return $this;
79 | }
80 |
81 | public function setOrFilters(array $orFilters = [])
82 | {
83 | $this->orFilters = $orFilters;
84 |
85 | return $this;
86 | }
87 |
88 | public function setSorting(array $sorting = [])
89 | {
90 | $this->sorting = $sorting;
91 |
92 | return $this;
93 | }
94 |
95 | public function getAndFilters()
96 | {
97 | return $this->andFilters;
98 | }
99 |
100 | public function getOrFilters()
101 | {
102 | return $this->orFilters;
103 | }
104 |
105 | /**
106 | * @param String $relation Nome della relazione semplice (groups.name) o con embedded (_embedded.groups.name)
107 | * @return $this
108 | */
109 | public function join(String $relation, $logicOperator = self::AND_OPERATOR_LOGIC)
110 | {
111 | $this->joinFactory->join($relation, $logicOperator);
112 |
113 | $innerJoins = $this->joinFactory->getInnerJoin();
114 | $leftJoins = $this->joinFactory->getLeftJoin();
115 |
116 | foreach ($innerJoins as $join) {
117 | if (!$this->joinAlreadyDone($join)) {
118 | $this->storeJoin($join);
119 | $this->qBuilder->innerJoin($join['field'], $join['relation']);
120 | }
121 | }
122 |
123 | foreach ($leftJoins as $join) {
124 | if (!$this->joinAlreadyDone($join)) {
125 | $this->storeJoin($join);
126 | $this->qBuilder->leftJoin($join['field'], $join['relation']);
127 | }
128 | }
129 | }
130 |
131 | private function joinAlreadyDone($join) :bool
132 | {
133 | $needle = $join['field'] . '_' . $join['relation'];
134 | if (in_array($needle, $this->joins)) {
135 | return true;
136 | }
137 |
138 | return false;
139 | }
140 |
141 | private function storeJoin($join)
142 | {
143 | $needle = $join['field'] . '_' . $join['relation'];
144 | $this->joins[] = $needle;
145 | }
146 |
147 | public function filter()
148 | {
149 | if (null === $this->andFilters && null === $this->orFilters) {
150 | throw new Exceptions\MissingFiltersException();
151 | }
152 |
153 | if (!$this->fields) {
154 | throw new Exceptions\MissingFieldsException();
155 | }
156 |
157 | if (null !== $this->andFilters) {
158 | $andFilterFactory = new AndFilter($this->entityAlias, $this->fields, $this->joinFactory);
159 | $andFilterFactory->createFilter($this->andFilters);
160 |
161 | $conditions = $andFilterFactory->getConditions();
162 | $parameters = $andFilterFactory->getParameters();
163 | $innerJoins = $andFilterFactory->getInnerJoin();
164 |
165 | foreach($conditions as $condition) {
166 | $this->qBuilder->andWhere($condition);
167 | }
168 |
169 | foreach($parameters as $parameter) {
170 | $this->qBuilder->setParameter($parameter['field'], $parameter['value']);
171 | }
172 |
173 | foreach ($innerJoins as $join) {
174 | if (!$this->joinAlreadyDone($join)) {
175 | $this->storeJoin($join);
176 | $this->qBuilder->innerJoin($join['field'], $join['relation']);
177 | }
178 | }
179 | }
180 |
181 | if (null !== $this->orFilters) {
182 | $orFilterFactory = new OrFilter($this->entityAlias, $this->fields, $this->joinFactory);
183 | $orFilterFactory->createFilter($this->orFilters);
184 |
185 | $conditions = $orFilterFactory->getConditions();
186 | $parameters = $orFilterFactory->getParameters();
187 | $leftJoins = $orFilterFactory->getLeftJoin();
188 |
189 | foreach ($conditions as $condition) {
190 | if ($condition !== '') {
191 | $this->qBuilder->andWhere($condition);
192 |
193 | foreach ($parameters as $parameter) {
194 | $this->qBuilder->setParameter($parameter['field'], $parameter['value']);
195 | }
196 |
197 | foreach ($leftJoins as $join) {
198 | if (!$this->joinAlreadyDone($join)) {
199 | $this->storeJoin($join);
200 | $this->qBuilder->leftJoin($join['field'], $join['relation']);
201 | }
202 | }
203 | }
204 | }
205 | }
206 |
207 | return $this;
208 | }
209 |
210 | public function sort()
211 | {
212 | if (!$this->fields) {
213 | throw new \RuntimeException(
214 | 'Oops! Fields are not defined'
215 | );
216 | }
217 |
218 | if (null === $this->sorting) {
219 | throw new \RuntimeException(
220 | 'Oops! Sorting is not defined'
221 | );
222 | }
223 |
224 | foreach ($this->sorting as $sort => $val) {
225 | $val = strtolower($val);
226 |
227 | $fieldName = $this->parser->camelize($sort);
228 |
229 | if (in_array($fieldName, $this->fields)) {
230 | $direction = ($val === self::DIRECTION_AZ) ? self::DIRECTION_AZ : self::DIRECTION_ZA;
231 | $this->ensureQueryBuilderIsDefined();
232 | $this->qBuilder->addOrderBy($this->entityAlias . '.' . $fieldName, $direction);
233 | }
234 |
235 | if (strstr($sort, '_embedded.')) {
236 | $this->join($sort);
237 | $relationEntityAlias = $this->joinFactory->getRelationEntityAlias();
238 |
239 | $embeddedFields = explode('.', $sort);
240 | $fieldName = $this->parser->camelize($embeddedFields[count($embeddedFields) - 1]);
241 | $direction = ($val === self::DIRECTION_AZ) ? self::DIRECTION_AZ : self::DIRECTION_ZA;
242 |
243 | $this->qBuilder->addOrderBy($relationEntityAlias . '.' . $fieldName, $direction);
244 | }
245 |
246 | }
247 |
248 | return $this;
249 | }
250 |
251 | public function getQueryBuilder() :QueryBuilder
252 | {
253 | if (!$this->qBuilder) {
254 | throw new UnInitializedQueryBuilderException();
255 | }
256 |
257 | return $this->qBuilder;
258 | }
259 |
260 | public function setRel(array $rel)
261 | {
262 | $this->rel = $rel;
263 |
264 | return $this;
265 | }
266 |
267 | public function getRel() : array
268 | {
269 | return $this->rel;
270 | }
271 |
272 | public function addRel($relation)
273 | {
274 | array_push($this->rel, $relation);
275 | }
276 |
277 | public function setPrinting($printing)
278 | {
279 | $this->printing = $printing;
280 |
281 | return $this;
282 | }
283 |
284 | public function getPrinting()
285 | {
286 | return $this->printing;
287 | }
288 |
289 | public function setPage(int $page)
290 | {
291 | $this->page = $page;
292 |
293 | return $this;
294 | }
295 |
296 | public function getPage() :int
297 | {
298 | return $this->page;
299 | }
300 |
301 | public function setPageLength($pageLength)
302 | {
303 | $this->pageLength = $pageLength;
304 |
305 | return $this;
306 | }
307 |
308 | public function getPageLength()
309 | {
310 | return $this->pageLength;
311 | }
312 |
313 | public function setSelect($select) : QueryBuilderFactory
314 | {
315 | $this->select = $select;
316 |
317 | return $this;
318 | }
319 |
320 | public function getSelect()
321 | {
322 | return $this->select;
323 | }
324 |
325 | public function getEntityManager() : EntityManager
326 | {
327 | return $this->manager;
328 | }
329 |
330 | public function ensureQueryBuilderIsDefined()
331 | {
332 | if (!$this->qBuilder) {
333 | throw new \RuntimeException(
334 | 'Oops! QueryBuilder was never initialized. '
335 | . "\n" . 'QueryBuilderFactory::createQueryBuilder()'
336 | . "\n" . 'QueryBuilderFactory::createSelectAndGroupBy()'
337 | );
338 | }
339 | }
340 | }
341 |
--------------------------------------------------------------------------------
/src/Mado/QueryBundle/Queries/QueryBuilderOptions.php:
--------------------------------------------------------------------------------
1 | options = $options;
12 | }
13 |
14 | public static function fromArray(array $options)
15 | {
16 | return new self($options);
17 | }
18 |
19 | public function get($option, $defaultValue = null)
20 | {
21 | $this->validateOption($option, $defaultValue);
22 |
23 | if (
24 | !isset($this->options[$option])
25 | || empty($this->options[$option])
26 | ) {
27 | return $defaultValue;
28 | }
29 |
30 | return $this->options[$option];
31 | }
32 |
33 | public function getAndFilters()
34 | {
35 | return $this->get('filters', []);
36 | }
37 |
38 | public function getOrFilters()
39 | {
40 | return $this->get('orFilters', []);
41 | }
42 |
43 | public function getSorting()
44 | {
45 | return $this->get('sorting', []);
46 | }
47 |
48 | public function getRel()
49 | {
50 | return $this->get('rel', []);
51 | }
52 |
53 | public function getPrinting()
54 | {
55 | return $this->get('printing', []);
56 | }
57 |
58 | public function getSelect()
59 | {
60 | return $this->get('select');
61 | }
62 |
63 | public function validateOption($option, $defaultValue)
64 | {
65 | $optionIsDefinedNegativeAndNotNull = (
66 | !isset($this->options[$option])
67 | || $this->options[$option] < 0
68 | ) && $defaultValue == null;
69 |
70 | if ('limit' == $option && $optionIsDefinedNegativeAndNotNull) {
71 | $this->options[$option] = PHP_INT_MAX;
72 | }
73 | }
74 |
75 | public function requireJustCount()
76 | {
77 | return isset($this->options['justCount'])
78 | && $this->options['justCount'] === 'true';
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/src/Mado/QueryBundle/Repositories/BaseRepository.php:
--------------------------------------------------------------------------------
1 | metadata = new MetaDataAdapter();
47 | $this->metadata->setClassMetadata($this->getClassMetadata());
48 | $this->metadata->setEntityName($this->getEntityName());
49 |
50 | $this->queryBuilderFactory = new QueryBuilderFactory($this->getEntityManager());
51 |
52 | $this->queryOptionBuilder = new QueryOptionsBuilder();
53 | $entityAlias = $this->metadata->getEntityAlias();
54 | $this->queryOptionBuilder->setEntityAlias($entityAlias);
55 | }
56 |
57 | public function initFromQueryBuilderOptions(QueryBuilderOptions $options)
58 | {
59 | $this->queryBuilderFactory->createQueryBuilder(
60 | $this->getEntityName(),
61 | $this->metadata->getEntityAlias()
62 | );
63 |
64 | $this->queryBuilderFactory->loadMetadataAndOptions(
65 | $this->metadata,
66 | $options
67 | );
68 | }
69 |
70 | public function getQueryBuilderFactory()
71 | {
72 | $this->initFromQueryBuilderOptions($this->queryOptions);
73 |
74 | return $this->queryBuilderFactory;
75 | }
76 |
77 | public function useResultCache($bool)
78 | {
79 | $this->useResultCache = $bool;
80 | }
81 |
82 | public function setRequest(Request $request)
83 | {
84 | return $this->setQueryOptionsFromRequest($request);
85 | }
86 |
87 | public function setRequestWithFilter(Request $request, $filter)
88 | {
89 | return $this->setQueryOptionsFromRequestWithCustomFilter($request, $filter);
90 | }
91 |
92 | public function setRequestWithOrFilter(Request $request, $orFilter)
93 | {
94 | return $this->setQueryOptionsFromRequestWithCustomOrFilter($request, $orFilter);
95 | }
96 |
97 | public function setQueryOptions(QueryBuilderOptions $options)
98 | {
99 | $this->queryOptions = $options;
100 | }
101 |
102 | public function setQueryOptionsFromRequest(Request $request = null)
103 | {
104 | $this->queryOptions = $this->queryOptionBuilder->fromRequest($request);
105 |
106 | return $this;
107 | }
108 |
109 | public function setQueryOptionsFromRequestWithCustomFilter(Request $request = null, $filter)
110 | {
111 | $this->queryOptions = $this->queryOptionBuilder->buildFromRequestAndCustomFilter($request, $filter);
112 |
113 | return $this;
114 | }
115 |
116 | public function setQueryOptionsFromRequestWithCustomOrFilter(Request $request = null, $orFilter)
117 | {
118 | $this->queryOptions = $this->queryOptionBuilder->buildForOrFilter($request);
119 |
120 | return $this;
121 | }
122 |
123 | public function getRequest()
124 | {
125 | return $this->request;
126 | }
127 |
128 | public function setRouteName($routeName = '')
129 | {
130 | $this->routeName = $routeName;
131 | return $this;
132 | }
133 |
134 | public function findAllNoPaginated()
135 | {
136 | $queryBuilderFactory = $this->getQueryBuilderFactory()
137 | ->filter()
138 | ->sort();
139 |
140 | $doctrineQueryBuilder = $queryBuilderFactory->getQueryBuilder();
141 |
142 | return $doctrineQueryBuilder->getQuery()->getResult();
143 | }
144 |
145 | public function findAllPaginated()
146 | {
147 | $this->initFromQueryBuilderOptions($this->queryOptions);
148 |
149 | $this->queryBuilderFactory->filter();
150 | $this->queryBuilderFactory->sort();
151 |
152 | $queryBuilder = $this->queryBuilderFactory->getQueryBuilder();
153 |
154 | if ($this->queryOptions->requireJustCount()) {
155 | $metadata = $this->metadata;
156 | $rootEntityAlias = $metadata->getEntityAlias();
157 | $select = 'count(' . $rootEntityAlias . '.id)';
158 |
159 | $count = $queryBuilder
160 | ->select($select)
161 | ->getQuery()
162 | ->getSingleScalarResult();
163 |
164 | return [ 'count' => $count ];
165 | }
166 |
167 | $this->lastQuery = $queryBuilder->getQuery()->getSql();
168 | $this->lastParameters = $queryBuilder->getQuery()->getParameters();
169 |
170 | return $this->paginateResults($queryBuilder);
171 | }
172 |
173 | public function getLastQuery()
174 | {
175 | return [
176 | 'query' => $this->lastQuery,
177 | 'params' => $this->lastParameters,
178 | ];
179 | }
180 |
181 | protected function paginateResults(QueryBuilder $queryBuilder)
182 | {
183 | $ormAdapter = new DoctrineORMAdapter($queryBuilder);
184 | $pagerfantaBuilder = new PagerfantaBuilder(new PagerfantaFactory(), $ormAdapter);
185 | $pager = new Pager();
186 | return $pager->paginateResults(
187 | $this->queryOptions,
188 | $ormAdapter,
189 | $pagerfantaBuilder,
190 | $this->routeName,
191 | $this->useResultCache
192 | );
193 | }
194 |
195 | protected function getCurrentEntityAlias() : string
196 | {
197 | return $this->currentEntityAlias;
198 | }
199 |
200 | protected function setCurrentEntityAlias(string $currentEntityAlias)
201 | {
202 | $this->currentEntityAlias = $currentEntityAlias;
203 | }
204 |
205 | protected function getEmbeddedFields() : array
206 | {
207 | return $this->embeddedFields;
208 | }
209 |
210 | protected function setEmbeddedFields(array $embeddedFields)
211 | {
212 | $this->embeddedFields = $embeddedFields;
213 | }
214 |
215 | public function getEntityAlias() : string
216 | {
217 | return $this->metadata->getEntityAlias();
218 | }
219 |
220 | protected function relationship($queryBuilder)
221 | {
222 | return $queryBuilder;
223 | }
224 |
225 | public function getQueryBuilderFactoryWithoutInitialization()
226 | {
227 | return $this->queryBuilderFactory;
228 | }
229 | }
230 |
--------------------------------------------------------------------------------
/src/Mado/QueryBundle/Resources/config/services.yml:
--------------------------------------------------------------------------------
1 | services:
2 |
3 | mado.query_builder_factory:
4 | class: Mado\QueryBundle\Queries\QueryBuilderFactory
5 | arguments:
6 | - "@doctrine.orm.entity_manager"
7 |
8 | mado.sherlock:
9 | class: Mado\QueryBundle\Component\Sherlock\Sherlock
10 | arguments:
11 | - "@doctrine.orm.entity_manager"
12 |
--------------------------------------------------------------------------------
/src/Mado/QueryBundle/Services/AdditionalFilterExtractor.php:
--------------------------------------------------------------------------------
1 | additionalFilters = $user->getAdditionalFilters();
14 | }
15 |
16 | public static function fromUser(AdditionalFilterable $user)
17 | {
18 | return new self($user);
19 | }
20 |
21 | public function getFilters(string $filterName)
22 | {
23 | if (isset($this->additionalFilters[$filterName])) {
24 | return $this->additionalFilters[$filterName];
25 | }
26 |
27 | return '';
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/Mado/QueryBundle/Services/Pager.php:
--------------------------------------------------------------------------------
1 | setRouter(new Router());
22 | }
23 |
24 | public function setRouter(Router $router)
25 | {
26 | $this->router = $router;
27 | }
28 |
29 | public function paginateResults (
30 | QueryBuilderOptions $queryOptions,
31 | DoctrineORMAdapter $ormAdapter,
32 | PagerfantaBuilder $pagerfantaBuilder,
33 | $routeName,
34 | $useResultCache
35 | ) {
36 | $limit = $queryOptions->get('limit', self::DEFAULT_LIMIT);
37 | $page = $queryOptions->get('page', self::DEFAULT_PAGE);
38 |
39 | $query = $ormAdapter->getQuery();
40 | if (isset($useResultCache) && $useResultCache) {
41 | $query->useResultCache(true, self::DEFAULT_LIFETIME);
42 | }
43 |
44 | $route = $this->router->createRouter($queryOptions, $routeName);
45 |
46 | return $pagerfantaBuilder->createRepresentation($route, $limit, $page);
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/Mado/QueryBundle/Services/Router.php:
--------------------------------------------------------------------------------
1 | get('_route_params')) {
16 | $routeParams = array_keys($queryOptions->get('_route_params'));
17 | }
18 |
19 | $list = array_merge([
20 | 'filtering',
21 | 'limit',
22 | 'page',
23 | 'sorting',
24 | ], $routeParams);
25 |
26 | foreach ($list as $itemKey => $itemValue) {
27 | $params[$itemValue] = $queryOptions->get($itemValue);
28 | }
29 |
30 | if (!isset($routeName)) {
31 | $routeName = $queryOptions->get('_route');
32 | }
33 |
34 | return new Route($routeName, $params);
35 | }
36 | }
--------------------------------------------------------------------------------
/src/Mado/QueryBundle/Services/StringParser.php:
--------------------------------------------------------------------------------
1 | exploded($string));
10 | }
11 |
12 | private function exploded(string $string)
13 | {
14 | return explode('_', $string);
15 | }
16 |
17 | public function tokenize(string $string, int $position)
18 | {
19 | return $this->exploded($string)[$position];
20 | }
21 |
22 | public function camelize($string)
23 | {
24 | $camelized = $this->tokenize($string, 0);
25 |
26 | for ($i = 1; $i < $this->numberOfTokens($string); $i++) {
27 | $camelized .= ucfirst($this->tokenize($string, $i));
28 | }
29 |
30 | return $camelized;
31 | }
32 |
33 | public static function dotNotationFor(string $class)
34 | {
35 | $dottedFullyQualifiedClassName = str_replace( '\\', '.', $class);
36 | return strtolower($dottedFullyQualifiedClassName);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/tests/Mado/QueryBundle/Component/Meta/DijkstraTest.php:
--------------------------------------------------------------------------------
1 | samepleJson = [
11 | "AppBundle\\Entity\\a" => [
12 | "relations" => [
13 | "item" => "AppBundle\\Entity\\Fizz",
14 | ]
15 | ],
16 | "AppBundle\\Entity\\mood" => [
17 | "relations" => [
18 | "item" => "AppBundle\\Entity\\b",
19 | ]
20 | ],
21 | "AppBundle\\Entity\\Fizz" => [
22 | "relations" => [
23 | "item" => "AppBundle\\Entity\\mood",
24 | "item" => "AppBundle\\Entity\\b",
25 | ]
26 | ],
27 | "AppBundle\\Entity\\b" => [
28 | "relations" => [
29 | "item" => "AppBundle\\Entity\\Fizz",
30 | "icdsatem" => "AppBundle\\Entity\\a",
31 | ]
32 | ],
33 | ];
34 |
35 | $dijkstra = new Dijkstra();
36 | $dijkstra->setMap($this->samepleJson);
37 |
38 | $paths = $dijkstra->shortestPaths(
39 | 'AppBundle\\Entity\\a',
40 | 'AppBundle\\Entity\\b'
41 | );
42 |
43 | $this->assertEquals(
44 | [[
45 | 'AppBundle\\Entity\\a',
46 | 'AppBundle\\Entity\\Fizz',
47 | 'AppBundle\\Entity\\b',
48 | ]],
49 | $paths
50 | );
51 | }
52 |
53 | public function testFindAlternativePaths()
54 | {
55 | $this->samepleJson = [
56 | "AppBundle\\Entity\\a" => [
57 | "relations" => [
58 | "item" => "AppBundle\\Entity\\Fizz",
59 | ]
60 | ],
61 | "AppBundle\\Entity\\mood" => [
62 | "relations" => [
63 | "item" => "AppBundle\\Entity\\b",
64 | ]
65 | ],
66 | "AppBundle\\Entity\\Fizz" => [
67 | "relations" => [
68 | "item" => "AppBundle\\Entity\\mood",
69 | "item" => "AppBundle\\Entity\\b",
70 | ]
71 | ],
72 | "AppBundle\\Entity\\b" => [
73 | "relations" => [
74 | "item" => "AppBundle\\Entity\\Fizz",
75 | "icdsatem" => "AppBundle\\Entity\\a",
76 | ]
77 | ],
78 | ];
79 |
80 | $dijkstra = new Dijkstra();
81 | $dijkstra->setMap($this->samepleJson);
82 |
83 | $paths = $dijkstra->shortestPaths(
84 | 'AppBundle\\Entity\\a',
85 | 'AppBundle\\Entity\\b',
86 | $excluded = [
87 | 'AppBundle\\Entity\\mood',
88 | ]
89 | );
90 |
91 | $this->assertEquals(
92 | [
93 | 'AppBundle\\Entity\\a',
94 | 'AppBundle\\Entity\\Fizz',
95 | 'AppBundle\\Entity\\b',
96 | ],
97 | $paths[0]
98 | );
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/tests/Mado/QueryBundle/Component/Meta/DijkstraWalkerTest.php:
--------------------------------------------------------------------------------
1 | mapper = $this
14 | ->getMockBuilder('Mado\QueryBundle\Component\Meta\DataMapper')
15 | ->disableOriginalConstructor()
16 | ->getMock();
17 |
18 | $this->dijkstra = $this
19 | ->getMockBuilder('Mado\QueryBundle\Component\Meta\Dijkstra')
20 | ->disableOriginalConstructor()
21 | ->getMock();
22 |
23 | $this->walker = new DijkstraWalker(
24 | $this->mapper,
25 | $this->dijkstra
26 | );
27 |
28 | $this->walker->getPath();
29 | }
30 |
31 | public function testBuildPathUsingDijkstra()
32 | {
33 | $this->mapper = $this
34 | ->getMockBuilder('Mado\QueryBundle\Component\Meta\DataMapper')
35 | ->disableOriginalConstructor()
36 | ->getMock();
37 | $this->mapper->expects($this->once())
38 | ->method('getMap')
39 | ->will($this->returnValue($laMappa = [
40 | 'start' => [
41 | 'relations' => [
42 | 'fine' => 'end',
43 | ]
44 | ],
45 | 'end' => [
46 | 'relations' => [
47 | 'inizio' => 'start',
48 | ]
49 | ]
50 | ]));
51 |
52 | $this->dijkstra = $this
53 | ->getMockBuilder('Mado\QueryBundle\Component\Meta\Dijkstra')
54 | ->disableOriginalConstructor()
55 | ->getMock();
56 | $this->dijkstra->expects($this->once())
57 | ->method('setMap')
58 | ->with($laMappa);
59 | $this->dijkstra->expects($this->once())
60 | ->method('shortestPaths')
61 | ->will($this->returnValue([[
62 | 'start',
63 | 'end'
64 | ]]));
65 |
66 | $this->walker = new DijkstraWalker(
67 | $this->mapper,
68 | $this->dijkstra
69 | );
70 |
71 | $this->walker->buildPathBetween('start', 'end');
72 |
73 | $pathFound = $this->walker->getPath();
74 |
75 | $this->assertEquals(
76 | '_embedded.fine',
77 | $pathFound
78 | );
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/tests/Mado/QueryBundle/Component/Meta/MapBuilderTest.php:
--------------------------------------------------------------------------------
1 | factory = $this
13 | ->getMockBuilder('Doctrine\ORM\Mapping\ClassMetadataFactory')
14 | ->disableOriginalConstructor()
15 | ->getMock();
16 | $this->factory->expects($this->once())
17 | ->method('getAllMetadata')
18 | ->will($this->returnValue($expectedMap));
19 |
20 | $this->manager = $this
21 | ->getMockBuilder('Doctrine\ORM\EntityManager')
22 | ->disableOriginalConstructor()
23 | ->getMock();
24 | $this->manager->expects($this->once())
25 | ->method('getMetadataFactory')
26 | ->will($this->returnValue($this->factory));
27 |
28 | $mapBuilder = new MapBuilder(
29 | $this->manager
30 | );
31 |
32 | $map = $mapBuilder->getMap();
33 |
34 | $this->assertEquals(
35 | $expectedMap,
36 | $map
37 | );
38 | }
39 |
40 | public function testBuildMapWithParentAndRelationEntities()
41 | {
42 | $expectedMap = [];
43 |
44 | $this->factory = $this
45 | ->getMockBuilder('Doctrine\ORM\Mapping\ClassMetadataFactory')
46 | ->disableOriginalConstructor()
47 | ->getMock();
48 | $this->factory->expects($this->once())
49 | ->method('getAllMetadata')
50 | ->will($this->returnValue(function () {
51 | return [
52 | 'SomeBundle\Entity\ParentEntity' => [
53 | 'relations' => [
54 | 'relName' => 'SomeOtherBundle\Entity\ChildEntity',
55 | ]
56 | ]
57 | ];
58 | }));
59 |
60 | $this->manager = $this
61 | ->getMockBuilder('Doctrine\ORM\EntityManager')
62 | ->disableOriginalConstructor()
63 | ->getMock();
64 | $this->manager->expects($this->once())
65 | ->method('getMetadataFactory')
66 | ->will($this->returnValue($this->factory));
67 |
68 | $mapBuilder = new MapBuilder(
69 | $this->manager
70 | );
71 |
72 | $map = $mapBuilder->getMap();
73 |
74 | $this->assertEquals(
75 | $expectedMap,
76 | $map
77 | );
78 | }
79 |
80 | public function testUsingCacheDoctirneIsNotCalled()
81 | {
82 | $expectedMap = [
83 | 'root' => [
84 | 'relations' => [
85 | 'rel_name' => 'Entity'
86 | ]
87 | ]
88 | ];
89 |
90 | $this->manager = $this
91 | ->getMockBuilder('Doctrine\ORM\EntityManager')
92 | ->disableOriginalConstructor()
93 | ->getMock();
94 |
95 | $this->manager->expects($this->never())
96 | ->method('getMetadataFactory');
97 |
98 | $mapBuilder = new MapBuilder($this->manager);
99 |
100 | $mapBuilder->forceCache($expectedMap);
101 |
102 | $map = $mapBuilder->getMap();
103 |
104 | $this->assertEquals(
105 | $expectedMap,
106 | $map
107 | );
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/tests/Mado/QueryBundle/Objects/FilterTest.php:
--------------------------------------------------------------------------------
1 | ['list' => [2, 3, 4]],
12 | 'path' => 'path.to',
13 | ]);
14 |
15 | $this->assertEquals('list',$f->getOperator());
16 | $this->assertEquals('path.to',$f->getPath());
17 | $this->assertEquals('2,3,4',$f->getIds());
18 | $this->assertEquals('path.to.id|list',$f->getFieldAndOperator());
19 | $this->assertEquals('path.to.id',$f->getField());
20 | }
21 |
22 | public function testAllowPathChange()
23 | {
24 | $old = Filter::box([
25 | 'ids' => ['list' => [2, 3, 4]],
26 | 'path' => 'path.to',
27 | ]);
28 |
29 | $new = $old->withPath('new.path');
30 |
31 | $this->assertEquals('new.path',$new->getPath());
32 | $this->assertEquals('new.path.id|list',$new->getFieldAndOperator());
33 | $this->assertEquals('new.path.id',$new->getField());
34 | }
35 |
36 | public function testAllowFullPathChange()
37 | {
38 | $old = Filter::box([
39 | 'ids' => ['list' => [2, 3, 4]],
40 | 'path' => 'path.to',
41 | ]);
42 |
43 | $new = $old->withFullPath('new.path|foo');
44 |
45 | $this->assertEquals('new.path',$new->getPath());
46 | $this->assertEquals('new.path|foo',$new->getFieldAndOperator());
47 | $this->assertEquals('new.path',$new->getField());
48 | }
49 |
50 | public function testPathChangeEmpty()
51 | {
52 | $old = Filter::box([
53 | 'ids' => ['list' => [2, 3, 4]],
54 | 'path' => 'path.to',
55 | ]);
56 |
57 | $new = $old->withPath('');
58 |
59 | $this->assertEquals('',$new->getPath());
60 | $this->assertEquals('id|list',$new->getFieldAndOperator());
61 | $this->assertEquals('id',$new->getField());
62 | }
63 |
64 | public function testBuildFromQueryString()
65 | {
66 | $queryStringFilter = Filter::fromQueryStringFilter([
67 | '_embedded.attributes.alfanumerico12|eq' => 'GTK'
68 | ]);
69 |
70 | $this->assertEquals('_embedded.attributes.alfanumerico12|eq',$queryStringFilter->getFieldAndOperator());
71 | $this->assertEquals('_embedded.attributes.alfanumerico12',$queryStringFilter->getField());
72 | $this->assertEquals('GTK',$queryStringFilter->getValue());
73 | $this->assertEquals('eq',$queryStringFilter->getOperator());
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/tests/Mado/QueryBundle/Objects/HalResponseTest.php:
--------------------------------------------------------------------------------
1 | 42,
12 | ]);
13 |
14 | $this->assertEquals(42, $response->total());
15 | }
16 |
17 | public function testExtractTotalFromRawJson()
18 | {
19 | $response = HalResponse::fromJson('{"total":"42"}');
20 |
21 | $this->assertEquals(42, $response->total());
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/tests/Mado/QueryBundle/Objects/MetaDataAdapterTest.php:
--------------------------------------------------------------------------------
1 | adapter = new MetaDataAdapter();
11 | }
12 |
13 | public function testProvideEntityAliasFromEntityName()
14 | {
15 | $this->adapter->setEntityName('Foo\\Bar');
16 | $this->assertEquals('b', $this->adapter->getEntityAlias());
17 | }
18 |
19 | public function testProvideEntityFieldsFromMetadata()
20 | {
21 | $metadata = new \stdClass();
22 | $metadata->fieldMappings = [
23 | 'foo' => 'fizz',
24 | 'bar' => 'buzz',
25 | ];
26 |
27 | $this->adapter->setClassMetadata($metadata);
28 | $this->assertEquals([
29 | 'foo',
30 | 'bar',
31 | ], $this->adapter->getFields());
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/tests/Mado/QueryBundle/Objects/PagerfantaBuilderTest.php:
--------------------------------------------------------------------------------
1 | getMockBuilder('Hateoas\Representation\PaginatedRepresentation')
17 | ->disableOriginalConstructor()
18 | ->getMock();
19 |
20 | $this->pagerfantaFactory = $this
21 | ->getMockBuilder('Hateoas\Representation\Factory\PagerfantaFactory')
22 | ->disableOriginalConstructor()
23 | ->getMock();
24 |
25 | $this->pagerfantaFactory
26 | ->expects($this->exactly(1))
27 | ->method('createRepresentation')
28 | ->willReturn($paginatedRepresentation);
29 |
30 | $this->ormAdapter = $this
31 | ->getMockBuilder('Pagerfanta\Adapter\DoctrineORMAdapter')
32 | ->disableOriginalConstructor()
33 | ->getMock();
34 |
35 | $this->pagerfantaBuilder = new \Mado\QueryBundle\Objects\PagerfantaBuilder(
36 | $this->pagerfantaFactory,
37 | $this->ormAdapter
38 | );
39 |
40 | $route = $this
41 | ->getMockBuilder('Hateoas\Configuration\Route')
42 | ->disableOriginalConstructor()
43 | ->getMock();
44 |
45 | $this->pagerfantaBuilder->createRepresentation($route, random_int(0, 9999), random_int(0, 9999));
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/tests/Mado/QueryBundle/Objects/QueryBuilderFactoryTest.php:
--------------------------------------------------------------------------------
1 | manager = \Doctrine\ORM\EntityManager::create(array(
14 | 'driver' => 'pdo_sqlite',
15 | 'path' => __DIR__ . '/../../data/db.sqlite',
16 | ),
17 | \Doctrine\ORM\Tools\Setup::createAnnotationMetadataConfiguration(
18 | array(__DIR__),
19 | true
20 | ));
21 | }
22 |
23 | public function testExposeEntityManager()
24 | {
25 | $queryBuilderFactory = new QueryBuilderFactory($this->manager);
26 | $this->assertSame(
27 | $this->manager,
28 | $queryBuilderFactory->getEntityManager()
29 | );
30 | }
31 |
32 | public function testProvideOneSingleResult()
33 | {
34 | $queryBuilderFactory = new QueryBuilderFactory($this->manager);
35 | $queryBuilderFactory->setFields([ 'id' ]);
36 | $queryBuilderFactory->setAndFilters([ 'id|eq' => 33 ]);
37 | $queryBuilderFactory->createQueryBuilder(MySimpleEntity::class, 'e');
38 | $queryBuilderFactory->filter();
39 |
40 | $doctrineQueryBuilder = $queryBuilderFactory->getQueryBuilder();
41 | $doctrineQueryBuilder->setMaxResults(1);
42 |
43 | $this->assertEquals(
44 | "SELECT m0_.id AS id_0 FROM MySimpleEntity m0_ WHERE m0_.id = ? LIMIT 1",
45 | $doctrineQueryBuilder->getQuery()->getSql()
46 | );
47 | }
48 |
49 | public function testSampleQueryMakedWithQueryBuilderFactory()
50 | {
51 | $queryBuilderFactory = new QueryBuilderFactory($this->manager);
52 | $queryBuilderFactory->setFields([ 'id' ]);
53 | $queryBuilderFactory->setAndFilters([ 'id|eq' => 33 ]);
54 | $queryBuilderFactory->createQueryBuilder(MySimpleEntity::class, 'e');
55 | $queryBuilderFactory->filter();
56 |
57 | $this->assertEquals(
58 | "SELECT m0_.id AS id_0 FROM MySimpleEntity m0_ WHERE m0_.id = ?",
59 | $queryBuilderFactory->getQueryBuilder()->getQuery()->getSql()
60 | );
61 |
62 | $this->assertContains(
63 | "SELECT e FROM Mado\QueryBundle\Tests\Objects\MySimpleEntity e WHERE e.id = :field_id",
64 | $queryBuilderFactory->getQueryBuilder()->getQuery()->getDql()
65 | );
66 | }
67 |
68 | public function testFilterWithListType()
69 | {
70 | $queryBuilderFactory = new QueryBuilderFactory($this->manager);
71 | $queryBuilderFactory->setFields([ 'id' ]);
72 | $queryBuilderFactory->setAndFilters([ 'id|list' => '42, 33' ]);
73 | $queryBuilderFactory->createQueryBuilder(MySimpleEntity::class, 'e');
74 | $queryBuilderFactory->filter();
75 |
76 | $this->assertEquals(
77 | "SELECT m0_.id AS id_0 FROM MySimpleEntity m0_ WHERE m0_.id IN (?)",
78 | $queryBuilderFactory->getQueryBuilder()->getQuery()->getSql()
79 | );
80 | }
81 |
82 | public function testFilterWithListTypeOnEmbeddedField()
83 | {
84 | $queryBuilderFactory = new QueryBuilderFactory($this->manager);
85 | $queryBuilderFactory->setFields([ 'id' ]);
86 | $queryBuilderFactory->setAndFilters([ '_embedded.group.id|list' => '42, 33']);
87 | $queryBuilderFactory->createQueryBuilder(User::class, 'e');
88 | $queryBuilderFactory->filter();
89 |
90 | $this->assertEquals(
91 | "SELECT "
92 | . "u0_.id AS id_0, "
93 | . "u0_.username AS username_1, "
94 | . "u0_.group_id AS group_id_2 "
95 | . "FROM User u0_ "
96 | . "INNER JOIN Group g1_ ON u0_.group_id = g1_.id "
97 | . "WHERE g1_.id IN (?)",
98 | $queryBuilderFactory->getQueryBuilder()->getQuery()->getSql()
99 | );
100 | }
101 |
102 | public function testFilterWithContainsOperator()
103 | {
104 | $queryBuilderFactory = new QueryBuilderFactory($this->manager);
105 | $queryBuilderFactory->setFields([ 'username', 'group' ]);
106 | $queryBuilderFactory->setAndFilters([ 'username|contains' => 'orar' ]);
107 | $queryBuilderFactory->createQueryBuilder(User::class, 'e');
108 | $queryBuilderFactory->filter();
109 |
110 | $this->assertEquals(
111 | "SELECT "
112 | . "u0_.id AS id_0, "
113 | . "u0_.username AS username_1, "
114 | . "u0_.group_id AS group_id_2 "
115 | . "FROM User u0_ "
116 | . "WHERE u0_.username LIKE ?",
117 | $queryBuilderFactory->getQueryBuilder()->getQuery()->getSql()
118 | );
119 | }
120 |
121 | public function testFilterWithFieldEqualityOperator()
122 | {
123 | $queryBuilderFactory = new QueryBuilderFactory($this->manager);
124 | $queryBuilderFactory->setFields([ 'username', 'group' ]);
125 | $queryBuilderFactory->setAndFilters([ 'username|field_eq' => 'group' ]);
126 | $queryBuilderFactory->createQueryBuilder(User::class, 'e');
127 | $queryBuilderFactory->filter();
128 |
129 | $this->assertEquals(
130 | "SELECT "
131 | . "u0_.id AS id_0, "
132 | . "u0_.username AS username_1, "
133 | . "u0_.group_id AS group_id_2 "
134 | . "FROM User u0_ "
135 | . "WHERE u0_.username = u0_.group_id",
136 | $queryBuilderFactory->getQueryBuilder()->getQuery()->getSql()
137 | );
138 | }
139 |
140 | public function testOneToManyQueryMakedHandly()
141 | {
142 | $queryBuilderFactory = new QueryBuilderFactory($this->manager);
143 | $queryBuilderFactory->setFields([ 'id' ]);
144 | $queryBuilderFactory->setRel([ 'group' ]);
145 | $queryBuilderFactory->setAndFilters([
146 | '_embedded.group.name|contains|1' => 'ad',
147 | '_embedded.group.name|contains|2' => 'ns',
148 | '_embedded.group.name|contains|3' => 'dm',
149 | '_embedded.group.name|contains|4' => 'mi',
150 | ]);
151 | $queryBuilderFactory->createQueryBuilder(User::class, 'e');
152 | $queryBuilderFactory->filter();
153 |
154 | $this->assertEquals(
155 | "SELECT" .
156 | " u0_.id AS id_0," .
157 | " u0_.username AS username_1," .
158 | " u0_.group_id AS group_id_2 " .
159 | "FROM User u0_ " .
160 | "INNER JOIN Group g1_ ON u0_.group_id = g1_.id " .
161 | "WHERE g1_.name LIKE ? " .
162 | "AND g1_.name LIKE ? " .
163 | "AND g1_.name LIKE ? " .
164 | "AND g1_.name LIKE ?",
165 | $queryBuilderFactory->getQueryBuilder()->getQuery()->getSql()
166 | );
167 | }
168 |
169 | public function testFiltersMustContainsAlsoFieldEquality()
170 | {
171 | $factory = new QueryBuilderFactory($this->manager);
172 |
173 | $validFilters = [
174 | 'eq',
175 | 'neq',
176 | 'gt',
177 | 'gte',
178 | 'lt',
179 | 'lte',
180 | 'startswith',
181 | 'contains',
182 | 'notcontains',
183 | 'endswith',
184 | 'list',
185 | 'nlist',
186 | 'field_eq',
187 | 'isnull',
188 | 'isnotnull',
189 | 'listcontains',
190 | ];
191 |
192 | $this->assertEquals(
193 | $validFilters,
194 | $factory->getAvailableFilters()
195 | );
196 | }
197 |
198 | public function testGetFields()
199 | {
200 | $fields = ['id'];
201 | $queryBuilderFactory = new QueryBuilderFactory($this->manager);
202 | $queryBuilderFactory->setFields($fields);
203 | $fieldsReturned = $queryBuilderFactory->getFields();
204 |
205 | $this->assertEquals($fields, $fieldsReturned);
206 | }
207 |
208 | /**
209 | * @expectedException \RuntimeException
210 | */
211 | public function testGetFieldsThrowExceptionIfNull()
212 | {
213 | $queryBuilderFactory = new QueryBuilderFactory($this->manager);
214 | $queryBuilderFactory->getFields();
215 | }
216 |
217 | public function testSetOrFilters()
218 | {
219 | $filters = ['id'];
220 | $queryBuilderFactory = new QueryBuilderFactory($this->manager);
221 | $queryBuilderFactory->setOrFilters($filters);
222 |
223 | $this->assertAttributeEquals($filters, 'orFilters', $queryBuilderFactory);
224 | }
225 |
226 | public function testGetOrFilters()
227 | {
228 | $filters = ['id'];
229 | $queryBuilderFactory = new QueryBuilderFactory($this->manager);
230 | $queryBuilderFactory->setOrFilters($filters);
231 | $fieldsReturned = $queryBuilderFactory->getOrFilters();
232 |
233 | $this->assertEquals($filters, $fieldsReturned);
234 | }
235 |
236 | public function testSetSorting()
237 | {
238 | $sorting = ['id'];
239 | $queryBuilderFactory = new QueryBuilderFactory($this->manager);
240 | $queryBuilderFactory->setSorting($sorting);
241 |
242 | $this->assertAttributeEquals($sorting, 'sorting', $queryBuilderFactory);
243 | }
244 |
245 | public function testGetFilters()
246 | {
247 | $filters = ['id'];
248 | $queryBuilderFactory = new QueryBuilderFactory($this->manager);
249 | $queryBuilderFactory->setAndFilters($filters);
250 | $fieldsReturned = $queryBuilderFactory->getAndFilters();
251 |
252 | $this->assertEquals($filters, $fieldsReturned);
253 | }
254 |
255 | /**
256 | * @expectedException Mado\QueryBundle\Component\Meta\Exceptions\UnInitializedQueryBuilderException
257 | */
258 | public function testGetQueryBuilderThrowExceptionIfNull()
259 | {
260 | $queryBuilderFactory = new QueryBuilderFactory($this->manager);
261 | $queryBuilderFactory->getQueryBuilder();
262 | }
263 |
264 | public function testGetRel()
265 | {
266 | $rel = 'foo';
267 | $queryBuilderFactory = new QueryBuilderFactory($this->manager);
268 | $queryBuilderFactory->setRel([$rel]);
269 | $relReturned = $queryBuilderFactory->getRel();
270 |
271 | $this->assertEquals([$rel], $relReturned);
272 | }
273 |
274 | public function testSetPrinting()
275 | {
276 | $print = 'foo';
277 | $queryBuilderFactory = new QueryBuilderFactory($this->manager);
278 | $queryBuilderFactory->setPrinting($print);
279 |
280 | $this->assertAttributeEquals($print, 'printing', $queryBuilderFactory);
281 | }
282 |
283 | public function testGetPrinting()
284 | {
285 | $print = 'foo';
286 | $queryBuilderFactory = new QueryBuilderFactory($this->manager);
287 | $queryBuilderFactory->setPrinting($print);
288 | $printReturned = $queryBuilderFactory->getPrinting();
289 |
290 | $this->assertEquals($print, $printReturned);
291 | }
292 |
293 | public function testSetPage()
294 | {
295 | $page = 100;
296 | $queryBuilderFactory = new QueryBuilderFactory($this->manager);
297 | $queryBuilderFactory->setPage($page);
298 |
299 | $this->assertAttributeEquals($page, 'page', $queryBuilderFactory);
300 | }
301 |
302 | public function testGetPage()
303 | {
304 | $page = 100;
305 | $queryBuilderFactory = new QueryBuilderFactory($this->manager);
306 | $queryBuilderFactory->setPage($page);
307 | $pageReturned = $queryBuilderFactory->getPage();
308 |
309 | $this->assertEquals($page, $pageReturned);
310 | }
311 |
312 | public function testSetPageLength()
313 | {
314 | $pageLength = 100;
315 | $queryBuilderFactory = new QueryBuilderFactory($this->manager);
316 | $queryBuilderFactory->setPageLength($pageLength);
317 |
318 | $this->assertAttributeEquals($pageLength, 'pageLength', $queryBuilderFactory);
319 | }
320 |
321 | public function testGetPageLength()
322 | {
323 | $pageLength = 100;
324 | $queryBuilderFactory = new QueryBuilderFactory($this->manager);
325 | $queryBuilderFactory->setPageLength($pageLength);
326 | $pageLengthReturned = $queryBuilderFactory->getPageLength();
327 |
328 | $this->assertEquals($pageLength, $pageLengthReturned);
329 | }
330 |
331 | public function testSetSelect()
332 | {
333 | $select = 'foo';
334 | $queryBuilderFactory = new QueryBuilderFactory($this->manager);
335 | $queryBuilderFactory->setSelect($select);
336 |
337 | $this->assertAttributeEquals($select, 'select', $queryBuilderFactory);
338 | }
339 |
340 | public function testGetSelect()
341 | {
342 | $select = 'foo';
343 | $queryBuilderFactory = new QueryBuilderFactory($this->manager);
344 | $queryBuilderFactory->setSelect($select);
345 | $selectReturned = $queryBuilderFactory->getSelect();
346 |
347 | $this->assertEquals($select, $selectReturned);
348 | }
349 |
350 | public function testListOnEmbeddedOrFilter()
351 | {
352 | $queryBuilderFactory = new QueryBuilderFactory($this->manager);
353 | $queryBuilderFactory->setFields([ 'id' ]);
354 | $queryBuilderFactory->setRel([ 'group' ]);
355 | $queryBuilderFactory->setOrFilters([
356 | '_embedded.group.id|list' => '1,2,3',
357 | ]);
358 | $queryBuilderFactory->createQueryBuilder(User::class, 'e');
359 | $queryBuilderFactory->filter();
360 |
361 | $this->assertEquals(
362 | "SELECT "
363 | . "u0_.id AS id_0, "
364 | . "u0_.username AS username_1, "
365 | . "u0_.group_id AS group_id_2 "
366 | . "FROM User u0_ "
367 | . "LEFT JOIN Group g1_ ON u0_.group_id = g1_.id "
368 | . "WHERE g1_.id IN (?)",
369 | $queryBuilderFactory->getQueryBuilder()->getQuery()->getSql()
370 | );
371 | }
372 |
373 | public function testFieldsArentInEntity()
374 | {
375 | $queryBuilderFactory = new QueryBuilderFactory($this->manager);
376 | $queryBuilderFactory->setFields([ 'id' ]);
377 | $queryBuilderFactory->setRel([ 'group' ]);
378 | $queryBuilderFactory->setOrFilters([
379 | 'id|list' => '1,2,3',
380 | ]);
381 | $queryBuilderFactory->createQueryBuilder(User::class, 'e');
382 | $queryBuilderFactory->filter();
383 |
384 | $this->assertEquals(
385 | "SELECT" .
386 | " u0_.id AS id_0," .
387 | " u0_.username AS username_1," .
388 | " u0_.group_id AS group_id_2 " .
389 | "FROM User u0_ " .
390 | "WHERE u0_.id IN (?)",
391 | $queryBuilderFactory->getQueryBuilder()->getQuery()->getSql()
392 | );
393 | }
394 |
395 | public function testCheckFieldsEqualitiWithOrOperator()
396 | {
397 | $queryBuilderFactory = new QueryBuilderFactory($this->manager);
398 | $queryBuilderFactory->setFields([ 'username', 'group' ]);
399 | $queryBuilderFactory->setOrFilters([ 'username|field_eq' => 'group' ]);
400 | $queryBuilderFactory->createQueryBuilder(User::class, 'e');
401 | $queryBuilderFactory->filter();
402 |
403 | $this->assertEquals(
404 | "SELECT "
405 | . "u0_.id AS id_0, "
406 | . "u0_.username AS username_1, "
407 | . "u0_.group_id AS group_id_2 "
408 | . "FROM User u0_ "
409 | . "WHERE u0_.username = u0_.group_id",
410 | $queryBuilderFactory->getQueryBuilder()->getQuery()->getSql()
411 | );
412 | }
413 |
414 | public function testCheckFieldsGreaterThan()
415 | {
416 | $queryBuilderFactory = new QueryBuilderFactory($this->manager);
417 | $queryBuilderFactory->setFields([ 'id', 'group' ]);
418 | $queryBuilderFactory->setOrFilters([ 'id|gte' => '42' ]);
419 | $queryBuilderFactory->createQueryBuilder(User::class, 'e');
420 | $queryBuilderFactory->filter();
421 |
422 | $this->assertEquals(
423 | "SELECT "
424 | . "u0_.id AS id_0, "
425 | . "u0_.username AS username_1, "
426 | . "u0_.group_id AS group_id_2 "
427 | . "FROM User u0_ "
428 | . "WHERE u0_.id >= ?",
429 | $queryBuilderFactory->getQueryBuilder()->getQuery()->getSql()
430 | );
431 | }
432 |
433 | public function testFilteringOrWithContains()
434 | {
435 | $queryBuilderFactory = new QueryBuilderFactory($this->manager);
436 | $queryBuilderFactory->setFields([ 'username', 'group' ]);
437 | $queryBuilderFactory->setOrFilters([ 'username|contains' => 'sorar' ]);
438 | $queryBuilderFactory->createQueryBuilder(User::class, 'e');
439 | $queryBuilderFactory->filter();
440 |
441 | $this->assertEquals(
442 | "SELECT "
443 | . "u0_.id AS id_0, "
444 | . "u0_.username AS username_1, "
445 | . "u0_.group_id AS group_id_2 "
446 | . "FROM User u0_ "
447 | . "WHERE u0_.username LIKE ?",
448 | $queryBuilderFactory->getQueryBuilder()->getQuery()->getSql()
449 | );
450 | }
451 |
452 | public function testCanBuildQueriesUsingOrOperator()
453 | {
454 | $queryBuilderFactory = new QueryBuilderFactory($this->manager);
455 | $queryBuilderFactory->setFields([ 'id' ]);
456 | $queryBuilderFactory->setRel([ 'group' ]);
457 | $queryBuilderFactory->setOrFilters([
458 | '_embedded.group.name|contains|1' => 'ad',
459 | '_embedded.group.description|contains|1' => 'ns',
460 | '_embedded.group.name|contains|2' => 'dm',
461 | '_embedded.group.description|contains|2' => 'mi',
462 | ]);
463 | $queryBuilderFactory->createQueryBuilder(User::class, 'e');
464 | $queryBuilderFactory->filter();
465 |
466 | $this->assertEquals(
467 | "SELECT" .
468 | " u0_.id AS id_0," .
469 | " u0_.username AS username_1," .
470 | " u0_.group_id AS group_id_2 " .
471 | "FROM User u0_ " .
472 | "LEFT JOIN Group g1_ ON u0_.group_id = g1_.id " .
473 | "WHERE (g1_.name LIKE ? OR g1_.description LIKE ?) AND " .
474 | "(g1_.name LIKE ? OR g1_.description LIKE ?)",
475 | $queryBuilderFactory->getQueryBuilder()->getQuery()->getSql()
476 | );
477 | }
478 |
479 | /** @expectedException \Mado\QueryBundle\Exceptions\MissingFiltersException */
480 | public function testThrowMissingFiltersExceptionsWheneverFiltersAreMissing()
481 | {
482 | $queryBuilderFactory = new QueryBuilderFactory($this->manager);
483 | $queryBuilderFactory->filter();
484 | }
485 |
486 | /** @expectedException \Mado\QueryBundle\Exceptions\MissingFieldsException */
487 | public function testThrowExceptionWheneverFieldsWereNotDefined()
488 | {
489 | $queryBuilderFactory = new QueryBuilderFactory($this->manager);
490 | $queryBuilderFactory->setAndFilters([ 'foo|eq' => 'bar' ]);
491 | $queryBuilderFactory->filter();
492 | }
493 |
494 | /**
495 | * @expectedException \RuntimeException
496 | * @expectedExceptionMessage Oops! Fields are not defined
497 | */
498 | public function testCantSortWithoutFields()
499 | {
500 | $queryBuilderFactory = new QueryBuilderFactory($this->manager);
501 | $queryBuilderFactory->sort();
502 | }
503 |
504 | /**
505 | * @expectedException \RuntimeException
506 | * @expectedExceptionMessage Oops! Sorting is not defined
507 | */
508 | public function testThrowExceptionWheneverSortIsRequestedWithoutSorting()
509 | {
510 | $queryBuilderFactory = new QueryBuilderFactory($this->manager);
511 | $queryBuilderFactory->setFields(['foo', 'bar']);
512 | $queryBuilderFactory->sort();
513 | }
514 |
515 | /**
516 | * @expectedException \RuntimeException
517 | * @expectedExceptionMessage Oops! QueryBuilder was never initialized
518 | */
519 | public function testThrowExceptionWhenQueryBuilderIsNotInitialized()
520 | {
521 | $queryBuilderFactory = new QueryBuilderFactory($this->manager);
522 | $queryBuilderFactory->setFields(['foo', 'bar']);
523 | $queryBuilderFactory->setSorting(['foo' => 'bar']);
524 | $queryBuilderFactory->sort();
525 | }
526 |
527 | public function testApplySortingJustForEntityFields()
528 | {
529 | $this->queryBuilder = $this
530 | ->getMockBuilder('Doctrine\ORM\QueryBuilder')
531 | ->disableOriginalConstructor()
532 | ->getMock();
533 | $this->queryBuilder->expects($this->once())
534 | ->method('select')
535 | ->with('alias')
536 | ->willReturn($this->queryBuilder);
537 | $this->queryBuilder->expects($this->once())
538 | ->method('from')
539 | ->with('EntityName')
540 | ->willReturn($this->queryBuilder);
541 |
542 | $this->manager = $this
543 | ->getMockBuilder('Doctrine\ORM\EntityManager')
544 | ->disableOriginalConstructor()
545 | ->getMock();
546 | $this->manager->expects($this->once())
547 | ->method('createQueryBuilder')
548 | ->willReturn($this->queryBuilder);
549 |
550 | $queryBuilderFactory = new QueryBuilderFactory($this->manager);
551 | $queryBuilderFactory->setFields(['foo', 'bar']);
552 | $queryBuilderFactory->setSorting(['foo' => 'bar']);
553 | $queryBuilderFactory->createQueryBuilder('EntityName', 'alias');
554 | $queryBuilderFactory->sort();
555 | }
556 |
557 | public function testApplySortingAlsoOnRelationsField()
558 | {
559 | $this->queryBuilder = $this
560 | ->getMockBuilder('Doctrine\ORM\QueryBuilder')
561 | ->disableOriginalConstructor()
562 | ->getMock();
563 | $this->queryBuilder->expects($this->once())
564 | ->method('select')
565 | ->with('alias')
566 | ->willReturn($this->queryBuilder);
567 | $this->queryBuilder->expects($this->once())
568 | ->method('from')
569 | ->with('EntityName')
570 | ->willReturn($this->queryBuilder);
571 | $this->queryBuilder->expects($this->once())
572 | ->method('innerJoin')
573 | ->with('alias.ciao', 'table_fizz');
574 |
575 | $this->metadata = $this
576 | ->getMockBuilder('Doctrine\ORM\Mapping\ClassMetadata')
577 | ->disableOriginalConstructor()
578 | ->getMock();
579 | $this->metadata->expects($this->once())
580 | ->method('hasAssociation')
581 | ->with('fizz')
582 | ->willReturn(true);
583 | $this->metadata->expects($this->once())
584 | ->method('getAssociationMapping')
585 | ->with('fizz')
586 | ->willReturn([
587 | 'fieldName' => 'ciao',
588 | 'targetEntity' => 'someEntityName',
589 | ]);
590 |
591 | $this->manager = $this
592 | ->getMockBuilder('Doctrine\ORM\EntityManager')
593 | ->disableOriginalConstructor()
594 | ->getMock();
595 | $this->manager->expects($this->once())
596 | ->method('createQueryBuilder')
597 | ->willReturn($this->queryBuilder);
598 | $this->manager->expects($this->once())
599 | ->method('getClassMetadata')
600 | ->with('EntityName')
601 | ->willReturn($this->metadata);
602 |
603 | $queryBuilderFactory = new QueryBuilderFactory($this->manager);
604 | $queryBuilderFactory->setFields(['foo', 'bar']);
605 | $queryBuilderFactory->setSorting(['_embedded.fizz.buzz' => 'bar']);
606 | $queryBuilderFactory->createQueryBuilder('EntityName', 'alias');
607 | $queryBuilderFactory->sort();
608 | }
609 |
610 | public function testGetAvailableFilters()
611 | {
612 | $queryBuilderFactory = new QueryBuilderFactory($this->manager);
613 |
614 | $expectedFilters = Dictionary::getOperators();
615 |
616 | $availableFilters = $queryBuilderFactory->getValueAvailableFilters();
617 |
618 | $this->assertEquals($expectedFilters, $availableFilters);
619 | }
620 |
621 | public function testAcceptRelationsToAdd()
622 | {
623 | $queryBuilderFactory = new QueryBuilderFactory($this->manager);
624 | $queryBuilderFactory->setFields([ 'id' ]);
625 | $queryBuilderFactory->setRel([ 'group' ]);
626 | $queryBuilderFactory->addRel('foo');
627 |
628 | $this->assertEquals(
629 | ['group', 'foo'],
630 | $queryBuilderFactory->getRel()
631 | );
632 | }
633 |
634 | public function testAndFilterUseInnerJoin()
635 | {
636 | $expectJoinType = 'innerJoin';
637 |
638 | $this->queryBuilder = $this
639 | ->getMockBuilder('Doctrine\ORM\QueryBuilder')
640 | ->disableOriginalConstructor()
641 | ->getMock();
642 | $this->queryBuilder
643 | ->method('select')
644 | ->willReturn($this->queryBuilder);
645 | $this->queryBuilder
646 | ->method('from')
647 | ->willReturn($this->queryBuilder);
648 | $this->queryBuilder->expects($this->once())
649 | ->method($expectJoinType)
650 | ->with('alias.baz', 'table_foo');
651 |
652 | $this->prepareDataForFilter();
653 |
654 | $queryBuilderFactory = new QueryBuilderFactory($this->manager);
655 | $queryBuilderFactory->setFields([ 'id' ]);
656 | $queryBuilderFactory->createQueryBuilder('EntityName', 'alias');
657 | $queryBuilderFactory->setAndFilters([ '_embedded.foo.baz|eq' => 'bar' ]);
658 | $queryBuilderFactory->filter();
659 | }
660 |
661 | public function testOrFilterUseLeftJoin()
662 | {
663 | $expectJoinType = 'leftJoin';
664 |
665 | $this->queryBuilder = $this
666 | ->getMockBuilder('Doctrine\ORM\QueryBuilder')
667 | ->disableOriginalConstructor()
668 | ->getMock();
669 | $this->queryBuilder
670 | ->method('select')
671 | ->willReturn($this->queryBuilder);
672 | $this->queryBuilder
673 | ->method('from')
674 | ->willReturn($this->queryBuilder);
675 | $this->queryBuilder->expects($this->once())
676 | ->method($expectJoinType)
677 | ->with('alias.baz', 'table_foo');
678 |
679 | $this->prepareDataForFilter();
680 |
681 | $queryBuilderFactory = new QueryBuilderFactory($this->manager);
682 | $queryBuilderFactory->setFields([ 'id' ]);
683 | $queryBuilderFactory->createQueryBuilder('EntityName', 'alias');
684 | $queryBuilderFactory->setOrFilters([ '_embedded.foo.baz|eq' => 'bar' ]);
685 | $queryBuilderFactory->filter();
686 | }
687 |
688 | private function prepareDataForFilter()
689 | {
690 | $this->metadata = $this
691 | ->getMockBuilder('Doctrine\ORM\Mapping\ClassMetadata')
692 | ->disableOriginalConstructor()
693 | ->getMock();
694 | $this->metadata
695 | ->method('hasAssociation')
696 | ->with('foo')
697 | ->willReturn(true);
698 | $this->metadata
699 | ->method('getAssociationMapping')
700 | ->with('foo')
701 | ->willReturn([
702 | 'fieldName' => 'baz',
703 | 'targetEntity' => 'someEntityName',
704 | ]);
705 |
706 | $this->manager = $this
707 | ->getMockBuilder('Doctrine\ORM\EntityManager')
708 | ->disableOriginalConstructor()
709 | ->getMock();
710 | $this->manager
711 | ->method('createQueryBuilder')
712 | ->willReturn($this->queryBuilder);
713 | $this->manager
714 | ->method('getClassMetadata')
715 | ->with('EntityName')
716 | ->willReturn($this->metadata);
717 | }
718 |
719 | public function testFilteringWithIsNull()
720 | {
721 | $queryBuilderFactory = new QueryBuilderFactory($this->manager);
722 | $queryBuilderFactory->setFields([ 'username', 'group' ]);
723 | $queryBuilderFactory->setAndFilters([ 'username|isnull' => '' ]);
724 | $queryBuilderFactory->createQueryBuilder(User::class, 'e');
725 | $queryBuilderFactory->filter();
726 |
727 | $this->assertEquals(
728 | "SELECT "
729 | . "u0_.id AS id_0, "
730 | . "u0_.username AS username_1, "
731 | . "u0_.group_id AS group_id_2 "
732 | . "FROM User u0_ "
733 | . "WHERE u0_.username IS NULL",
734 | $queryBuilderFactory->getQueryBuilder()->getQuery()->getSql()
735 | );
736 | }
737 |
738 | public function testFilteringOrWithIsNull()
739 | {
740 | $queryBuilderFactory = new QueryBuilderFactory($this->manager);
741 | $queryBuilderFactory->setFields([ 'username', 'group' ]);
742 | $queryBuilderFactory->setOrFilters([ 'username|isnull' => '' ]);
743 | $queryBuilderFactory->createQueryBuilder(User::class, 'e');
744 | $queryBuilderFactory->filter();
745 |
746 | $this->assertEquals(
747 | "SELECT "
748 | . "u0_.id AS id_0, "
749 | . "u0_.username AS username_1, "
750 | . "u0_.group_id AS group_id_2 "
751 | . "FROM User u0_ "
752 | . "WHERE u0_.username IS NULL",
753 | $queryBuilderFactory->getQueryBuilder()->getQuery()->getSql()
754 | );
755 | }
756 |
757 | public function testFilteringAndWithIsNullIntoEmbedded()
758 | {
759 | $queryBuilderFactory = new QueryBuilderFactory($this->manager);
760 | $queryBuilderFactory->setFields([ 'id' ]);
761 | $queryBuilderFactory->setRel([ 'group' ]);
762 | $queryBuilderFactory->setAndFilters([
763 | '_embedded.group.name|isnull' => ''
764 | ]);
765 | $queryBuilderFactory->createQueryBuilder(User::class, 'e');
766 | $queryBuilderFactory->filter();
767 |
768 | $this->assertEquals(
769 | "SELECT" .
770 | " u0_.id AS id_0," .
771 | " u0_.username AS username_1," .
772 | " u0_.group_id AS group_id_2 " .
773 | "FROM User u0_ " .
774 | "INNER JOIN Group g1_ ON u0_.group_id = g1_.id " .
775 | "WHERE g1_.name IS NULL",
776 | $queryBuilderFactory->getQueryBuilder()->getQuery()->getSql()
777 | );
778 | }
779 |
780 | public function testFilteringOrWithIsNullIntoEmbedded()
781 | {
782 | $queryBuilderFactory = new QueryBuilderFactory($this->manager);
783 | $queryBuilderFactory->setFields([ 'id' ]);
784 | $queryBuilderFactory->setRel([ 'group' ]);
785 | $queryBuilderFactory->setOrFilters([
786 | '_embedded.group.name|isnull' => ''
787 | ]);
788 | $queryBuilderFactory->createQueryBuilder(User::class, 'e');
789 | $queryBuilderFactory->filter();
790 |
791 | $this->assertEquals(
792 | "SELECT" .
793 | " u0_.id AS id_0," .
794 | " u0_.username AS username_1," .
795 | " u0_.group_id AS group_id_2 " .
796 | "FROM User u0_ " .
797 | "LEFT JOIN Group g1_ ON u0_.group_id = g1_.id " .
798 | "WHERE g1_.name IS NULL",
799 | $queryBuilderFactory->getQueryBuilder()->getQuery()->getSql()
800 | );
801 | }
802 |
803 | public function testFilteringWithIsNotNull()
804 | {
805 | $queryBuilderFactory = new QueryBuilderFactory($this->manager);
806 | $queryBuilderFactory->setFields([ 'username', 'group' ]);
807 | $queryBuilderFactory->setAndFilters([ 'username|isnotnull' => '' ]);
808 | $queryBuilderFactory->createQueryBuilder(User::class, 'e');
809 | $queryBuilderFactory->filter();
810 |
811 | $this->assertEquals(
812 | "SELECT "
813 | . "u0_.id AS id_0, "
814 | . "u0_.username AS username_1, "
815 | . "u0_.group_id AS group_id_2 "
816 | . "FROM User u0_ "
817 | . "WHERE u0_.username IS NOT NULL",
818 | $queryBuilderFactory->getQueryBuilder()->getQuery()->getSql()
819 | );
820 | }
821 |
822 | public function testFilteringOrWithIsNotNull()
823 | {
824 | $queryBuilderFactory = new QueryBuilderFactory($this->manager);
825 | $queryBuilderFactory->setFields([ 'username', 'group' ]);
826 | $queryBuilderFactory->setOrFilters([ 'username|isnotnull' => '' ]);
827 | $queryBuilderFactory->createQueryBuilder(User::class, 'e');
828 | $queryBuilderFactory->filter();
829 |
830 | $this->assertEquals(
831 | "SELECT "
832 | . "u0_.id AS id_0, "
833 | . "u0_.username AS username_1, "
834 | . "u0_.group_id AS group_id_2 "
835 | . "FROM User u0_ "
836 | . "WHERE u0_.username IS NOT NULL",
837 | $queryBuilderFactory->getQueryBuilder()->getQuery()->getSql()
838 | );
839 | }
840 |
841 | public function testFilteringAndWithIsNotNullIntoEmbedded()
842 | {
843 | $queryBuilderFactory = new QueryBuilderFactory($this->manager);
844 | $queryBuilderFactory->setFields([ 'id' ]);
845 | $queryBuilderFactory->setRel([ 'group' ]);
846 | $queryBuilderFactory->setAndFilters([
847 | '_embedded.group.name|isnotnull' => ''
848 | ]);
849 | $queryBuilderFactory->createQueryBuilder(User::class, 'e');
850 | $queryBuilderFactory->filter();
851 |
852 | $this->assertEquals(
853 | "SELECT" .
854 | " u0_.id AS id_0," .
855 | " u0_.username AS username_1," .
856 | " u0_.group_id AS group_id_2 " .
857 | "FROM User u0_ " .
858 | "INNER JOIN Group g1_ ON u0_.group_id = g1_.id " .
859 | "WHERE g1_.name IS NOT NULL",
860 | $queryBuilderFactory->getQueryBuilder()->getQuery()->getSql()
861 | );
862 | }
863 |
864 | public function testFilteringOrWithIsNotNullIntoEmbedded()
865 | {
866 | $queryBuilderFactory = new QueryBuilderFactory($this->manager);
867 | $queryBuilderFactory->setFields([ 'id' ]);
868 | $queryBuilderFactory->setRel([ 'group' ]);
869 | $queryBuilderFactory->setOrFilters([
870 | '_embedded.group.name|isnotnull' => ''
871 | ]);
872 | $queryBuilderFactory->createQueryBuilder(User::class, 'e');
873 | $queryBuilderFactory->filter();
874 |
875 | $this->assertEquals(
876 | "SELECT" .
877 | " u0_.id AS id_0," .
878 | " u0_.username AS username_1," .
879 | " u0_.group_id AS group_id_2 " .
880 | "FROM User u0_ " .
881 | "LEFT JOIN Group g1_ ON u0_.group_id = g1_.id " .
882 | "WHERE g1_.name IS NOT NULL",
883 | $queryBuilderFactory->getQueryBuilder()->getQuery()->getSql()
884 | );
885 | }
886 |
887 | public function testFilteringListContains()
888 | {
889 | $queryBuilderFactory = new QueryBuilderFactory($this->manager);
890 | $queryBuilderFactory->setFields([ 'id', 'username' ]);
891 | $queryBuilderFactory->setRel([ 'group' ]);
892 | $queryBuilderFactory->setAndFilters([
893 | 'username|listcontains' => 'a,b',
894 | '_embedded.group.name|listcontains' => 'c,d'
895 | ]);
896 | $queryBuilderFactory->createQueryBuilder(User::class, 'e');
897 | $queryBuilderFactory->filter();
898 |
899 | $this->assertEquals(
900 | "SELECT u0_.id AS id_0, u0_.username AS username_1, u0_.group_id AS group_id_2" .
901 | " FROM User u0_" .
902 | " INNER JOIN Group g1_ ON u0_.group_id = g1_.id " .
903 | "WHERE ((u0_.username LIKE ? OR u0_.username LIKE ?)) " .
904 | "AND ((g1_.name LIKE ? OR g1_.name LIKE ?))",
905 | $queryBuilderFactory->getQueryBuilder()->getQuery()->getSql()
906 | );
907 | }
908 |
909 | public function testSortingIntoTwoLevelsEmbedded()
910 | {
911 | $queryBuilderFactory = new QueryBuilderFactory($this->manager);
912 | $queryBuilderFactory->setFields([ 'id' ]);
913 | $queryBuilderFactory->setRel([ 'group', 'company' ]);
914 | $queryBuilderFactory->setSorting([
915 | '_embedded.group.company.id' => 'asc'
916 | ]);
917 | $queryBuilderFactory->createQueryBuilder(User::class, 'e');
918 | $queryBuilderFactory->sort();
919 |
920 | $this->assertEquals(
921 | "SELECT" .
922 | " u0_.id AS id_0," .
923 | " u0_.username AS username_1," .
924 | " u0_.group_id AS group_id_2 " .
925 | "FROM User u0_ " .
926 | "INNER JOIN Group g1_ ON u0_.group_id = g1_.id " .
927 | "INNER JOIN Company c2_ ON g1_.company_id = c2_.id " .
928 | "ORDER BY c2_.id ASC",
929 | $queryBuilderFactory->getQueryBuilder()->getQuery()->getSql()
930 | );
931 | }
932 | }
933 |
934 | /** @Entity() */
935 | class MySimpleEntity
936 | {
937 | /** @Id @Column(type="integer") */
938 | private $id;
939 | }
940 |
941 | /** @Entity() */
942 | class User
943 | {
944 | /** @Id @Column(type="integer") */
945 | private $id;
946 | /** @Column(type="string") */
947 | private $username;
948 | /** @ManyToOne(targetEntity="Group", inversedBy="member") */
949 | private $group;
950 | }
951 |
952 | /** @Entity() */
953 | class Group
954 | {
955 | /** @Id @Column(type="integer") */
956 | private $id;
957 | /** @Column(type="string") */
958 | private $name;
959 | /** @Column(type="string") */
960 | private $description;
961 | /** @OneToMany(targetEntity="User", mappedBy="member") */
962 | private $members;
963 | /** @ManyToOne(targetEntity="Company", inversedBy="groups") */
964 | private $company;
965 | }
966 |
967 | /** @Entity() */
968 | class Company
969 | {
970 | /** @Id @Column(type="integer") */
971 | private $id;
972 | /** @Column(type="string") */
973 | private $name;
974 | /** @OneToMany(targetEntity="Group", mappedBy="company") */
975 | private $group;
976 | }
977 |
--------------------------------------------------------------------------------
/tests/Mado/QueryBundle/Objects/QueryBuilderOptionsTest.php:
--------------------------------------------------------------------------------
1 | 'andFilterValue',
14 | 'orFilters' => 'orFiltersValue',
15 | 'sorting' => 'asc',
16 | 'rel' => 'azione',
17 | 'printing' => 'pppp',
18 | 'select' => 'a,b,c',
19 | ]);
20 |
21 | $this->assertEquals('andFilterValue', $op->getAndFilters());
22 | $this->assertEquals('orFiltersValue', $op->getOrFilters());
23 | $this->assertEquals('asc', $op->getSorting());
24 | $this->assertEquals('azione', $op->getRel());
25 | $this->assertEquals('pppp', $op->getPrinting());
26 | $this->assertEquals('a,b,c', $op->getSelect());
27 |
28 | $this->assertEquals(
29 | $op->get('filters'),
30 | $op->getAndFilters()
31 | );
32 |
33 | $this->assertNull($op->get('fake'));
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/tests/Mado/QueryBundle/Objects/ValueTest.php:
--------------------------------------------------------------------------------
1 | getFilter();
15 |
16 | $this->assertEquals('foo', $filter);
17 | }
18 |
19 | public function testCamesFromQuerystringWheneverIsComposedByAString()
20 | {
21 | $value = Value::fromFilter('foo');
22 |
23 | $this->assertSame(true, $value->camesFromQueryString());
24 | }
25 |
26 | public function testCamesFromAdditionalFiltersWheneverComposedByAnArray()
27 | {
28 | $value = Value::fromFilter(['op' => [1, 2, 3]]);
29 |
30 | $this->assertSame(false, $value->camesFromQueryString());
31 | }
32 |
33 | public function testDetectOperator()
34 | {
35 | $value = Value::fromFilter(['op' => [1, 2, 3]]);
36 |
37 | $this->assertEquals('op', $value->getOperator());
38 | }
39 |
40 | public function testDetectIds()
41 | {
42 | $value = Value::fromFilter(['op' => [1, 2, 3]]);
43 |
44 | $this->assertEquals([1, 2, 3], $value->getValues());
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/tests/Mado/QueryBundle/Queries/Objects/FilterObjectTest.php:
--------------------------------------------------------------------------------
1 | getOperator();
15 | $this->assertEquals('bar', $operator);
16 | }
17 |
18 | public function testWheneverOperatorIsntDefinedUseDefaultOperator()
19 | {
20 | $filter = FilterObject::fromRawFilter('foo');
21 | $operator = $filter->getOperator();
22 | $this->assertEquals(Dictionary::DEFAULT_OPERATOR, $operator);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/tests/Mado/QueryBundle/Queries/Objects/QueryOptionsBuilderTest.php:
--------------------------------------------------------------------------------
1 | builder = new QueryOptionsBuilder();
12 | $this->builder->setEntityAlias($alias = 'asdf');
13 | $this->assertEquals(
14 | $alias,
15 | $this->builder->getEntityAlias()
16 | );
17 | }
18 |
19 | /** @expectedException \RuntimeException */
20 | public function testRequireEntityAliasDefinition()
21 | {
22 | $this->builder = new QueryOptionsBuilder();
23 | $this->builder->ensureEntityAliasIsDefined();
24 | }
25 |
26 | public function testShouldBuildOptionsFromEmtpyRequest()
27 | {
28 | $this->request = $this
29 | ->getMockBuilder('Symfony\Component\HttpFoundation\Request')
30 | ->disableOriginalConstructor()
31 | ->getMock();
32 | $this->request->attributes = $this
33 | ->getMockBuilder('Symfony\Component\HttpFoundation\ParameterBag')
34 | ->disableOriginalConstructor()
35 | ->getMock();
36 | $this->request->attributes->expects($this->once())
37 | ->method('all')
38 | ->willReturn([]);
39 | $this->request->query = $this
40 | ->getMockBuilder('Symfony\Component\HttpFoundation\ParameterBag')
41 | ->disableOriginalConstructor()
42 | ->getMock();
43 |
44 | $this->request->query->expects($this->at(0))->method('get')->with('filtering', [])->willReturn([]);
45 | $this->request->query->expects($this->at(1))->method('get')->with('filtering_or', [])->willReturn([]);
46 | $this->request->query->expects($this->at(2))->method('get')->with('sorting', [])->willReturn([]);
47 | $this->request->query->expects($this->at(3))->method('get')->with('printing', [])->willReturn([]);
48 | $this->request->query->expects($this->at(4))->method('get')->with('rel', '')->willReturn([]);
49 | $this->request->query->expects($this->at(5))->method('get')->with('page', '')->willReturn([]);
50 | $this->request->query->expects($this->at(6))->method('get')->with('select', 'asdf')->willReturn([]);
51 | $this->request->query->expects($this->at(7))->method('get')->with('filtering', '')->willReturn([]);
52 | $this->request->query->expects($this->at(8))->method('get')->with('limit', '')->willReturn([]);
53 |
54 | $this->builder = new QueryOptionsBuilder();
55 | $this->builder->setEntityAlias($alias = 'asdf');
56 | $options = $this->builder->fromRequest($this->request);
57 |
58 | $this->assertEquals(
59 | QueryBuilderOptions::fromArray([
60 | 'filtering' => [],
61 | 'orFilters' => [],
62 | 'limit' => [],
63 | 'page' => [],
64 | 'filters' => [],
65 | 'orFiltering' => [],
66 | 'sorting' => [],
67 | 'rel' => [],
68 | 'printing' => [],
69 | 'select' => [],
70 | ]),
71 | $options
72 | );
73 | }
74 |
75 | public function testFilteringOrIsConvertedInBothOriltersAndOrfiltering()
76 | {
77 | $this->request = $this
78 | ->getMockBuilder('Symfony\Component\HttpFoundation\Request')
79 | ->disableOriginalConstructor()
80 | ->getMock();
81 | $this->request->attributes = $this
82 | ->getMockBuilder('Symfony\Component\HttpFoundation\ParameterBag')
83 | ->disableOriginalConstructor()
84 | ->getMock();
85 | $this->request->attributes->expects($this->once())
86 | ->method('all')
87 | ->willReturn([]);
88 | $this->request->query = $this
89 | ->getMockBuilder('Symfony\Component\HttpFoundation\ParameterBag')
90 | ->disableOriginalConstructor()
91 | ->getMock();
92 |
93 | $this->request->query->expects($this->at(0))->method('get')->with('filtering', [])->willReturn([]);
94 | $this->request->query->expects($this->at(1))->method('get')->with('filtering_or', [])->willReturn([
95 | 'foo' => 'bar',
96 | ]);
97 | $this->request->query->expects($this->at(2))->method('get')->with('sorting', [])->willReturn([]);
98 | $this->request->query->expects($this->at(3))->method('get')->with('printing', [])->willReturn([]);
99 | $this->request->query->expects($this->at(4))->method('get')->with('rel', '')->willReturn([]);
100 | $this->request->query->expects($this->at(5))->method('get')->with('page', '')->willReturn([]);
101 | $this->request->query->expects($this->at(6))->method('get')->with('select', 'asdf')->willReturn([]);
102 | $this->request->query->expects($this->at(7))->method('get')->with('filtering', '')->willReturn([]);
103 | $this->request->query->expects($this->at(8))->method('get')->with('limit', '')->willReturn([]);
104 |
105 | $this->builder = new QueryOptionsBuilder();
106 | $this->builder->setEntityAlias($alias = 'asdf');
107 | $options = $this->builder->fromRequest($this->request);
108 |
109 | $this->assertEquals(
110 | QueryBuilderOptions::fromArray([
111 | 'filtering' => [],
112 | 'orFilters' => [
113 | 'foo' => 'bar',
114 | ],
115 | 'limit' => [],
116 | 'page' => [],
117 | 'filters' => [],
118 | 'orFiltering' => [
119 | 'foo' => 'bar',
120 | ],
121 | 'sorting' => [],
122 | 'rel' => [],
123 | 'printing' => [],
124 | 'select' => [],
125 | ]),
126 | $options
127 | );
128 | }
129 |
130 | public function testAdjustOrFilteringWheneverIsAnArray()
131 | {
132 | $this->request = $this
133 | ->getMockBuilder('Symfony\Component\HttpFoundation\Request')
134 | ->disableOriginalConstructor()
135 | ->getMock();
136 | $this->request->attributes = $this
137 | ->getMockBuilder('Symfony\Component\HttpFoundation\ParameterBag')
138 | ->disableOriginalConstructor()
139 | ->getMock();
140 | $this->request->attributes->expects($this->once())
141 | ->method('all')
142 | ->willReturn([]);
143 | $this->request->query = $this
144 | ->getMockBuilder('Symfony\Component\HttpFoundation\ParameterBag')
145 | ->disableOriginalConstructor()
146 | ->getMock();
147 |
148 | $this->request->query->expects($this->at(0))->method('get')->with('filtering', [])->willReturn([]);
149 | $this->request->query->expects($this->at(1))->method('get')->with('filtering_or', [])->willReturn([
150 | 'foo' => [
151 | 'bar',
152 | 'foo',
153 | ]
154 | ]);
155 | $this->request->query->expects($this->at(2))->method('get')->with('sorting', [])->willReturn([]);
156 | $this->request->query->expects($this->at(3))->method('get')->with('printing', [])->willReturn([]);
157 | $this->request->query->expects($this->at(4))->method('get')->with('rel', '')->willReturn([]);
158 | $this->request->query->expects($this->at(5))->method('get')->with('page', '')->willReturn([]);
159 | $this->request->query->expects($this->at(6))->method('get')->with('select', 'asdf')->willReturn([]);
160 | $this->request->query->expects($this->at(7))->method('get')->with('filtering', '')->willReturn([]);
161 | $this->request->query->expects($this->at(8))->method('get')->with('limit', '')->willReturn([]);
162 |
163 | $this->builder = new QueryOptionsBuilder();
164 | $this->builder->setEntityAlias($alias = 'asdf');
165 | $options = $this->builder->fromRequest($this->request);
166 |
167 | $this->assertEquals(
168 | QueryBuilderOptions::fromArray([
169 | 'filtering' => [],
170 | 'orFilters' => [
171 | '0|0' => 'bar',
172 | '1|1' => 'foo',
173 | ],
174 | 'limit' => [],
175 | 'page' => [],
176 | 'filters' => [],
177 | 'orFiltering' => [
178 | '0|0' => 'bar',
179 | '1|1' => 'foo',
180 | ],
181 | 'sorting' => [],
182 | 'rel' => [],
183 | 'printing' => [],
184 | 'select' => [],
185 | ]),
186 | $options
187 | );
188 | }
189 |
190 | public function testShouldBuildOptionsFromEmptyRequestAndCustomFilters()
191 | {
192 | $this->request = $this
193 | ->getMockBuilder('Symfony\Component\HttpFoundation\Request')
194 | ->disableOriginalConstructor()
195 | ->getMock();
196 | $this->request->attributes = $this
197 | ->getMockBuilder('Symfony\Component\HttpFoundation\ParameterBag')
198 | ->disableOriginalConstructor()
199 | ->getMock();
200 | //$this->request->attributes->expects($this->once())
201 | //->method('all')
202 | //->willReturn([]);
203 | $this->request->query = $this
204 | ->getMockBuilder('Symfony\Component\HttpFoundation\ParameterBag')
205 | ->disableOriginalConstructor()
206 | ->getMock();
207 |
208 | $this->request->query->expects($this->at(0))->method('get')->with('filtering', [])->willReturn([]);
209 | $this->request->query->expects($this->at(1))->method('get')->with('filtering_or', [])->willReturn([]);
210 | $this->request->query->expects($this->at(2))->method('get')->with('sorting', [])->willReturn([]);
211 | $this->request->query->expects($this->at(3))->method('get')->with('printing', [])->willReturn([]);
212 | $this->request->query->expects($this->at(4))->method('get')->with('rel', '')->willReturn([]);
213 | $this->request->query->expects($this->at(5))->method('get')->with('page', '')->willReturn([]);
214 | $this->request->query->expects($this->at(6))->method('get')->with('select', 'asdf')->willReturn([]);
215 | $this->request->query->expects($this->at(7))->method('get')->with('filtering', '')->willReturn([]);
216 | $this->request->query->expects($this->at(8))->method('get')->with('limit', '')->willReturn([]);
217 |
218 | $this->builder = new QueryOptionsBuilder();
219 | $this->builder->setEntityAlias($alias = 'asdf');
220 | $options = $this->builder->buildFromRequestAndCustomFilter($this->request, [
221 | 'custom' => 'filter',
222 | ]);
223 |
224 | $this->assertEquals(
225 | QueryBuilderOptions::fromArray([
226 | 'filtering' => [],
227 | 'orFilters' => [],
228 | 'limit' => [],
229 | 'page' => [],
230 | 'filters' => [
231 | 'custom' => 'filter',
232 | ],
233 | '_route_params' => null,
234 | 'sorting' => [],
235 | 'rel' => [],
236 | 'printing' => [],
237 | 'select' => [],
238 | 'justCount' => null,
239 | 'id' => null,
240 | '_route' => null,
241 | ]),
242 | $options
243 | );
244 | }
245 |
246 | public function testShouldBuildQueryWithOrfiltersAndCustomFilters()
247 | {
248 | $this->request = $this
249 | ->getMockBuilder('Symfony\Component\HttpFoundation\Request')
250 | ->disableOriginalConstructor()
251 | ->getMock();
252 | $this->request->attributes = $this
253 | ->getMockBuilder('Symfony\Component\HttpFoundation\ParameterBag')
254 | ->disableOriginalConstructor()
255 | ->getMock();
256 | //$this->request->attributes->expects($this->once())
257 | //->method('all')
258 | //->willReturn([]);
259 | $this->request->query = $this
260 | ->getMockBuilder('Symfony\Component\HttpFoundation\ParameterBag')
261 | ->disableOriginalConstructor()
262 | ->getMock();
263 |
264 | $this->request->query->expects($this->at(0))->method('get')->with('filtering', [])->willReturn([]);
265 | $this->request->query->expects($this->at(1))->method('get')->with('filtering_or', [])->willReturn([
266 | 'foo' => 'bar',
267 | ]);
268 | $this->request->query->expects($this->at(2))->method('get')->with('sorting', [])->willReturn([]);
269 | $this->request->query->expects($this->at(3))->method('get')->with('printing', [])->willReturn([]);
270 | $this->request->query->expects($this->at(4))->method('get')->with('rel', '')->willReturn([]);
271 | $this->request->query->expects($this->at(5))->method('get')->with('page', '')->willReturn([]);
272 | $this->request->query->expects($this->at(6))->method('get')->with('select', 'asdf')->willReturn([]);
273 | $this->request->query->expects($this->at(7))->method('get')->with('filtering', '')->willReturn([]);
274 | $this->request->query->expects($this->at(8))->method('get')->with('limit', '')->willReturn([]);
275 |
276 | $this->builder = new QueryOptionsBuilder();
277 | $this->builder->setEntityAlias($alias = 'asdf');
278 | $options = $this->builder->buildFromRequestAndCustomFilter($this->request, [
279 | 'custom' => 'filter',
280 | ]);
281 |
282 | $this->assertEquals(
283 | QueryBuilderOptions::fromArray([
284 | 'filtering' => [],
285 | 'orFilters' => [
286 | 'foo' => 'bar',
287 | ],
288 | 'limit' => [],
289 | 'page' => [],
290 | 'filters' => [
291 | 'custom' => 'filter',
292 | ],
293 | '_route_params' => null,
294 | 'sorting' => [],
295 | 'rel' => [],
296 | 'printing' => [],
297 | 'select' => [],
298 | 'justCount' => null,
299 | 'id' => null,
300 | '_route' => null,
301 | ]),
302 | $options
303 | );
304 | }
305 |
306 | public function testBuildOptionsFromRequestWithOrFiltersAsArrayAndCustomFilters()
307 | {
308 | $this->request = $this
309 | ->getMockBuilder('Symfony\Component\HttpFoundation\Request')
310 | ->disableOriginalConstructor()
311 | ->getMock();
312 | $this->request->attributes = $this
313 | ->getMockBuilder('Symfony\Component\HttpFoundation\ParameterBag')
314 | ->disableOriginalConstructor()
315 | ->getMock();
316 | //$this->request->attributes->expects($this->once())
317 | //->method('all')
318 | //->willReturn([]);
319 | $this->request->query = $this
320 | ->getMockBuilder('Symfony\Component\HttpFoundation\ParameterBag')
321 | ->disableOriginalConstructor()
322 | ->getMock();
323 |
324 | $this->request->query->expects($this->at(0))->method('get')->with('filtering', [])->willReturn([]);
325 | $this->request->query->expects($this->at(1))->method('get')->with('filtering_or', [])->willReturn([
326 | 'foo' => [
327 | 'bar',
328 | 'atro',
329 | ]
330 | ]);
331 | $this->request->query->expects($this->at(2))->method('get')->with('sorting', [])->willReturn([]);
332 | $this->request->query->expects($this->at(3))->method('get')->with('printing', [])->willReturn([]);
333 | $this->request->query->expects($this->at(4))->method('get')->with('rel', '')->willReturn([]);
334 | $this->request->query->expects($this->at(5))->method('get')->with('page', '')->willReturn([]);
335 | $this->request->query->expects($this->at(6))->method('get')->with('select', 'asdf')->willReturn([]);
336 | $this->request->query->expects($this->at(7))->method('get')->with('filtering', '')->willReturn([]);
337 | $this->request->query->expects($this->at(8))->method('get')->with('limit', '')->willReturn([]);
338 |
339 | $this->builder = new QueryOptionsBuilder();
340 | $this->builder->setEntityAlias($alias = 'asdf');
341 | $options = $this->builder->buildFromRequestAndCustomFilter($this->request, [
342 | 'custom' => 'filter',
343 | ]);
344 |
345 | $this->assertEquals(
346 | QueryBuilderOptions::fromArray([
347 | 'filtering' => [],
348 | 'orFilters' => [
349 | '0|0' => 'bar',
350 | '1|1' => 'atro',
351 | ],
352 | 'limit' => [],
353 | 'page' => [],
354 | 'filters' => [
355 | 'custom' => 'filter',
356 | ],
357 | '_route_params' => null,
358 | 'sorting' => [],
359 | 'rel' => [],
360 | 'printing' => [],
361 | 'select' => [],
362 | 'justCount' => null,
363 | 'id' => null,
364 | '_route' => null,
365 | ]),
366 | $options
367 | );
368 | }
369 |
370 | public function testShouldBuildQueryWithOrfiltersAndCustomOrFilters()
371 | {
372 | $this->request = $this
373 | ->getMockBuilder('Symfony\Component\HttpFoundation\Request')
374 | ->disableOriginalConstructor()
375 | ->getMock();
376 | $this->request->attributes = $this
377 | ->getMockBuilder('Symfony\Component\HttpFoundation\ParameterBag')
378 | ->disableOriginalConstructor()
379 | ->getMock();
380 | //$this->request->attributes->expects($this->once())
381 | //->method('all')
382 | //->willReturn([]);
383 | $this->request->query = $this
384 | ->getMockBuilder('Symfony\Component\HttpFoundation\ParameterBag')
385 | ->disableOriginalConstructor()
386 | ->getMock();
387 |
388 | $this->request->query->expects($this->at(0))->method('get')->with('filtering', [])->willReturn([]);
389 | $this->request->query->expects($this->at(1))->method('get')->with('filtering_or', [])->willReturn([]);
390 | $this->request->query->expects($this->at(2))->method('get')->with('sorting', [])->willReturn([]);
391 | $this->request->query->expects($this->at(3))->method('get')->with('printing', [])->willReturn([]);
392 | $this->request->query->expects($this->at(4))->method('get')->with('rel', '')->willReturn([]);
393 | $this->request->query->expects($this->at(5))->method('get')->with('page', '')->willReturn([]);
394 | $this->request->query->expects($this->at(6))->method('get')->with('select', 'asdf')->willReturn([]);
395 | $this->request->query->expects($this->at(7))->method('get')->with('filtering', '')->willReturn([]);
396 | $this->request->query->expects($this->at(8))->method('get')->with('limit', '')->willReturn([]);
397 |
398 | $this->builder = new QueryOptionsBuilder();
399 | $this->builder->setEntityAlias($alias = 'asdf');
400 | $options = $this->builder->buildForOrFilter($this->request, [
401 | 'fizz' => 'buzz',
402 | ]);
403 |
404 | $this->assertEquals(
405 | QueryBuilderOptions::fromArray([
406 | 'filtering' => [],
407 | 'orFilters' => [
408 | 'fizz' => 'buzz',
409 | ],
410 | 'limit' => [],
411 | 'page' => [],
412 | 'filters' => [],
413 | '_route_params' => null,
414 | 'sorting' => [],
415 | 'rel' => [],
416 | 'printing' => [],
417 | 'select' => [],
418 | 'id' => null,
419 | '_route' => null,
420 | ]),
421 | $options
422 | );
423 | }
424 |
425 | public function testShouldBuildQueryWithOrfiltersAsArrayAndCustomOrFilters()
426 | {
427 | $this->request = $this
428 | ->getMockBuilder('Symfony\Component\HttpFoundation\Request')
429 | ->disableOriginalConstructor()
430 | ->getMock();
431 | $this->request->attributes = $this
432 | ->getMockBuilder('Symfony\Component\HttpFoundation\ParameterBag')
433 | ->disableOriginalConstructor()
434 | ->getMock();
435 | //$this->request->attributes->expects($this->once())
436 | //->method('all')
437 | //->willReturn([]);
438 | $this->request->query = $this
439 | ->getMockBuilder('Symfony\Component\HttpFoundation\ParameterBag')
440 | ->disableOriginalConstructor()
441 | ->getMock();
442 |
443 | $this->request->query->expects($this->at(0))->method('get')->with('filtering', [])->willReturn([]);
444 | $this->request->query->expects($this->at(1))->method('get')->with('filtering_or', [])->willReturn([
445 | 'a' => [
446 | 'b',
447 | 'c',
448 | ],
449 | ]);
450 | $this->request->query->expects($this->at(2))->method('get')->with('sorting', [])->willReturn([]);
451 | $this->request->query->expects($this->at(3))->method('get')->with('printing', [])->willReturn([]);
452 | $this->request->query->expects($this->at(4))->method('get')->with('rel', '')->willReturn([]);
453 | $this->request->query->expects($this->at(5))->method('get')->with('page', '')->willReturn([]);
454 | $this->request->query->expects($this->at(6))->method('get')->with('select', 'asdf')->willReturn([]);
455 | $this->request->query->expects($this->at(7))->method('get')->with('filtering', '')->willReturn([]);
456 | $this->request->query->expects($this->at(8))->method('get')->with('limit', '')->willReturn([]);
457 |
458 | $this->builder = new QueryOptionsBuilder();
459 | $this->builder->setEntityAlias($alias = 'asdf');
460 | $options = $this->builder->buildForOrFilter($this->request, [ ]);
461 |
462 | $this->assertEquals(
463 | QueryBuilderOptions::fromArray([
464 | 'filtering' => [],
465 | 'orFilters' => [
466 | '0|0' => 'b',
467 | '1|1' => 'c',
468 | ],
469 | 'limit' => [],
470 | 'page' => [],
471 | 'filters' => [],
472 | '_route_params' => null,
473 | 'sorting' => [],
474 | 'rel' => [],
475 | 'printing' => [],
476 | 'select' => [],
477 | 'id' => null,
478 | '_route' => null,
479 | ]),
480 | $options
481 | );
482 | }
483 |
484 | /** @expectedException Mado\QueryBundle\Exceptions\InvalidFiltersException */
485 | public function testInvalidFilterThrownException()
486 | {
487 | $this->request = $this
488 | ->getMockBuilder('Symfony\Component\HttpFoundation\Request')
489 | ->disableOriginalConstructor()
490 | ->getMock();
491 | $this->request->attributes = $this
492 | ->getMockBuilder('Symfony\Component\HttpFoundation\ParameterBag')
493 | ->disableOriginalConstructor()
494 | ->getMock();
495 | $this->request->query = $this
496 | ->getMockBuilder('Symfony\Component\HttpFoundation\ParameterBag')
497 | ->disableOriginalConstructor()
498 | ->getMock();
499 |
500 | $this->request->query->expects($this->at(0))->method('get')->with('filtering', [])->willReturn('');
501 | $this->request->query->expects($this->at(1))->method('get')->with('filtering_or', [])->willReturn([]);
502 | $this->request->query->expects($this->at(2))->method('get')->with('sorting', [])->willReturn([]);
503 | $this->request->query->expects($this->at(3))->method('get')->with('printing', [])->willReturn([]);
504 | $this->request->query->expects($this->at(4))->method('get')->with('rel', '')->willReturn([]);
505 | $this->request->query->expects($this->at(5))->method('get')->with('page', '')->willReturn([]);
506 | $this->request->query->expects($this->at(6))->method('get')->with('select', 'asdf')->willReturn([]);
507 | $this->request->query->expects($this->at(7))->method('get')->with('filtering', '')->willReturn([]);
508 | $this->request->query->expects($this->at(8))->method('get')->with('limit', '')->willReturn([]);
509 |
510 | $this->builder = new QueryOptionsBuilder();
511 | $this->builder->setEntityAlias($alias = 'asdf');
512 | $this->builder->buildFromRequestAndCustomFilter($this->request, []);
513 | }
514 | }
515 |
--------------------------------------------------------------------------------
/tests/Mado/QueryBundle/Queries/QueryBuilderOptionsTest.php:
--------------------------------------------------------------------------------
1 | -1]);
13 | $this->assertEquals(PHP_INT_MAX, $options->get('limit'));
14 | }
15 |
16 | public function testUndefinedLimitMeansInfiniteByDefault()
17 | {
18 | $options = QueryBuilderOptions::fromArray([]);
19 | $this->assertEquals(PHP_INT_MAX, $options->get('limit'));
20 | }
21 |
22 | public function testGetDefaultValueIfNotSpecified()
23 | {
24 | $options = QueryBuilderOptions::fromArray([]);
25 | $this->assertEquals(42, $options->get('limit', 42));
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/tests/Mado/QueryBundle/Services/AdditionalFilterExtractorTest.php:
--------------------------------------------------------------------------------
1 | $ids,
12 | ];
13 |
14 | $this->user = $this
15 | ->getMockBuilder('\Mado\QueryBundle\Interfaces\AdditionalFilterable')
16 | ->disableOriginalConstructor()
17 | ->getMock();
18 | $this->user->expects($this->once())
19 | ->method('getAdditionalFilters')
20 | ->will($this->returnValue($additionalFilters));
21 |
22 | $filter = \Mado\QueryBundle\Services\AdditionalFilterExtractor::fromUser($this->user);
23 |
24 | $this->assertEquals(
25 | $ids,
26 | $filter->getFilters('additionalfilter')
27 | );
28 | }
29 |
30 | public function testExtractEmptyArray()
31 | {
32 | $this->user = $this
33 | ->getMockBuilder('\Mado\QueryBundle\Interfaces\AdditionalFilterable')
34 | ->disableOriginalConstructor()
35 | ->getMock();
36 | $this->user->expects($this->once())
37 | ->method('getAdditionalFilters')
38 | ->will($this->returnValue([]));
39 |
40 | $filter = \Mado\QueryBundle\Services\AdditionalFilterExtractor::fromUser($this->user);
41 |
42 | $this->assertEquals('', $filter->getFilters('additionalfilter'));
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/tests/Mado/QueryBundle/Services/PagerTest.php:
--------------------------------------------------------------------------------
1 | pagerfantaFactoryMock = $this
27 | ->getMockBuilder(\Hateoas\Representation\Factory\PagerfantaFactory::class)
28 | ->disableOriginalConstructor()
29 | ->getMock();
30 |
31 | $this->router = $this
32 | ->getMockBuilder(\Mado\QueryBundle\Services\Router::class)
33 | ->disableOriginalConstructor()
34 | ->getMock();
35 |
36 | $this->queryBuilder = $this
37 | ->getMockBuilder(\Doctrine\ORM\QueryBuilder::class)
38 | ->disableOriginalConstructor()
39 | ->getMock();
40 |
41 | $this->queryBuilderOptions = $this
42 | ->getMockBuilder(\Mado\QueryBundle\Queries\QueryBuilderOptions::class)
43 | ->disableOriginalConstructor()
44 | ->getMock();
45 |
46 | $this->pagerfantaBuilder = $this
47 | ->getMockBuilder(\Mado\QueryBundle\Objects\PagerfantaBuilder::class)
48 | ->disableOriginalConstructor()
49 | ->getMock();
50 |
51 | $this->doctrineOrmAdapter = $this
52 | ->getMockBuilder(\Pagerfanta\Adapter\DoctrineORMAdapter::class)
53 | ->disableOriginalConstructor()
54 | ->getMock();
55 |
56 | $this->query = $this
57 | ->getMockBuilder(\Doctrine\ORM\AbstractQuery::class)
58 | ->disableOriginalConstructor()
59 | ->getMock();
60 |
61 | $this->pagerfanta = $this
62 | ->getMockBuilder(\Pagerfanta\Pagerfanta::class)
63 | ->disableOriginalConstructor()
64 | ->getMock();
65 |
66 | $this->doctrineOrmAdapter
67 | ->method('getQuery')
68 | ->willReturn($this->query);
69 |
70 | $this->queryBuilderOptions
71 | ->expects($this->at(0))
72 | ->method('get')
73 | ->with('limit')
74 | ->willReturn(1);
75 |
76 | $this->queryBuilderOptions
77 | ->expects($this->at(1))
78 | ->method('get')
79 | ->with('page')
80 | ->willReturn(1);
81 |
82 | $this->pagerfantaBuilder
83 | ->method('create')
84 | ->willReturn($this->pagerfanta);
85 |
86 | $this->pagerfantaBuilder
87 | ->method('createRepresentation')
88 | ->willReturn(true);
89 |
90 | $this->pager = new Pager();
91 | }
92 |
93 | public function testPaginateWithoutCache()
94 | {
95 | $this->query
96 | ->expects($this->never())
97 | ->method('useResultCache');
98 |
99 | $routeName = 'foo';
100 | $useCache = null;
101 |
102 | $this->pager->setRouter($this->router);
103 |
104 | $this->pager->paginateResults(
105 | $this->queryBuilderOptions,
106 | $this->doctrineOrmAdapter,
107 | $this->pagerfantaBuilder,
108 | $routeName,
109 | $useCache
110 | );
111 | }
112 |
113 | public function testPaginateWithCache()
114 | {
115 | $this->query
116 | ->expects($this->once())
117 | ->method('useResultCache');
118 |
119 | $routeName = 'foo';
120 | $useCache = true;
121 |
122 | $this->pager->setRouter($this->router);
123 |
124 | $this->pager->paginateResults(
125 | $this->queryBuilderOptions,
126 | $this->doctrineOrmAdapter,
127 | $this->pagerfantaBuilder,
128 | $routeName,
129 | $useCache
130 | );
131 | }
132 | }
133 |
--------------------------------------------------------------------------------
/tests/Mado/QueryBundle/Services/RouterTest.php:
--------------------------------------------------------------------------------
1 | 'foo',
13 | 'orFilters' => 'bar'
14 | ]);
15 |
16 | $this->router = new Router();
17 | $route = $this->router->createRouter($queryBuilderOptions, 'foo');
18 |
19 | $this->assertEquals('foo', $route->getName());
20 | }
21 |
22 | public function testCreateRouterWithRouteParams()
23 | {
24 | $routeName = 'route';
25 | $routeParamsKey = 'foo';
26 | $routeParamsValue = 'bar';
27 | $queryBuilderOptions = QueryBuilderOptions::fromArray([
28 | '_route_params' => [$routeParamsKey => $routeParamsValue]
29 | ]);
30 |
31 | $this->router = new Router();
32 | $route = $this->router->createRouter($queryBuilderOptions, $routeName);
33 | $routeParams = $route->getParameters();
34 |
35 | $this->assertEquals($routeName, $route->getName());
36 | $this->assertTrue(array_key_exists($routeParamsKey, $routeParams));
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/tests/Mado/QueryBundle/Services/StringParserTest.php:
--------------------------------------------------------------------------------
1 | parser = new StringParser();
11 |
12 | $this->assertEquals(
13 | 'fizzBuzzFooBar',
14 | $this->parser->camelize('fizz_buzz_foo_bar')
15 | );
16 | }
17 |
18 | public function testDotNotationFor()
19 | {
20 | $result = StringParser::dotNotationFor('Foo\bar');
21 |
22 | $this->assertEquals('foo.bar', $result);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------