{"id":37012849,"url":"https://github.com/studiomado/query-bundle","last_synced_at":"2026-01-14T01:14:49.015Z","repository":{"id":49753285,"uuid":"99698479","full_name":"studiomado/query-bundle","owner":"studiomado","description":"Query doctrine database from query string and provide HATEOAS responses.","archived":false,"fork":false,"pushed_at":"2022-10-04T15:51:34.000Z","size":415,"stargazers_count":13,"open_issues_count":12,"forks_count":5,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-10-19T23:09:39.324Z","etag":null,"topics":["database","dijkstra","doctrine","doctrine2","graphql","hateoas","query-builder","rest-api","symfony"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/studiomado.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG-2.0.md","contributing":".github/CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-08-08T13:53:54.000Z","updated_at":"2020-05-15T16:43:45.000Z","dependencies_parsed_at":"2022-09-22T14:41:24.512Z","dependency_job_id":null,"html_url":"https://github.com/studiomado/query-bundle","commit_stats":null,"previous_names":[],"tags_count":97,"template":false,"template_full_name":null,"purl":"pkg:github/studiomado/query-bundle","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/studiomado%2Fquery-bundle","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/studiomado%2Fquery-bundle/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/studiomado%2Fquery-bundle/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/studiomado%2Fquery-bundle/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/studiomado","download_url":"https://codeload.github.com/studiomado/query-bundle/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/studiomado%2Fquery-bundle/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28407661,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T00:40:43.272Z","status":"ssl_error","status_checked_at":"2026-01-14T00:40:42.636Z","response_time":56,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["database","dijkstra","doctrine","doctrine2","graphql","hateoas","query-builder","rest-api","symfony"],"created_at":"2026-01-14T01:14:48.271Z","updated_at":"2026-01-14T01:14:49.007Z","avatar_url":"https://github.com/studiomado.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# QueryBundle\n\nlatest stable version [![Latest Stable Version](https://poser.pugx.org/studiomado/query-bundle/version)](https://packagist.org/packages/studiomado/query-bundle)\n\n\n| 2.4 (master) | 2.3 | 2.2 |\n|----------------|----------|---|\n| [![Build Status](https://scrutinizer-ci.com/g/studiomado/query-bundle/badges/build.png?b=master)](https://scrutinizer-ci.com/g/studiomado/query-bundle/build-status/master) | [![Build Status](https://scrutinizer-ci.com/g/studiomado/query-bundle/badges/build.png?b=2.3)](https://scrutinizer-ci.com/g/studiomado/query-bundle/build-status/2.3) | [![Build Status](https://scrutinizer-ci.com/g/studiomado/query-bundle/badges/build.png?b=2.2)](https://scrutinizer-ci.com/g/studiomado/query-bundle/build-status/2.2) |\n| [![Code Coverage](https://scrutinizer-ci.com/g/studiomado/query-bundle/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/studiomado/query-bundle/?branch=master) | [![Code Coverage](https://scrutinizer-ci.com/g/studiomado/query-bundle/badges/coverage.png?b=2.3)](https://scrutinizer-ci.com/g/studiomado/query-bundle/?branch=2.3) | [![Code Coverage](https://scrutinizer-ci.com/g/studiomado/query-bundle/badges/coverage.png?b=2.2)](https://scrutinizer-ci.com/g/studiomado/query-bundle/?branch=2.2) |\n| [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/studiomado/query-bundle/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/studiomado/query-bundle/?branch=master) |  [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/studiomado/query-bundle/badges/quality-score.png?b=2.3)](https://scrutinizer-ci.com/g/studiomado/query-bundle/?branch=2.3) | [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/studiomado/query-bundle/badges/quality-score.png?b=2.2)](https://scrutinizer-ci.com/g/studiomado/query-bundle/?branch=2.2) |\n\n\n## Run tests\n\n - `./runtests.sh` run all unit tests\n - `./agile.sh` generate testdox documentation\n - `./coverage.sh` generate and open html coverage\n\n# Plain symfony project for query-bundle\n\nThe purpose of this project is to see how studiomado/query-bundle works and can be installed in a plain symfony project.\n\n - database configuration\n - install query-bundle\n - create at least one entity\n\n# Database configuration\n\nRemember 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.\n\nThis 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.\n\n    prompt\u003e ./bin/console doctrine:database:create\n    Created database /path/to/project/var/data/data.sqlite for connection named default\n\n# Install query-bundle\n\n    prompt\u003e composer require studiomado/query-bundle\n\n# Create at least one entity\n\nCreate at least one entity ...\n\n    prompt\u003e ./bin/console doctrine:generate:entity\n\nIn this example I created an entity Task following command steps.\n\n    created ./src/AppBundle/Entity/\n    created ./src/AppBundle/Entity/Task.php\n    \u003e Generating entity class src/AppBundle/Entity/Task.php: OK!\n    \u003e \u003e Generating repository class src/AppBundle/Repository/TaskRepository.php: OK!\n\n... and update the schema ...\n\n\t\tprompt\u003e ./bin/console doctrine:schema:update\n\t\tATTENTION: This operation should not be executed in a production environment.\n\t\t\t\t\t\t\t Use the incremental update to detect changes during development and use\n\t\t\t\t\t\t\t the SQL DDL provided to manually update your database in production.\n\n\t\tThe Schema-Tool would execute \"1\" queries to update the database.\n\t\tPlease run the operation by passing one - or both - of the following options:\n\t\t\t\tdoctrine:schema:update --force to execute the command\n\t\t\t\tdoctrine:schema:update --dump-sql to dump the SQL statements to the screen\n\nThe schema update works only with force option\n\n    prompt\u003e ./bin/console doctrine:schema:update --force\n    Updating database schema...\n    Database schema updated successfully! \"1\" query was executed\n\nJust take a look of the database content (that now is simply empty).\n\n    prompt\u003e ./bin/console doctrine:query:dql \"select t from AppBundle:Task t\"\n\nThe query will return an empty array of result\n\n     array (size=0)\n       empty\n\nJust add first task ... \n\n    prompt\u003e ./bin/console doctrine:query:sql \"insert into task values (null, 'complete this guide', 'todo') \"\n\nand take a look of the content\n\n    prompt\u003e ./bin/console doctrine:query:dql \"select t from AppBundle:Task t\"\n\n    array (size=1)\n      0 =\u003e\n        object(stdClass)[507]\n          public '__CLASS__' =\u003e string 'AppBundle\\Entity\\Task' (length=21)\n          public 'id' =\u003e int 1\n          public 'description' =\u003e string 'complete this guide' (length=19)\n          public 'status' =\u003e string 'todo' (length=4)\n\n\n# Complete installation\n\nFirst of all install vendors\n\n    prompt\u003e composer require jms/serializer-bundle\n    prompt\u003e composer require willdurand/hateoas-bundle\n    prompt\u003e composer require white-october/pagerfanta-bundle\n    prompt\u003e composer require friendsofsymfony/rest-bundle\n\nand then, … add vendors in your app/AppKernel \n\n    new FOS\\RestBundle\\FOSRestBundle(),\n    new JMS\\SerializerBundle\\JMSSerializerBundle(),\n    new Bazinga\\Bundle\\HateoasBundle\\BazingaHateoasBundle(),\n\n# Complete configuration and use the bundle\n\nOnce everything is done, you can add new endpoints using the query-bundle to query the database.\n\n```\nnamespace AppBundle\\Controller;\n\nuse Sensio\\Bundle\\FrameworkExtraBundle\\Configuration\\Route;\nuse Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\Response;\n\nclass DefaultController extends Controller\n{\n    /** @Route(\"/\", name=\"homepage\") */\n    public function indexAction(\n        Request $request,\n        \\Doctrine\\ORM\\EntityManager $em,\n        \\JMS\\Serializer\\Serializer $serializer\n    ) {\n        $data = $em-\u003egetRepository('AppBundle:Task')\n            -\u003esetRequest($request)\n            -\u003efindAllPaginated();\n\n        $content = $serializer-\u003eserialize($data, 'json');\n\n        return new Response($content, 200);\n    }\n}\n```\n\n# Configure your entity repository\n\nNow be sure that your repository extends the right BaseRepository.\n\n```\nnamespace AppBundle\\Repository;\n\nclass TaskRepository extends \\Mado\\QueryBundle\\Repositories\\BaseRepository\n{\n    // to do …\n}\n```\n\n```\nnamespace AppBundle\\Entity;\n\n/** @ORM\\Entity(repositoryClass=\"AppBundle\\Repository\\TaskRepository\") */\nclass Task\n{\n    // to do …\n}\n```\n\n# Customize entity serialization\n\nNow if you want to customize responses add\n\n    use JMS\\Serializer\\Annotation as JMS;\n\nOn top of your entities and complete your JMS configurations. See JMS documentation to get all the complete documentation.\n\nHere some examples:\n\n - http://127.0.0.1:8000/?filtering[status]=todo\n - http://127.0.0.1:8000/?filtering[status|contains]=od\n - http://127.0.0.1:8000/?filtering[status|endswith]=gress\n\n# Find All No Paginated\n\nAdded a new method in **BaseRepository**  \nWhen you need results applying filter and sort without pagination\n```\npublic function findAllNoPaginated();\n```\nThis feature was needed to create an Excel Report, injecting results into the Excel Report\n\nExample without pagination\n--------------------------\nIn Controller:\n```\npublic function getTasksExcelReportAction(Request $request)\n    {\n        $tasks = $this-\u003egetDoctrine()\n            -\u003egetRepository('AppBundle:Task')\n            -\u003efindAllNoPaginated();\n        \n        $reportExcel = new TasksReport($tasks);\n        $reportExcel-\u003ecreateReport();\n        \n        $excelContent = $reportExcel-\u003eprintReport();\n        \n        return new Response(\n            $excelContent,\n            200, [\n                'Content-Type' =\u003e 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',\n            ]\n        );        \n    } \n```  \n\nExample with pagination\n-----------------------\nIn Controller:\n```\n    public function getTasksAction(Request $request)\n    {\n        return $this-\u003egetDoctrine()\n            -\u003egetRepository('AppBundle:Task')\n            -\u003esetRequest($request)\n            -\u003efindAllPaginated();\n    }\n```\n\n# Queries\n\n## AND Conditions\n\nIf 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:\n\n```\n/api/foo?filtering[name|eq]=bar\u0026filtering[surname|eq]=bar\n```\n\nThis request will produce a query like this:\n\n```\nSELECT f0_.id AS id_0, f0_.name AS name_1, f0_.surname AS surname_2\" .\nFROM foo f0_\" .\nWHERE f0_.name = \"bar\" AND f0_.surname = \"bar\"\n```\n\n## OR Conditions\n\nIf 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:\n\n```\n/api/foo?filtering_or[name|eq]=bar\u0026filtering_or[surname|eq]=bar\n```\n\nThis request will produce a query like this:\n\n```\nSELECT f0_.id AS id_0, f0_.name AS name_1, f0_.surname AS surname_2\" .\nFROM foo f0_\" .\nWHERE ((f0_.name = \"bar\" OR f0_.surname = \"bar\"))\n```\n\nInstead, if you want to have more OR conditions separated you can do something like this:\n\n ```\n /api/foo?filtering_or[name|eq|1]=bar\u0026filtering_or[surname|eq|1]=bar\u0026filtering_or[group|contains|2]=baz\u0026filtering_or[role|contains|2]=baz\n ```\n \nThis request will produce a query like this:\n\n```\nSELECT 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\" .\nFROM foo f0_\" .\nWHERE (f0_.name = \"bar\" OR f0_.surname = \"bar\") AND (f0_.group LIKE \"%baz%\" OR f0_.role LIKE \"%baz%\")\n```\n\nThis can be done by using a counter after the operator separated by ```|``` \n\n## Search into relations\n\nIf you want to search inside an entity where a condition is inside another entity you can do this:\n\n```\n/api/users?filtering[_embedded.group.name|contains =bar\n```\n\nThis request will produce a query like this:\n\n```\nSELECT u0_.id AS id_0 u0_.username AS username_1,  u0_.group_id AS group_id_2 \" .\nFROM User u0_\nLEFT JOIN Group g1_ ON u0_.group_id = g1_.id \" .\nWHERE g1_.name LIKE \"%bar%\"\n```\n\nTo do this you need to add inside the user entity some Hateoas annotations like this:\n\n```\n * @Hateoas\\Relation(\n *     \"groups\",\n *     embedded = @Hateoas\\Embedded(\n *         \"expr(object.getGroups())\",\n *          exclusion = @Hateoas\\Exclusion(\n *              excludeIf = \"expr(object.getGroups().isEmpty() === true)\",\n *              groups={\"groups\"},\n *              maxDepth = 1\n *          )\n *     ),\n *     exclusion = @Hateoas\\Exclusion(\n *              excludeIf = \"expr(object.getGroups().isEmpty() === true)\",\n *              groups={\"groups\"},\n *              maxDepth = 1\n *          )\n * )\n \n ```\n\nIf you add Hateoas annotations correctly, you can search deeper than only \"one level\". Here an example:\n\n```\n/api/users?filtering[_embedded.profile.location.country.name|contains]=italy\n```\n\nIn this example you search all users that have a profile with a country location name: Italy.  \nProfile, location and country are entities and name is the field.\n\nYou can use _embedded filter also into filtering_or conditions.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstudiomado%2Fquery-bundle","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstudiomado%2Fquery-bundle","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstudiomado%2Fquery-bundle/lists"}