PHPackages                             ray/query-module - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [API Development](/categories/api)
4. /
5. ray/query-module

ActiveLibrary[API Development](/categories/api)

ray/query-module
================

An external media access framework

0.11.1(2mo ago)7293.8k—8.5%5[1 issues](https://github.com/ray-di/Ray.QueryModule/issues)2MITPHPPHP ^8.2CI passing

Since May 16Pushed 2mo ago2 watchersCompare

[ Source](https://github.com/ray-di/Ray.QueryModule)[ Packagist](https://packagist.org/packages/ray/query-module)[ Docs](https://github.com/koriym/Koriym.PhpSkeleton)[ RSS](/packages/ray-query-module/feed)WikiDiscussions 1.x Synced 1mo ago

READMEChangelog (10)Dependencies (22)Versions (23)Used By (2)

Ray.QueryModule
===============

[](#rayquerymodule)

[![codecov](https://camo.githubusercontent.com/af6b927f0121b4850737c7ec6cb5cc07af09bba11229c641cf490e30f4a8f2ca/68747470733a2f2f636f6465636f762e696f2f67682f7261792d64692f5261792e51756572794d6f64756c652f6272616e63682f312e782f67726170682f62616467652e7376673f746f6b656e3d363047324d46444f4252)](https://codecov.io/gh/ray-di/Ray.QueryModule)[![Type Coverage](https://camo.githubusercontent.com/d04a9856ae53d9a5c6073aeb8557a640d2416996139c69af8ea8f6f59b7f61ca/68747470733a2f2f73686570686572642e6465762f6769746875622f7261792d64692f5261792e51756572794d6f64756c652f636f7665726167652e737667)](https://shepherd.dev/github/ray-di/Ray.QueryModule)[![Continuous Integration](https://github.com/ray-di/Ray.QueryModule/workflows/Continuous%20Integration/badge.svg)](https://github.com/ray-di/Ray.QueryModule/workflows/Continuous%20Integration/badge.svg)

[Japanese](README.ja.md)

Overview
--------

[](#overview)

`Ray.QueryModule` makes a query to an external media such as a database or Web API with a function object to be injected.

- `SqlQueryModule` is for DB. Convert the SQL file to a simple function object that executes that SQL.
- `WebQueryModule` is for the Web API. Convert the URI and method set into a simple function object that Web requests to that URI.
- `PhpQueryModule` is a generic module. It provides storage access which can not be provided by static conversion by PHP function object.

Motivation
----------

[](#motivation)

- You can have a clear boundary between domain layer (usage code) and infrastructure layer (injected function) in code.
- Execution objects are generated automatically so you do not need to write procedural code for execution.
- Since usage codes are indifferent to the actual state of external media, storage can be changed later. Easy parallel development and stabbing.

Installation
------------

[](#installation)

### Composer install

[](#composer-install)

```
$ composer require ray/query-module

```

### Module install

[](#module-install)

```
use Ray\Di\AbstractModule;
use Ray\Query\SqlQueryModule;

class AppModule extends AbstractModule
{
    protected function configure()
    {
        // SqlQueryModule install
        $this->install(new SqlQueryModule($sqlDir));

        // WebQueryModule install
        $webQueryConfig = [
            'post_todo' => ['POST', 'https://httpbin.org/todo'], // bind-name => [method, uri]
            'get_todo' => ['GET', 'https://httpbin.org/todo']
        ];
        $guzzleConfig = []; // @see http://docs.guzzlephp.org/en/stable/request-options.html
        $this->install(new WebQueryModule($webQueryConfig, $guzzleConfig));
    }
}
```

### SQL files

[](#sql-files)

$sqlDir/**todo\_insert.sql**

```
INSERT INTO todo (id, title) VALUES (:id, :title)
```

$sqlDir/**todo\_item\_by\_id.sql**

```
SELECT * FROM todo WHERE id = :id
```

Convert SQL to SQL invocation object
------------------------------------

[](#convert-sql-to-sql-invocation-object)

A callable object injected into the constructor. Those object was made in specified sql with `@Named` binding.

```
class Todo
{
    /**
     * @var callable
     */
    private $createTodo;

    /**
     * @var callable
     */
    private $todo;

    /**
     * @Named("createTodo=todo_insert, todo=todo_item_by_id")
     */
    public function __construct(
        callable $createTodo,
        callable $todo
    ){
        $this->createTodo = $createTodo;
        $this->todo = $todo;
    }

    public function get(string $uuid)
    {
        return ($this->todo)(['id' => $uuid]);
    }

    public function create(string $uuid, string $title)
    {
        ($this->createTodo)([
            'id' => $uuid,
            'title' => $title
        ]);
    }
}
```

Row or RowList
--------------

[](#row-or-rowlist)

You can specify expected return value type is either `Row` or `RowList` with `RowInterface` or `RowListInterface`. `RowInterface` is handy to specify SQL which return single row.

```
use Ray\Query\RowInterface;

class Todo
{
    /**
     * @Named("todo_item_by_id")
     */
    public function __construct(RowInterface $todo)
    {
        $this->todo = $todo;
    }

    public function get(string $uuid)
    {
        $todo = ($this->todo)(['id' => $uuid]); // single row data
    }
}
```

```
use Ray\Query\RowListInterface;

class Todos
{
    /**
     * @Named("todos")
     */
    public function __construct(RowListInterface $todos)
    {
        $this->todos = $todos;
    }

    public function get(string $uuid)
    {
        $todos = ($this->todos)(); // multiple row data
    }
}
```

Override the method with callable object
----------------------------------------

[](#override-the-method-with-callable-object)

Entire method invocation can be override with callable object in specified with `@Query`.

```
class Foo
{
    /**
     * @Query(id="todo_item_by_id")
     */
    public function get(string $id)
    {
    }
}
```

When parameter name is different method arguments and Query object arguments, uri\_template style expression can solve it.

```
class FooTempalted
{
    /**
     * @Query(id="todo_item_by_id?id={a}", templated=true)
     */
    public function get(string $a)
    {
    }
}
```

Specify `type='row'` when single row result is expected to return.

```
class FooRow
{
    /**
     * @Query(id="ticket_item_by_id", type="row")
     */
    public function onGet(string $id) : ResourceObject
    {
    }
}
```

If there is no SELECT result, it returns `404 Not Found`.

Convert URI to Web request object
---------------------------------

[](#convert-uri-to-web-request-object)

With `WebQueryModule`, it converts the URI bound in the configuration into an invocation object for web access and injects it. In the following example, an invocation object of `$createTodo` which makes` POST` request to `https://httpbin.org/todo` is injected as `$createTodo`.

```
use Ray\Di\AbstractModule;
use Ray\Query\SqlQueryModule;

class AppModule extends AbstractModule
{
    protected function configure()
    {
        // WebQueryModuleインストール
        $webQueryConfig = [
            'todo_post' => ['POST', 'https://httpbin.org/todo'],
            'todo_get' => ['GET', 'https://httpbin.org/todo']
        ];
        $guzzleConfig = [];
        $this->install(new WebQueryModule($webQueryConfig, $guzzleConfig));
    }
}
```

The usage code is the same as for `SqlQueryModule`.

```
/**
 * @Named("createTodo=todo_post, todo=todo_get")
 */
public function __construct(
    callable $createTodo,
    callable $todo
){
    $this->createTodo = $createTodo;
    $this->todo = $todo;
}
```

```
// POST
($this->createTodo)([
    'id' => $uuid,
    'title' => $title
]);

// GET
($this->todo)(['id' => $uuid]);
```

The usage code of `@Query` does not change either.

Bind to PHP class
-----------------

[](#bind-to-php-class)

If other dependencies are needed, we bind to PHP class and use dependency as a service.

```
class CreateTodo implements QueryInterface
{
    private $pdo;
    private $builder;

    public function __construct(PdoInterface $pdo, QueryBuilderInferface $builder)
    {
        $this->pdo = $pdo;
        $this->builder = $builder;
    }

    public function __invoke(array $query)
    {
        // Query execution using $pdo and $builder
        return $result;
    }
}
```

Bind to `callable`.

```
$this->bind('')->annotatedWith('cretate_todo')->to(CreateTodo::class); // callableはインターフェイスなし
```

The usage codes are the same. The usage code of `@Query` does not change either.

ISO8601 DateTime Module
-----------------------

[](#iso8601-datetime-module)

Convert the specified column name value to the [ISO8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. In PHP, it is a format defined by constants of [DateTime::ATOM](https://www.php.net/manual/en/class.datetime.php#datetime.constants.atom). Install date column names as an array and pass it as an argument to `Iso8601FormatModule`.

```
$this->install(new Iso8601FormatModule(['created_at', 'updated_at']));
```

SQL file name log
-----------------

[](#sql-file-name-log)

The SQL file name can be appended to the SQL statement as a comment. This is useful for query logging.

```
use Ray\Query\SqlFileName;
use Ray\Query\SqlQueryModule;

$this->install(new SqlQueryModule(__DIR__ . '/Fake/sql', null, new SqlFileName()));
```

Execute SQL

```
/* todo_item_by_id.sql */ SELECT * FROM todo WHERE id = :id
```

Demo
----

[](#demo)

```
php demo/run.php

```

BEAR.Sunday example
-------------------

[](#bearsunday-example)

- [Koriym.Ticketsan](https://github.com/koriym/Koriym.TicketSan/blob/master/src/Resource/App/Ticket.php)

###  Health Score

58

—

FairBetter than 98% of packages

Maintenance82

Actively maintained with recent releases

Popularity42

Moderate usage in the ecosystem

Community19

Small or concentrated contributor base

Maturity75

Established project with proven stability

 Bus Factor1

Top contributor holds 96.5% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~158 days

Recently: every ~352 days

Total

19

Last Release

77d ago

Major Versions

0.11.0 → 1.x-dev2026-03-03

PHP version history (4 changes)0.1.0PHP &gt;=7.1.0

0.5.2PHP &gt;=7.2.0

0.6.0PHP ^7.3 || ^8.0

0.11.0PHP ^8.2

### Community

Maintainers

![](https://www.gravatar.com/avatar/db4fc75ffc631168d0d7143b6f2c24b1534dfb921212bd851c026c5cbbb1344d?d=identicon)[koriym](/maintainers/koriym)

---

Top Contributors

[![koriym](https://avatars.githubusercontent.com/u/529021?v=4)](https://github.com/koriym "koriym (248 commits)")[![KazuyaUchida](https://avatars.githubusercontent.com/u/86758002?v=4)](https://github.com/KazuyaUchida "KazuyaUchida (5 commits)")[![amashigeseiji](https://avatars.githubusercontent.com/u/1837070?v=4)](https://github.com/amashigeseiji "amashigeseiji (3 commits)")[![kseta](https://avatars.githubusercontent.com/u/1487865?v=4)](https://github.com/kseta "kseta (1 commits)")

---

Tags

repository

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/ray-query-module/health.svg)

```
[![Health](https://phpackages.com/badges/ray-query-module/health.svg)](https://phpackages.com/packages/ray-query-module)
```

###  Alternatives

[tencentcloud/tencentcloud-sdk-php

TencentCloudApi php sdk

3731.2M42](/packages/tencentcloud-tencentcloud-sdk-php)[bear/package

BEAR.Sunday application framework package

30527.9k23](/packages/bear-package)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
