PHP code example of tarantool / mapper

1. Go to this page and download the library: Download tarantool/mapper library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

tarantool / mapper example snippets


use Tarantool\Client\Client;
use Tarantool\Mapper\Mapper;

$client = Client::fromDefaults();
$mapper = new Mapper($client);

// internaly mapper wraps client with special middleware
assert($mapper->client !== $client);

$person = $mapper->createSpace('person', [
    'engine' => 'memtx',
    'if_not_exists' => true,
]);

// add properties - name, type and options
$person->addProperty('id', 'unsigned');
$person->addProperty('name', 'string');
$person->addProperty('birthday', 'unsigned');
$person->addProperty('gender', 'string', [
    'default' => 'male'
]);

// indexes are created using fields array and optional index configuration
$person->addIndex(['name']);
$person->addIndex(['birthday'], ['unique' => true]);

// index name is fields based, but you can specify any preffered one
$person->addIndex(['name', 'birthday'], [
    'type' => 'hash',
    'name' => 'name_with_birthday',
]);

/**
 * define format using properties
 */
class Tracker
{
    public int $id;
    public int $reference;
    public string $status;

    public static function initSchema(\Tarantool\Mapper\Space $space)
    {
        $space->addIndex(['reference']);
    }
}

$tracker = $mapper->createSpace('tracker');
$tracker->setClass(Tracker::class);
$tracker->migrate();

/**
 * define format using constructor promotion
 */
class Policy
{
    public function __construct(
        public int $id,
        public string $nick,
        public string $status,
    ) {
    }

    public static function initialize(\Tarantool\Mapper\Space $space)
    {
        $space->addIndex(['nick'], ['unique' => true]);
    }
}

$policy = $mapper->createSpace('policy', ['if_not_exists' => true]);
$policy->setClass(Policy::class, 'initialize'); // use custom initialize method
$policy->migrate();

/**
 * mapper access using class name
 */
class Login
{
    public function __construct(
        public int $id,
        public string $username,
        public string $password,
    ) {
    }

    public static function initSchema(\Tarantool\Mapper\Space $space)
    {
        $space->addIndex(['username'], ['unique' => true]);
    }
}

$nekufa = $mapper->findOrCreate(Login::class, ['username' = 'nekufa']);
$mapper->update(Login::class, $nekufa, ['password' => password_hash("secret")]);

// get space instance
$persons = $mapper->getSpace('person');

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

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

// retreive entites by id using space
$helloWorld = $mapper->getSpace('post')->findOne(['id' => 3]);

// or using mapper wrapper
$helloWorld = $mapper->findOne('post', ['id' => 3]);

// pass client criteria object as well
$criteria = Criteria::index('age')->andKey([18])->andGeIterator();
$adults = $mapper->find('user', $criteria);

// updates are easy
$posts = $mapper->getSpace('post');
$helloWorld = $posts->update($helloWorld, [
    'title' => 'Hello world'
]);

// if you use instance classes, instance would be updated
$policy = $mapper->findOrFail('policy', ['id' => 3]);
$policy = $mapper->get('policy', 3); // getter shortcut
$mapper->update('policy', $policy, [
    'title' => 'updated title',
]);
echo $policy->title; // updated title

// use client operations as well
use Tarantool\Client\Schema\Operations;
$mapper->getSpace('policy')->update($policy, Operations::add('counter', 1));
var_dump($policy->counter); // actual value

use Symfony\Component\Cache\Adapter\ApcuAdapter;
$cache = new ApcuAdapter();

$mapper = new Mapper(Client::fromDefaults());
$mapper->cache = $cache;
$mapper->getSpace('_vspace'); // schema is fetched now

$mapper = new Mapper(Client::fromDefaults());
$mapper->cache = $cache;
$mapper->getSpace('_vspace'); // no new requests are made

use Symfony\Component\Cache\Adapter\ArrayAdapter;

$mapper = new Mapper(Client::fromDefaults());
$mapper->getSpace('_vspace')->cache = new ArrayAdapter(); // feel free to set default ttl

$mapper->find('_vspace'); // query is executed
$mapper->find('_vspace'); // results are fetched from cache
$mapper->find('_vspace'); // results are fetched from cache

$mapper->spy = true;

$nekufa = $mapper->create('user', ['login' => 'nekufa']);
$firstPost = $mapper->create('post', [
    'user_id' => $nekufa->id,
    'title' => 'hello world',
]);
$mapper->update('post', $firstPost, ['title' => 'Final title']);

// now there are two changes
[$first, $second] = $mapper->getChanges();
echo $first->type; // insert
echo $first->space; // user
echo $first->data; // ['login' => 'nekufa']

// all changes would be merged by space and key
// this reduces changes duplicates
echo $second->type; // insert
echo $second->space; // post
echo $second->data; // ['user_id' => 1, 'title' => 'Final title']

// of course you can flush all changes and start registration from scratch
$mapper->flushChanges();

$pool = new Pool(function (string $prefix) {
    return new Mapper(Client::fromDsn('tcp://' . $prefix));
});

// connect to tarantool instance `volume` and find all timelines.
$trackers = $pool->findOne('volume.timeline');

$nekufa = $pool->findOrCreate('guard.login', ['username' => 'nekufa']);
$pool->update('guard.login', $nekufa, ['locked_at' => time()]);

// pool also wraps changes with the prefixes
echo $pool->getChanges()[0]->space; // guard.login

// all expressions do the same behind the scenes
$pool->find('flow.tracker', ['status' => 'active']);
$pool->getMapper('flow')->find('tracker', ['status' => 'active']);
$pool->getMapper('flow')->getSpace('tracker')->find(['status' => 'active']);

// this method will always deliver and parse lua code on the tarantool side
$mapper->evaluate('return a + b', ['a' => 2, 'b' => 7]); // 9

// first call a function would be created with name evaluate_{BODYHASH}
// there would be two requests - create function and call it
$mapper->call('return a + b', ['a' => 2, 'b' => 7]); // 9

// second call will produce single request with function name and arguments
$mapper->call('return a + b', ['a' => 2, 'b' => 7]); // 9
u

use Tarantool\Mapper\Migration;
use Tarantool\Mapper\Space;

class DropLegacySpaces extends Migration
{
    public function beforeSchema(Mapper $mapper)
    {
        $mapper->call(<<<LUA
            if box.space.legacy then
                box.space.legacy:drop()
                box.space.legacy_detail:drop()
            end
        LUA);
    }
}
class InitializeData extends Migration
{
    public function afterSchema(Mapper $mapper)
}
$mapper = $container->get(Mapper::class);

// also migrate accepts migration instance, or migration class arrays
$mapper->migrate(DropLegacySpaces::class, InitializeData::class);