Ostico / PhpOrient

PhpOrient - Official Php driver based on the binary protocol of OrientDB.
Other
68 stars 37 forks source link

PhpOrient doesn't correctly save a record when it contains a linkset #11

Closed alaimos closed 9 years ago

alaimos commented 9 years ago

PHP Code to reproduce bug:

<?php

require('ws/vendor/autoload.php');

try {

    $client = new \PhpOrient\PhpOrient('localhost', 2424);
    $client->username = 'root';
    $client->password = 'vagrant';
    $client->connect();
    $doCreate = false;
    if (!$client->dbExists('temp')) {
        $client->dbCreate('temp', \PhpOrient\Protocols\Common\Constants::STORAGE_TYPE_MEMORY,
            \PhpOrient\Protocols\Common\Constants::DATABASE_TYPE_DOCUMENT);
        $doCreate = true;
    }
    $client->dbOpen('temp');
    if ($doCreate) {
        $client->sqlBatch('
            create class Prova1;
            create property Prova1.aString string;
            insert into Prova1 (aString) VALUES ("b"),("c"),("d");
            create class Prova2;
            create property Prova2.aString string;
            create property Prova2.anEmbeddedSetOfString embeddedset string;
            create property Prova2.aLinkedSetOfProva1 linkset Prova1;');
    }

    $clusterProva1 = $client->query("select classes[name='Prova1'].defaultClusterId from 0:1", -1)[0]['classes'];
    $clusterProva2 = $client->query("select classes[name='Prova2'].defaultClusterId from 0:1", -1)[0]['classes'];

    echo "Default cluster for Prova1: $clusterProva1\n";
    echo "Default cluster for Prova2: $clusterProva2\n\n";

    $newRecord = ['oClass' => 'Prova2', 'oData' => [
        'aString' => 'record di prova',
        'anEmbeddedSetOfString' => ['qualcosa 1', 'qualcosa 2', 'ancora altro'],
        'aLinkedSetOfProva1' => [new \PhpOrient\Protocols\Binary\Data\ID($clusterProva1, 1),
            new \PhpOrient\Protocols\Binary\Data\ID($clusterProva1, 2)]
    ]];

    $newRecordObject = \PhpOrient\Protocols\Binary\Data\Record::fromConfig($newRecord);
    $newRecordObject->setRid(new \PhpOrient\Protocols\Binary\Data\ID($clusterProva2));

    $tmp = $client->recordCreate($newRecordObject);

    $record = $client->recordLoad($tmp->getRid())[0];

    print_r($record->prova2);

} catch (\Exception $e) {
    echo $e . "\n";
}

_Expected Result:_

    Default cluster for Prova1: 9
    Default cluster for Prova2: 10

    Array
    (
        [0] => PhpOrient\Protocols\Binary\Data\ID Object
            (
                [cluster] => 9
                [position] => 1
            )

        [1] => PhpOrient\Protocols\Binary\Data\ID Object
            (
                [cluster] => 9
                [position] => 2
            )

    )

_Actual outcome obtained after code execution:_

    Default cluster for Prova1: 9
    Default cluster for Prova2: 10

    exception 'OutOfBoundsException' with message 'prova2 key does not exists.' in /vagrant/src/www/ws/vendor/ostico/phporient/src/PhpOrient/Protocols/Binary/Data/Record.php:193
    Stack trace:
    #0 /vagrant/src/www/ws/vendor/ostico/phporient/src/PhpOrient/Protocols/Binary/Data/Record.php(246): PhpOrient\Protocols\Binary\Data\Record->offsetGet('prova2')
    #1 /vagrant/src/www/prova.php(49): PhpOrient\Protocols\Binary\Data\Record->__get('prova2')
    #2 {main}

_Output of "select * from Prova2":_

    {
        "result": [
            {
                "@type": "d",
                "@rid": "#10:0",
                "@version": 1,
                "@class": "Prova2",
                "aString": "record di prova",
                "anEmbeddedSetOfString": [
                    "ancora altro",
                    "qualcosa 1",
                    "qualcosa 2"
                ],
                "aLinkedSetOfProva1": [

                ],
                "@fieldTypes": "anEmbeddedSetOfString=e,aLinkedSetOfProva1=n"
            }
        ],
        "notification": "Query executed in 0.101 sec. Returned 1 record(s)"
    }

_Environment:_

_Proposed fix:_

In class \PhpOrient\Protocols\Binary\Serialization\CSV line 514 following:

        } elseif ( $value instanceof \DateTime ) {
            return $value->getTimestamp() . 't';

add:

        } elseif ($value instanceof \PhpOrient\Protocols\Binary\Data\ID) {
            return $value->__toString();
Ostico commented 9 years ago

Hi Salvatore, i tried your script and you are right, the linkset of rids are not correctly handled when writing to the data stream.

I followed your suggestion, the patch you provided works fine.

Thank you.

P.S. In your test there is an error on this line:

    print_r( $record->prova2 ); 
    ## produce an exception not related with PhpOrient
    ## exception 'OutOfBoundsException' with message 'prova2 key does not exists.'

    ## it should be
    /**
     * @var \PhpOrient\Protocols\Binary\Data\Record $record
     */
    print_r( $record->getOData() );  
    ## or
    print_r( $record->aLinkedSetOfProva1 );

    ## Actual result  
/*
    Array
    (
        [aString] => Test record
        [anEmbeddedSetOfString] => Array
            (
                [0] => something 1
                [1] => something 2
                [2] => more other
            )

        [aLinkedSetOfProva1] => Array
            (
                [0] => PhpOrient\Protocols\Binary\Data\ID Object
                    (
                        [cluster] => 9
                        [position] => 1
                    )

                [1] => PhpOrient\Protocols\Binary\Data\ID Object
                    (
                        [cluster] => 9
                        [position] => 2
                    )

            )

    )
*/