{"id":37010273,"url":"https://github.com/bancer/native-sql-mapper","last_synced_at":"2026-01-14T00:59:13.594Z","repository":{"id":325717604,"uuid":"1101945888","full_name":"bancer/native-sql-mapper","owner":"bancer","description":"A lightweight extension for the CakePHP ORM that converts prepared PDO statements into fully mapped result sets. It infers entities and associations from CakePHP-style aliases, supports deep and belongsToMany relations, and builds nested entity graphs automatically with strict alias validation.","archived":false,"fork":false,"pushed_at":"2025-12-13T19:54:37.000Z","size":86,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-12-15T14:52:42.046Z","etag":null,"topics":[],"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/bancer.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-11-22T14:33:36.000Z","updated_at":"2025-12-10T21:55:23.000Z","dependencies_parsed_at":null,"dependency_job_id":"0c06a84c-6168-4bef-91f9-107009198df0","html_url":"https://github.com/bancer/native-sql-mapper","commit_stats":null,"previous_names":["bancer/native-sql-mapper"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/bancer/native-sql-mapper","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bancer%2Fnative-sql-mapper","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bancer%2Fnative-sql-mapper/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bancer%2Fnative-sql-mapper/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bancer%2Fnative-sql-mapper/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bancer","download_url":"https://codeload.github.com/bancer/native-sql-mapper/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bancer%2Fnative-sql-mapper/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28407630,"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":[],"created_at":"2026-01-14T00:59:12.899Z","updated_at":"2026-01-14T00:59:13.561Z","avatar_url":"https://github.com/bancer.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# native-sql-mapper\n\nA lightweight extension for the CakePHP ORM that converts **native SQL queries** (executed through prepared PDO statements) into **fully hydrated CakePHP entity graphs**.\n\nThis library allows you to execute raw SQL while still benefiting from CakePHP’s entity system, associations, nested structures, and conventions. It supports **deep associations**, **belongsToMany relations**, **junction data**, **nested mapping**, and **strict alias validation**.\n\n`native-sql-mapper` is ideal when:\n\n- You need SQL performance or features that exceed the ORM’s query builder  \n- You want complex joins, window functions, CTEs, subqueries, aggregates\n- You do not want to spend time on converting your SQL statements to query objects using CakePHP's query builder\n- But still want **CakePHP entities**, **patch-like hydration**, and **nested association graphs** automatically built from the result set  \n\nAliases such as:\n\n```\nArticles__id,\nArticles__title,\nComments__id,\nComments__article_id,\nComments__content\n```\n\nwill be converted into a fully hydrated entity objects.\n\n---\n\n## 🚀 Features\n\n- **Native SQL → real CakePHP entities**  \n- **Deep association support** (belongsTo, hasMany, hasOne, belongsToMany)\n- **Automatic nested entity graph building**\n- **Strict alias validation** based on your ORM associations\n- **No configuration required** — conventions are inferred\n- **Works with any SQL** (CTEs, window functions, unions, etc.)\n\n---\n\n## 📦 Installation\n\nInstall via Composer:\n\n```bash\ncomposer require bancer/native-sql-mapper\n```\n---\n\n## 🔧 Setup \u0026 Usage\n\n### 1. Import the trait in your Table class\n\n```php\nuse Bancer\\NativeQueryMapper\\ORM\\NativeSQLMapperTrait;\n```\n\n### 2. Use the trait\n\n```php\nuse NativeSQLMapperTrait;\n```\n\n### 3. Example usage\n\n```php\n$ArticlesTable = $this-\u003efetchTable(ArticlesTable::class);\n$stmt = $ArticlesTable-\u003eprepareNativeStatement(\"\n    SELECT\n        id     AS Articles__id,\n        title  AS Articles__title\n    FROM articles\n    WHERE title = :title\n\");\n$stmt-\u003ebindValue('title', 'My Article Title');\n/** @var \\App\\Model\\Entity\\Article[] $entities */\n$entities = $ArticlesTable-\u003emapNativeStatement($stmt)-\u003eall();\n```\n\n`$entities` now contains hydrated `Article` entities based on the SQL result.\n\n---\n\n## 🔁 hasMany Example Using Minimalistic SQL\n\n```php\n$stmt = $ArticlesTable-\u003eprepareNativeStatement(\"\n    SELECT\n        a.id        AS Articles__id,\n        title       AS Articles__title,\n        c.id        AS Comments__id,\n        article_id  AS Comments__article_id,\n        content     AS Comments__content\n    FROM articles AS a\n    LEFT JOIN comments AS c\n        ON a.id=c.article_id\n\");\n$entities = $ArticlesTable-\u003emapNativeStatement($stmt)-\u003eall();\n```\n`$entities` now contains an array of Article objects with Comment objects as children.\n\nSame as the result of reqular `-\u003efind()...-\u003etoArray()`:\n```php\n$entities = $ArticlesTable-\u003efind()\n    -\u003eselect(['Articles.id', 'Articles.title'])\n    -\u003econtain([\n        'Comments' =\u003e [\n            'fields' =\u003e ['Comments.id', 'Comments.article_id', 'Comments.content'],\n        ],\n    ])\n    -\u003etoArray();\n```\nNotice that `FROM` and `JOIN` clauses may use short or long aliases or no aliases at all (if the query does not use 'hasMany' or 'belongsToMany' associations) but all fields in `SELECT` clause must use aliases according to CakePHP naming convention `{Alias}__{field_name}`.\n\n## 🔁 belongsToMany Example\n\n```php\n$ArticlesTable = $this-\u003efetchTable(ArticlesTable::class);\n$stmt = $ArticlesTable-\u003eprepareNativeStatement(\"\n    SELECT\n        Articles.id     AS Articles__id,\n        Articles.title  AS Articles__title,\n        Tags.id         AS Tags__id,\n        Tags.name       AS Tags__name\n    FROM articles AS Articles\n    LEFT JOIN articles_tags AS ArticlesTags\n        ON Articles.id=ArticlesTags.article_id\n    LEFT JOIN tags AS Tags\n        ON Tags.id=ArticlesTags.tag_id\n\");\n$entities = $ArticlesTable-\u003emapNativeStatement($stmt)-\u003eall();\n```\nYou can find more examples in tests - https://github.com/bancer/native-sql-mapper/tree/develop/tests/TestCase/ORM.\n\n### Mapping\n---\n\n## 🧠 How It Works\n\n- Aliases are parsed using CakePHP’s `Alias__field` naming convention  \n- Mapping is validated against real your ORM associations  \n- Deep nested associations are built recursively      \n- Only entities and associations that exist in your ORM are allowed  \n\n---\n\n## ➕ BONUS: IN() placeholder helper for native SQL\n\nWhen working with **native SQL queries** in CakePHP, PDO does not support binding arrays directly to `IN (…)` clauses. Each value must be expanded into its own placeholder and bound individually.\n\nThe `InPlaceholders` class provides a small, explicit helper that removes this boilerplate while keeping native SQL fully transparent and predictable.\n\n##### What it does\n\n`InPlaceholders` is a **value object** that:\n\n- Generates named placeholders for use inside SQL `IN (…)` clauses\n- Binds all values to a prepared statement safely\n- Infers the correct PDO parameter type automatically (or accepts one explicitly)\n- Fails fast on invalid input (empty prefix or empty value list)\n\nThere is **no ORM magic** involved — this works purely at the native SQL / PDO level.\n\n##### Basic example\n\n```php\nuse Bancer\\NativeQueryMapper\\Database\\InPlaceholders;\n\n$statuses = new InPlaceholders('status', [1, 5, 9]);\n$sql = \u003c\u003c\u003cSQL\n    SELECT email as Users__email\n    FROM users\n    WHERE status_id IN ($statuses)\nSQL;\n$stmt = $this-\u003eprepareNativeStatement($sql);\n$statuses-\u003ebindValuesToStatement($stmt);\n$entities = $this-\u003emapNativeStatement($stmt)-\u003eall();\n```\n\n---\n\n## ⚠️ Requirements\n\n- Cake ORM **4.x** or **5.x** (or CakePHP **4.x** or **5.x**)\n- PHP **7.4+** or **8.0+**\n- PDO database driver  \n\n---\n\n## 📝 Notes \u0026 Limitations\n\n- Aliases **must** follow CakePHP-style naming: `Model__field`.\n- If SQL retrieves data from 'hasMany' or 'belongsToMany' associations then all primary columns must be present in `SELECT` clause\n- Fields without valid aliases throw exceptions\n- Associations must exist in the Table class, incorrect aliases throw exceptions  \n- Pagination must be handled manually\n- This library is not a replacement of CakePHP query builder but a useful addition to it.\n\n---\n\n## ✔️ Summary\n\n`native-sql-mapper` gives you the **freedom** of native SQL with the **structure** of CakePHP entities.  \nIt fills the gap between raw PDO statements and the ORM — allowing complex SQL while preserving the integrity of your entity graphs.\n\n---\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbancer%2Fnative-sql-mapper","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbancer%2Fnative-sql-mapper","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbancer%2Fnative-sql-mapper/lists"}