PHPackages                             egorov/mapper - 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. [Database &amp; ORM](/categories/database)
4. /
5. egorov/mapper

AbandonedArchivedLibrary[Database &amp; ORM](/categories/database)

egorov/mapper
=============

PHP Object Mapper for Tarantool.

4.3.20(7y ago)0261MITPHPPHP ^7.0

Since Jun 11Pushed 7y ago1 watchersCompare

[ Source](https://github.com/Desure85/mapper)[ Packagist](https://packagist.org/packages/egorov/mapper)[ RSS](/packages/egorov-mapper/feed)WikiDiscussions master Synced 2d ago

READMEChangelogDependencies (5)Versions (153)Used By (1)

Tarantool Mapper
================

[](#tarantool-mapper)

[![License](https://camo.githubusercontent.com/72cb433731ead81db4c922f93d68ac3cdeb8c79035fed6e3ee24a51e6261ed94/68747470733a2f2f706f7365722e707567782e6f72672f746172616e746f6f6c2f6d61707065722f6c6963656e73652e706e67)](https://packagist.org/packages/tarantool/mapper)[![Build Status](https://camo.githubusercontent.com/e9378a94d899128535f6e3393fcbd9b9c9e0088162b12d5a5d3bc0358b6fcfa0/68747470733a2f2f7472617669732d63692e6f72672f746172616e746f6f6c2d7068702f6d61707065722e7376673f6272616e63683d6d6173746572)](https://travis-ci.org/tarantool-php/mapper)[![Latest Version](https://camo.githubusercontent.com/201ba254d66af120c9bcfa1fb8b2f595477e69f1e667aaf8654a23266211aeb0/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f72656c656173652f746172616e746f6f6c2d7068702f6d61707065722e7376673f7374796c653d666c61742d737175617265)](https://github.com/tarantool-php/mapper/releases)[![Total Downloads](https://camo.githubusercontent.com/e30b094f3e803184f30b24d87b95a83df8e4e015b1471e9bbd3b5c9f9190123e/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f746172616e746f6f6c2f6d61707065722e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/tarantool/mapper)[![Scrutinizer Code Quality](https://camo.githubusercontent.com/7d3c88ee0c7d2e5a9d37806a9bb64332b6712377e7b6662a685bf30500f8e1cc/68747470733a2f2f7363727574696e697a65722d63692e636f6d2f672f746172616e746f6f6c2d7068702f6d61707065722f6261646765732f7175616c6974792d73636f72652e706e673f623d6d6173746572)](https://scrutinizer-ci.com/g/tarantool-php/mapper/?branch=master)[![Code Coverage](https://camo.githubusercontent.com/27817fc0005c76e40be7eb323eb2fbef06823b3e7fa1922723f7811bd7c163e5/68747470733a2f2f7363727574696e697a65722d63692e636f6d2f672f746172616e746f6f6c2d7068702f6d61707065722f6261646765732f636f7665726167652e706e673f623d6d6173746572)](https://scrutinizer-ci.com/g/tarantool-php/mapper/?branch=master)

- [Installation](#installation)
- [Instantiate mapper](#instantiate-mapper)
- [Logging](#logging)
- [Existing types](#existing-types)
- [Describe entities](#describe-entities)
- [Use migrations](#use-migrations)
- [Use fluent api](#use-fluent-api)
- [Working with the data](#working-with-the-data)
- [Indexes](#indexes)
- [Array properties](#array-properties)
- [Sequence plugin](#sequence-plugin)
- [User-defined classes plugin](#user-defined-classes-plugin)
- [Annotation plugin](#annotation-plugin)
- [Internals](#internals)
- [Performance](#performance)

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

[](#installation)

The recommended way to install the library is through [Composer](http://getcomposer.org):

```
$ composer require tarantool/mapper

```

Instantiate mapper
------------------

[](#instantiate-mapper)

Usually, you manage dependencies in your service provider. To get started you should instantiate connection, packer, client and mapper itself. In this example we use PurePacker and StreamConnection. It means you don't need any pecl extensions. To see other implementations please check [client documentation](https://github.com/tarantool-php/client#usage)

```
use Tarantool\Client\Client;
use Tarantool\Client\Connection\StreamConnection;
use Tarantool\Client\Packer\PurePacker;
use Tarantool\Mapper\Mapper;

$connection = new StreamConnection();
$client = new Client($connection, new PurePacker());
$mapper = new Mapper($client);
```

Logging
-------

[](#logging)

By default, client does not logs tarantool requests, you can use mapper\\client that supports logging.

```
use Tarantool\Client\Connection\StreamConnection;
use Tarantool\Client\Packer\PurePacker;
use Tarantool\Mapper\Mapper;
use Tarantool\Mapper\Client;

$connection = new StreamConnection();
$client = new Client($connection, new PurePacker());
$mapper = new Mapper($client);

$result = $client->ping();

$log = $client->getLog();
```

Existing types
--------------

[](#existing-types)

You can start with your current configuration. Please, note - all instances are mapped to key-value objects.

```
$globalSpace = $mapper->find('_space', ['name' => '_space']);
echo $globalSpace->id; // 280

$indexes = $mapper->find('_index', ['id' => $globalSpace->id]);
var_dump($indexes); // indexes on _index space
echo $indexes[0]->name;  // primary index
echo $indexes[0]->type; // tree

$guest = $mapper->find('_user', ['name' => 'guest']);
echo $guest->id; // 0
echo $guest->type; // user
```

Describe entities
-----------------

[](#describe-entities)

To get started you should describe your types and fields using meta object.

```
$person = $mapper->getSchema()->createSpace('person');

// add properties
$person->addProperty('id', 'unsigned');
$person->addProperty('name', 'string');
$person->addProperty('birthday', 'unsigned');
$person->addProperty('gender', 'string');

// add multiple properties
$person->addProperties([
  'telegram' => 'string',
  'vk' => 'string',
  'facebook' => 'string',
]);

// add indexes
// first index is primary
$person->createIndex([
    'type' => 'hash', // define type
    'fields' => ['id'],
]);

// create unique indexes using property or array of properties as parameter
$person->createIndex('name');

// create not unique indexes
$person->createIndex([
    'fields' => 'birthday',
    'unique' => false
]);

// if you wish - you can specify index name
$person->createIndex([
    'fields' => ['name', 'birthday'],
    'type' => 'hash',
    'name' => 'name_with_birthday',
]);
```

Use migrations
--------------

[](#use-migrations)

```
use Tarantool\Mapper\Mapper;
use Tarantool\Mapper\Migration;

class InitTesterSchema implements Migration
{
  public function migrate(Mapper $mapper)
  {
    $tester = $mapper->getSchema()->createSpace('tester', [
      'engine' => 'memtx', // or vinyl
      'properties' => [
        'id' => 'unsigned',
        'name' => 'string',
      ]
    ]);
    $tester->createIndex('id');
  }
}

$mapper->getBootstrap()->register(InitTesterSchema::class);
// or register instance $mapper->getBootstrap()->register(new InitTesterSchema());

$mapper->getBootstrap()->migrate();
```

Use fluent api
--------------

[](#use-fluent-api)

```
use Tarantool\Mapper\Mapper;
use Tarantool\Mapper\Migration;

class InitTesterSchema implements Migration
{
  public function migrate(Mapper $mapper)
  {
    $mapper->getSchema()->createSpace('person')
      ->addProperty('id', 'unsigned')
      ->addProperty('name', 'string')
      ->addIndex('id');
  }
}
```

Working with the data
---------------------

[](#working-with-the-data)

Now you can store and retreive data from tarantool storage using mapper instance.

```
// get repository instance
$persons = $mapper->getRepository('person');

// create new entity
$dmitry = $persons->create([
  'id' => 1,
  'name' => 'Dmitry'
]);

// save
$mapper->save($dmitry);

// you can create entities using mapper wrapper.
// this way entity will be created and saved in the tarantool
$vasily = $mapper->create('person', [
  'id' => 2,
  'name' => 'Vasily'
]);

// you can retreive entites by id from repository
$helloWorld = $mapper->getRepository('post')->find(3);

// or using mapper wrapper
$helloWorld = $mapper->find('post', 3);

// updates are easy
$helloWorld->title = "Hello World!";
$mapper->save($helloWorld);
```

Indexes
-------

[](#indexes)

```
$note = $mapper->getSchema()->createSpace('note');
$note->addProperty('slug', 'string');
$note->addProperty('title', 'string',
$note->addProperty('status', 'string');

$note->addIndex('slug');
$note->addIndex([
  'fields' => 'status',
  'unique' => false
]);

// find using repository
$mapper->getRepository('note')->find(['status' => 'active']);
// find using shortcut
$mapper->find('note', ['status' => 'active']);

// find first
$mapper->getRepository('note')->findOne(['slug' => 'my-secret-note']);

// composite indexes can be used partial
$person = $mapper->getSchema()->createSpace('person');
$person->addProperty('id', 'unsigned');
$person->addProperty('client', 'unsigned');
$person->addProperty('sector', 'unsigned');
$person->addProperty('name', 'unsigned');

$person->addIndex('id');
$person->addIndex([
  'fields' => ['client', 'sector'],
  'unique' => false
]);

// using index parts
$mapper->find('person', ['client' => 2]);
$mapper->find('person', ['client' => 2, 'sector' => 27]);
```

Array properties
----------------

[](#array-properties)

You can store arrays as property without any serialization to string.

```
$pattern = $mapper->getSchema()->createSpace('shift_pattern');
$pattern->addProperty('id', 'unsigned');
$pattern->addProperty('title', 'string');
$pattern->addProperty('pattern', '*');

$pattern->addIndex('id');

$mapper->create('shift_pattern', [
  'id' => 1,
  'title' => '5 days week',
  'pattern' => [
    ['work' => true],
    ['work' => true],
    ['work' => true],
    ['work' => true],
    ['work' => true],
    ['work' => false],
    ['work' => false],
  ]
]);

$mapper->get('shift_pattern', 1)->pattern[5]; // read element with index 5 from pattern array
```

Sequence plugin
---------------

[](#sequence-plugin)

If you want you can use sequence plugin that generates next value based on sequence space. Or you can implement id generator using any other source, for example with raft protocol.

```
$mapper->getSchema()->createSpace('post', [
    'id' => 'unsigned',
    'title' => 'string',
    'body' => 'string',
  ])
  ->addIndex('id');

$mapper->getPlugin(Tarantool\Mapper\Plugin\Sequence::class);

$entity = $mapper->create('post', [
  'title' => 'Autoincrement implemented',
  'body' => 'You can use Sequence plugin to track and fill your entity id'
]);

echo $entity->id; // will be set when you create an instance
```

User-defined classes plugin
---------------------------

[](#user-defined-classes-plugin)

If you want you can specify classes to use for repository and entity instances. Entity and repository class implementation are ommited, but you should just extend base classes.

```
$userClasses = $mapper->getPlugin(Tarantool\Mapper\Plugin\UserClasses::class);
$userClasses->mapEntity('person', Application\Entity\Person::class);
$userClasses->mapRepository('person', Application\Repository\Person::class);

$nekufa = $mapper->create('person', [
  'email' => 'nekufa@gmail.com'
]);

get_class($nekufa); // Application\Entity\Person;

$mapper->getSchema()->getSpace('person')->getRepository(); // will be instance of Application\Repository\Person
```

Annotation plugin
-----------------

[](#annotation-plugin)

You can describe your entities using dobclock. Mapper will create space, format and indexes for you.

```
namespace Entity;

use Tarantool\Mapper\Entity;

class Person extends Entity
{
    /**
     * @var integer
     */
    public $id;

    /**
     * @var string
     */
    public $name;
}

class Post extends Entity
{
    /**
     * @var integer
     */
    public $id;

    /**
     * @var string
     */
    public $slug;

    /**
     * @var string
     */
    public $title;

    /**
     * @var string
     */
    public $body;

    /**
     * @var Person
     */
    public $author;

    /**
     * @var integer
     * @required
     */
    public $salary;
}
```

If you want to index fields, extend repository and define indexes property

```
namespace Repository;

use Tarantool\Mapper\Repository;

class Post extends Repository
{
    public $engine = 'memtx'; // or vinyl

    public $indexes = [
        // if your index is unique, you can set property collection
        ['id'],
        // extended definition unique index with one field
        [
          'fields' => ['slug'],
          'unique' => true,
        ],
        // extended definition (similar to Space::addIndex params)
        // [
        //  'fields' => ['year', 'month', 'day'],
        //  'unique' => true
        // ],
    ];
}
```

Register plugin and all your classes:

```
$mapper->getPlugin(Tarantool\Mapper\Plugin\Sequence::class); // just not to fill id manually
$mapper->getPlugin(Tarantool\Mapper\Plugin\Annotation::class)
  ->register(Entity\Person::class)
  ->register(Entity\Post::class)
  ->register(Repository\Person::class)
  ->migrate(); // sync database schema with code

$nekufa = $mapper->create('person', ['name' => 'dmitry']);

$post = $mapper->create('post', [
  'author' => $nekufa,
  'slug' => 'hello-world',
  'title' => 'Hello world',
  'body' => 'Now you can use mapper better way'
]);

// in addition you can simple get related entity
$post->getAuthor() == $nekufa; // true

// or related collection
$nekufa->getPostCollection() == [$post]; // true
```

Internals
---------

[](#internals)

Mapper uses IdentityMap and query caching

```
$dmitry = $mapper->getRepository('person')->findOne(['name' => 'Dmitry']); // person with id 1
echo $dmitry == $mapper->findOne('person', 1); // true

// query result are cached until you create new entites
$mapper->getRepository('person')->findOne(['name' => 'Dmitry']);

// you can flush cache manually
$mapper->getRepository('person')->flushCache();
```

Performance
-----------

[](#performance)

Mapper overhead depends on amount of rows and operation type. Table contains overhead in **milliseconds** per entity. In some cases, overhead can't be calculated due float precision.

Operation100100010 000100 000create entity one by one0.0170.0220.0230.024select entity one by one-0.0150.0160.018one select for all entites--0.0020.006Perfomance test was made on (intel i5-6400), bash for windows 10 using php 7.0.18. For example, when single select will produce 10 000 entites, you will get 20ms overhead.

###  Health Score

32

—

LowBetter than 72% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity6

Limited adoption so far

Community14

Small or concentrated contributor base

Maturity76

Established project with proven stability

 Bus Factor1

Top contributor holds 97.3% 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 ~5 days

Recently: every ~18 days

Total

151

Last Release

2791d ago

Major Versions

v1.0.9 → 2.0.0-alpha2017-03-05

2.7.8 → 3.0.02017-05-24

3.6.12 → 4.0.02017-10-31

PHP version history (3 changes)v1.0.0PHP ^5.5|^7.0

2.0.0-alphaPHP ^7.0

4.3.0PHP ^7.1

### Community

Maintainers

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

---

Top Contributors

[![nekufa](https://avatars.githubusercontent.com/u/405067?v=4)](https://github.com/nekufa "nekufa (289 commits)")[![rybakit](https://avatars.githubusercontent.com/u/533861?v=4)](https://github.com/rybakit "rybakit (4 commits)")[![Desure85](https://avatars.githubusercontent.com/u/10466638?v=4)](https://github.com/Desure85 "Desure85 (3 commits)")[![lav45](https://avatars.githubusercontent.com/u/675367?v=4)](https://github.com/lav45 "lav45 (1 commits)")

---

Tags

clientnosqlmapperpuretarantool

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/egorov-mapper/health.svg)

```
[![Health](https://phpackages.com/badges/egorov-mapper/health.svg)](https://phpackages.com/packages/egorov-mapper)
```

###  Alternatives

[tarantool/mapper

PHP Object Mapper for Tarantool.

6862.4k4](/packages/tarantool-mapper)[doctrine/persistence

The Doctrine Persistence project is a set of shared interfaces and functionality that the different Doctrine object mappers share.

4.1k286.5M762](/packages/doctrine-persistence)[tarantool/client

PHP client for Tarantool.

67430.7k21](/packages/tarantool-client)[clue/redis-react

Async Redis client implementation, built on top of ReactPHP.

28210.5M45](/packages/clue-redis-react)[basho/riak

Official Riak client for PHP

159246.7k7](/packages/basho-riak)[mroosz/php-cassandra

A pure-PHP client for Apache Cassandra and ScyllaDB with support for CQL binary protocol v3, v4 and v5 (Cassandra 2.1+ incl. 3.x-5.x; ScyllaDB 6.2 and 2025.x), synchronous and asynchronous APIs, prepared statements, batches, result iterators, object mapping, SSL/TLS, and LZ4 compression.

205.6k2](/packages/mroosz-php-cassandra)

PHPackages © 2026

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