Code Monkey home page Code Monkey logo

neo4j-php-ogm's Introduction

THIS REPOSITORY IS ARCHIVED.

Please head to http://github.com/neo4j-php or http://neo4j.com/developer/php for up-to-date PHP support for Neo4j.


GraphAware Neo4j PHP OGM

Object Graph Mapper for Neo4j in PHP

Build Status Latest Stable Version Latest Unstable Version Total Downloads License

Current Release : 1.0.0-RC9

Installation

Install with composer

composer require graphaware/neo4j-php-ogm:@rc

Documentation

The new documentation is available on ReadTheDocs.

Some parts from the old documentation might be still missing.

Getting Help

For questions, please open a new thread on StackOverflow with the graphaware, neo4j and neo4j-php-ogm tags.

For isses, please raise a Github issue in the repository.

License

The library is released under the MIT License, refer to the LICENSE file bundled with this package.

neo4j-php-ogm's People

Contributors

androlgenhald avatar apopiak avatar cebe avatar ikwattro avatar joethielen avatar kbsali avatar lchrusciel avatar mikaelmattsson avatar nyholm avatar oguillet avatar theum avatar ttmelki avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

neo4j-php-ogm's Issues

RelationshipEntity with Same Class for startNode and EndNode

The TC1 has an issue when it comes to RelationshipEntities that have the same class as target and end node.

For example:
MATCH (u:User)-[:USER_FOLLOWS {since: XYZ}]->(u:User)

So a User class would have 2 properties

$follows
$isFollowedBy

and a respective UserFollowsUser relationship entity class. But when I load data from the database the source and tagret entity are both set to the source entity. The problem is in GraphAware\Neo4j\OGM\Hydrator\EntityHydrator in public function hydrateRelationshipEntity($alias, Result $dbResult, $sourceEntity)

// set the start node
        if ($relationshipEntityMetadata->getStartNodeClass() === $this->_classMetadata->getClassName()) {
            $relationshipEntityMetadata->setStartNodeProperty($entity, $sourceEntity);
        } else {
            $relationshipEntityMetadata->setStartNodeProperty($entity, $targetEntity);
        }
        // set the end node
        if ($relationshipEntityMetadata->getEndNodeClass() === $this->_classMetadata->getClassName()) {
            $relationshipEntityMetadata->setEndNodeProperty($entity, $sourceEntity);
        } else {
            $relationshipEntityMetadata->setEndNodeProperty($entity, $targetEntity);
        }

Both if clauses resolve in true and so the start node and the end node are both with $sourceEntity.

Unique annotation

Hello,

It is plan to add a Unique annotation like Doctrine ?
For example :

/**
 * @Column(type="string",  unique=true)
 */
protected $username;

It could be very useful !

Feature: Dynamic labels

I see there is an undocumented @Label annotation that can be used with a boolean to include or exclude it. What are your thoughts on having an array that can be used to dynamically set labels? A use case for this would be inheritance:

class Foo{
    /**
     * @OGM\DynamicLabelArray
     */
    protected $dynamicLabels = [];

    public function __construct(){
        $this->dynamicLabels[] = 'FOO';
    }
}

class Bar extends Foo{
    public function __construct(){
        parent::__construct();
        $this->dynamicLabels[] = 'BAR';
    }
}

So all Bar objects would also get the FOO label, and queries using FOO would still match them.
Is this reasonable? Is there a better alternative?

Use PRs

When the maintainers make code changes, could you consider using PRs? I would like to be notified whenever something changes. Also, it's great that the tests run before pushing to master.

Keep up the good work!

Implement Lazy loading or opportunity to load multiple levels of relationships

When loading entities via the BaseRepository Methods (findOneBy, findAll, ...) the EntityManager only returns the object + the objects directly related to the loaded object.

E.g.: User -> FOLLOWS -> User

Accessing $user->getFollowers()->getFirst()->getFollowers() will return no followers, even though there might be some.

Either implementing lazy loading of these entities or the opportunity to define a depth of how deep relationships shall be followed would highly improve the neo4j-php-ogm

Thanks

Issues when changing relationships

When changing a relationship there are issues with it not creating the new one and not deleting the old one.

use GraphAware\Neo4j\OGM\Annotations as OGM;
use GraphAware\Neo4j\OGM\EntityManager;

/**
 * @OGM\Node(label="A")
 */
class A
{
    /**
     * @OGM\GraphId()
     * @var int
     */
    protected $id;

    /**
     * @OGM\Relationship(type="TEST", direction="OUTGOING", targetEntity="B", collection=false)
     * @var B
     */
    protected $b;

    /**
     * @return int
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * @param int $id
     */
    public function setId($id)
    {
        $this->id = $id;
    }

    /**
     * @return B
     */
    public function getB()
    {
        return $this->b;
    }

    /**
     * @param B $b
     */
    public function setB($b)
    {
        if ($this->b !== null)
        {
            $this->b->setA(null);
        }
        $this->b = $b;
        if ($b !== null && $b->getA() !== $this)
        {
            $b->setA($this);
        }
    }
}

/**
 * @OGM\Node(label="B")
 */
class B
{
    /**
     * @OGM\GraphId()
     * @var int
     */
    protected $id;

    /**
     * @OGM\Relationship(type="TEST", direction="INCOMING", targetEntity="A", collection=false)
     * @var A
     */
    protected $a;

    /**
     * @return int
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * @param int $id
     */
    public function setId($id)
    {
        $this->id = $id;
    }

    /**
     * @return A
     */
    public function getA()
    {
        return $this->a;
    }

    /**
     * @param A $a
     */
    public function setA($a)
    {
        $this->a = $a;
    }
}

$manager = EntityManager::create('[redacted]');

$a1 = new A();

$b1 = new B();
$b2 = new B();

$a1->setB($b1);

$manager->persist($a1);
$manager->persist($b1);
$manager->persist($b2);

$manager->flush();

$a1->setB($b2);

//$manager->persist($a1);
$manager->flush();

With the second $manager->persist($a1) commented the second flush doesn't update anything:
commented-before
commented-after

With the second persist uncommented, the second flush adds the relationship, but it doesn't delete the first relationship:
uncommented-before
uncommented-after

Newly created objects lack parent object links.

I might mess up the terminology here so please bear with me.

If I create 3 new nodes via neo4j-php-ogm (RC1 & dev-master, tried both specifically) with simple relationships like X->Y->Z, then immediately do a findOneBy() on Y and do a print_r() on it, the arrayCollection for Z is OK and correct, but the link (not a collection since there can only be one in this use case) back to X does not populate. Doing something like a Y->getX() results in null, whereas Y->getZs() is OK.

It does populate the DB correctly. And if, instead of immediately doing a findOneBy(), I first destroy then create a new EntityManager, then do the findOneBy(), then it works perfect.

It seems partially similar to #21 , at least, in terms of odd behavior with new objects.

I can create a full set of test data if need be, but I was hoping the above would be clear enough.

Implement persistent collections

Right now proxies initializations relies on getters. Which forces the user to call it before doing any operation on a Relationship collection.

Implementing Persistent collections would remove this constraint.

Proposition: make pagination for related entities

Doctrine has extra lazyness for this
[http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/tutorials/extra-lazy-associations.html]
It allows to write something like $parent->getChilds()->slice(5, 10), which will result in limiting query part responsible for relational nodes matching.
Can we have something similar?
Doctrine way is too complex i guess, so maybe easyer will be to add something like $parent->getChilds(5,10) wich will pass limit/offset data through reflection to NodeCollectionInitializer
(NodeCollectionInitializer to BasicEntityPersister->getSimpleRelationshipCollection() to getSimpleRelationshipCollectionStatement()) (I`m not sure it will work with reflections)
Or simplier and clearer way will be to add limit Annotation, like OrderBy one. This will be way more better than fetch all related nodes and filter them as array.

Lazy relationship loading: errors loading 2nd degree relationships

There is a problem loading 2nd degree relationships (Lazy Loaded collections as well as simple relationships).

Two scenarios cause trouble:

  1. If I create the following simple structure with a TestUser having a TestUserData Entity ($userData / 1:1) and this entity in turn has a lazy loaded Relationship ($someValues / 1:n) to a collection of TestUserDataValue. In short: entity -> entity -> collection
  2. Additionally, the TestUser has a lazy loaded relationship to TestUser ($sponsoredChildren / 1:n) and the TestUser has simple relationships to TestUser ($sponsoredBy: n:1) and TestUserData (1:1). In short: Entity -> collection -> entity

Regarding Scenario 1
In the constructor of TestUserData(), I initialize the ArrayCollection for the relationship as usual (see complete code of classes below).

    public function __construct()
    {
        $this->someValues = new ArrayCollection();
    }

First, creating the TestUser entities and saving them to the database

        $u1 = new TestUser();
        $u1->setName('test01');
        $u1->setUserData(new TestUserData());

        $u2 = new TestUser();
        $u2->setName('test02');
        $u2->setUserData(new TestUserData());

        $u1->addSponsoredChild($u2);

        $em->persist($u1);
        $em->persist($u2);
        $em->flush();

Now adding some values to the TestUserData:

$u->getUserData()->addSomeValue(new TestUserDataValue('foo', 10));
$em->persist($u);
$em->flush();

But when I load this TestUser now from the database (new script, not right after the above code is executed because it is still in the entity Manager), user.userData.someValues is null, and not an Object of LazyRelationshipCollection

$u = $em->getRepository(TestUser::class)->findOneBy('name', 'test01');
var_dump($u->getUserData()->getSomeValues()); // Outputs null, not ArrayCollection

If I load the UserData object directly from the Database, everything is fine:

$ud = $em->getRepository(TestUserData::class)->findOneById($u->getUserData()->getId());
echo "Count of someValue: {$ud->getSomeValues()->count()}";

Regarding Scenario 2
Similar behavior occurs if I have an entity (TestUser), that has a collection of entities (sponsoredBy TestUser) and these TestUser entities have simple relationships (e.g., userData, sponsoredBy). When I load the entity directly from the database, userData and sponsoredBy are loaded correctly. If I access the entity via user->getSponsoredChildren, userData and sponsoredBy are null.

    $u1 = $em->getRepository(TestUser::class)->findOneBy('name', 'test01');
    $u2FromLazy = $u1->getSponsoredChildren()->first();
    echo "User test02 loaed from lazy relationship - Name: {$u2FromLazy->getName()}, userData: " 
        . (($u2FromLazy->getUserData() === null) ? "NULL" : print_r($u2FromLazy->getUserData(), true)) . "<br />"; // Outputs NULL

    // User data object of child is not null when called directly from the child loaded from db: childUser.userData
    $u2FromDb = $em->getRepository(TestUser::class)->findOneBy('name', 'test02');
    echo "User test02 loaed from database - Name: {$u2FromDb->getName()}, userData: " 
        . (($u2FromDb->getUserData() === null) ? "NULL" : print_r($u2FromDb->getUserData(), true)); // Outputs the ProxyManagerGeneratedProxy

Here are my classes:

TestUser.php

/**
  * @OGM\Node(label="TestUser")
  */
class TestUser
{

    /**
     * @OGM\GraphId()
     *
     * @var int
     */
    protected $id;


    /**
     * @OGM\Property(type="string")
     *
     * @var string
     */
    protected $name;

    /**
     * @OGM\Relationship(type="TEST_USER_HAS_SPONSORED_CHILDREN", direction="OUTGOING", targetEntity="TestUser", collection=true, mappedBy="sponsoredBy")
     * @OGM\Lazy()
     * @OGM\OrderBy(property="name", order="ASC")
     * 
     * @var ArrayCollection|TestUser[]
     */
    protected $sponsoredChildren;        

    /**
     * @OGM\Relationship(type="TEST_USER_HAS_SPONSORED_CHILDREN", direction="INCOMING", targetEntity="TestUser", collection=false, mappedBy="sponsoredChildren")
     * 
     * @var TestUser
     */
    protected $sponsoredBy;

    /**
     * @OGM\Relationship(type="TEST_USER_HAS_USER_DATA", direction="OUTGOING", targetEntity="TestUserData", collection=false)
     * 
     * 
     * @var TestUserData
     */
    protected $userData;

    public function __construct()
    {
        $this->sponsoredChildren = new ArrayCollection();     
    }

    /**
     *
     * @param
     *            User
     */
    public function addSponsoredChild(TestUser $obj)
    {
        if (! $this->sponsoredChildren->contains($obj)) {
            $this->sponsoredChildren->add($obj);
        }
        return $this;
    }

    /**
     *
     * @param
     *            User
     */
    public function removeSponsoredChild(TestUser $obj)
    {
        if ($this->sponsoredChildren->contains($obj)) {
            $this->sponsoredChildren->removeElement($obj);
        }
        return $this;
    }

    /**
     *
     * @return the int
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     *
     * @param
     *            $id
     */
    public function setId($id)
    {
        $this->id = $id;
        return $this;
    }

    /**
     *
     * @return the string
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     *
     * @param
     *            $name
     */
    public function setName($name)
    {
        $this->name = $name;
        return $this;
    }

    /**
     *
     * @return TestUser
     */
    public function getSponsoredBy()
    {
        return $this->sponsoredBy;
    }

    /**
     *
     * @param TestUser $sponsoredBy            
     */
    public function setSponsoredBy(TestUser $sponsoredBy)
    {
        $this->sponsoredBy = $sponsoredBy;
        return $this;
    }

    /**
     *
     * @return ArrayCollection|TestUser[]
     */
    public function getSponsoredChildren()
    {
        return $this->sponsoredChildren;
    }

    /**
     *
     * @param ArrayCollection $sponsoredChildren            
     */
    public function setSponsoredChildren($sponsoredChildren)
    {
        $this->sponsoredChildren = $sponsoredChildren;
        return $this;
    }

    /**
     *
     * @return the TestUserData
     */
    public function getUserData()
    {
        return $this->userData;
    }

    /**
     *
     * @param
     *            $userData
     */
    public function setUserData(TestUserData $userData)
    {
        $this->userData = $userData;
        return $this;
    }

}

TestUserData.php

/**
 * @OGM\Node(label="TestUserData")
 **/
class TestUserData {

    /**
     * @OGM\GraphId()
     * 
     * @var int
     */
    protected $id;

    /**
     * @OGM\Relationship(type="TEST_USER_DATA_HAS_USER_DATA_VALUE", direction="OUTGOING", targetEntity="TestUserDataValue", collection=true)
     * @OGM\Lazy()
     * @var ArrayCollection|TestUserDataValue[]
     */
    protected $someValues;

    public function __construct()
    {
        $this->someValues = new ArrayCollection();
    }

    /**
     *
     * @return the int
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     *
     * @return ArrayCollection|UserDataValue[]
     */
    public function getSomeValues()
    {
        return $this->someValues;
    }

    /**
     * Adds a UserDataValue to the downlineNavigatorValues
     *
     * @param UserDataValue
     */
    public function addSomeValue(TestUserDataValue $v)
    {
        if (! $this->someValues->contains($v)) {
            $this->someValues->add($v);
        }
    }
}

TestUserDataValue.php

    /**
 * @OGM\Node(label="TestUserDataValue")
 **/
class TestUserDataValue {


    /**
     * @OGM\GraphId()
     * 
     * @var int
     */
    protected $id;

    /**
     * @OGM\Property(type="string")
     * 
     * @var string
     */
    protected $fieldName;

    /**
     * @OGM\Property(type="int")
     * 
     * @var int
     */
    protected $value;



    // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    //
    //                  Helper functions
    //
    // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    /**
     * @param string $fieldName
     * @param string $fieldType
     * @param mixed $value
     */
    public function __construct($fieldName, $value)
    {
        $this->setFieldName($fieldName);
        $this->setValue($value);
    }

    /**
     *
     * @return the int
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     *
     * @return the string
     */
    public function getFieldName()
    {
        return $this->fieldName;
    }

    /**
     *
     * @param
     *            $fieldName
     */
    public function setFieldName($fieldName)
    {
        $this->fieldName = $fieldName;
        return $this;
    }

    /**
     *
     * @return the int
     */
    public function getValue()
    {
        return $this->value;
    }

    /**
     *
     * @param
     *            $value
     */
    public function setValue($value)
    {
        $this->value = $value;
        return $this;
    }
}

EntityManger's factories

The EntityManger has two factories: EntityManger::create and EntityManger::buildWithHost.

It seams like

EntityManger::buildWithHost($host);
// same as
EntityManger::create($host);

Is that correct? If so, we should break BC while we can (before stable release) and remove EntityManger::buildWithHost.

Odd behavior of entity manager persist with new objects

First, I have to say thank you for this very nice piece of work! I have been working quite a bit with this library and it helps a lot! However, I ran into the following problem:

I have the following class of a User that is organized in a tree structure. User sponsors user sponsors user... :

/**
 * @OGM\Node(label="TestUser")
 */
class TestUser
{

    /**
     * @OGM\GraphId()
     *
     * @var int
     */
    protected $id;


    /**
     * @OGM\Property(type="string")
     *
     * @var string
     */
    protected $name;

   /**
     * @OGM\Relationship(type="TEST_USER_HAS_SPONSORED_CHILDREN", direction="OUTGOING", targetEntity="TestUser", collection=true, mappedBy="sponsoredBy")
     * @OGM\Lazy()
     * @OGM\OrderBy(property="name", order="ASC")
     * 
     * @var ArrayCollection|TestUser[]
     */
    protected $sponsoredChildren;

    public function __construct()
    {
        $this->sponsoredChildren = new ArrayCollection();        
    }



    /**
     *
     * @param
     *            User
     */
    public function addSponsoredChild(TestUser $obj)
    {
        if (! $this->sponsoredChildren->contains($obj)) {
            $this->sponsoredChildren->add($obj);
        }
        return $this;
    }

    /**
     *
     * @return the int
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     *
     * @param
     *            $id
     */
    public function setId($id)
    {
        $this->id = $id;
        return $this;
    }

    /**
     *
     * @return the string
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     *
     * @param
     *            $name
     */
    public function setName($name)
    {
        $this->name = $name;
        return $this;
    }

    /**
     *
     * @return the ArrayCollection|TestUser[]
     */
    public function getSponsoredChildren()
    {
        return $this->sponsoredChildren;
    }

    /**
     *
     * @param unknown_type $sponsoredChildren            
     */
    public function setSponsoredChildren($sponsoredChildren)
    {
        $this->sponsoredChildren = $sponsoredChildren;
        return $this;
    }
}

Now when I want to create simple relationships on new objects like the following

        $u1 = new TestUser();
        $u1->setName('test01');
        $u1->setUserData(new TestUserData());
        $em->persist($u1); // *1st PERSIST_U1

        $u2 = new TestUser();
        $u2->setName('test02');
        $u2->setUserData(new TestUserData());
        // $em->persist($u2); // *PERSIST_U2

        $u3 = new TestUser();
        $u3->setName('test03');
        $u3->setUserData(new TestUserData());
        // $em->persist($u3); // *PERSIST_U3

        $u2->addSponsoredChild($u3);
        $u1->addSponsoredChild($u2);

        // $em->persist($u1); // *2nd_PERSIST_U1
    }

    $em->flush();

The above code creates only $u1, no $u2 and $u3 and of course also no relationships, since $u2 and $u3 do not exist.

If $em->persist($u3) and $em->persist($u2) above are called, the entities $u2 and $u3 are created in the database, however, the relationship between $u1 and $u2 as well as the relationship between $u1 and $u3 are not created.

If *2nd_PERSIST_U1 is called, everything is fine and all entities as well as relationships are created. However, persist should not have to be called here, since $u1 is already managed by the entity manager and any changes to the object should reflect in the database on next flush.

Could you please check on that? Thanks

Hide property

Hi all,

thanks for this package!

I wonder if there is an annotation to hide the property.
For example password.

Is it possible?

Thanks

Entity manager constructor bug

When creating a entity manager i get this error

Argument 1 passed to GraphAware\Neo4j\OGM\EntityManager::__construct() must be an instance of GraphAware\Neo4j\Client\ClientInterface, instance of GraphAware\Neo4j\Client\Client given,

unserialize error on findOnBy

Hello,
I rencently upgrade my version of gaphaware-ogm (via composer) and I notice the new implementation of many components.
I was really impressed about it and I just want to say thank you for your job !
Then I changed some part of my code (especialy findOnBy's usages) for the new prototype.
One of this usage is present in my UserProvider class used by the Secury Bundle.

Unfortunatly, when I tried to log on, UserProvider execute the findOneBy function and I got an error from the ProxyFactory which fails on the userialize operation at line 180.

Here is my dev log file content:

[2017-03-07 21:16:04] request.INFO: Matched route "login_check". {"route":"login_check","route_parameters":{"_route":"login_check"},"request_uri":"http://localhost/pokesphere/web/app_dev.php/login_check","method":"POST"} []
[2017-03-07 21:16:04] security.INFO: Authentication request failed. {"exception":"[object] (Symfony\\Component\\Security\\Core\\Exception\\AuthenticationServiceException(code: 0): Warning: Erroneous data format for unserializing 'neo4j_ogm_proxy_PokeSphereBundle_Entity_User' at C:\\UwAmp\\www\\pokesphere\\vendor\\symfony\\symfony\\src\\Symfony\\Component\\Security\\Core\\Authentication\\Provider\\DaoAuthenticationProvider.php:94, Symfony\\Component\\Debug\\Exception\\ContextErrorException(code: 0): Warning: Erroneous data format for unserializing 'neo4j_ogm_proxy_PokeSphereBundle_Entity_User' at C:\\UwAmp\\www\\pokesphere\\vendor\\graphaware\\neo4j-php-ogm\\src\\Proxy\\ProxyFactory.php:180)"} []
[2017-03-07 21:16:04] security.DEBUG: Authentication failure, redirect triggered. {"failure_path":"/login"} []
[2017-03-07 21:16:08] request.INFO: Matched route "login". {"route":"login","route_parameters":{"_controller":"PokeSphereBundle\\Controller\\SecurityController::loginAction","_route":"login"},"request_uri":"http://localhost/pokesphere/web/app_dev.php/login","method":"GET"} []
[2017-03-07 21:16:08] security.INFO: Populated the TokenStorage with an anonymous Token. [] []
[2017-03-07 21:16:09] request.INFO: Matched route "_assetic_4be3d33_2". {"route":"_assetic_4be3d33_2","route_parameters":{"_controller":"assetic.controller:render","name":"4be3d33","pos":2,"_format":"css","_route":"_assetic_4be3d33_2"},"request_uri":"http://localhost/pokesphere/web/app_dev.php/css/4be3d33_part_1_ie10-viewport-bug-workaround_3.css","method":"GET"} []
[2017-03-07 21:16:09] request.INFO: Matched route "_assetic_4be3d33_0". {"route":"_assetic_4be3d33_0","route_parameters":{"_controller":"assetic.controller:render","name":"4be3d33","pos":0,"_format":"css","_route":"_assetic_4be3d33_0"},"request_uri":"http://localhost/pokesphere/web/app_dev.php/css/4be3d33_part_1_bootstrap-theme.min_1.css","method":"GET"} []
[2017-03-07 21:16:09] request.INFO: Matched route "_assetic_4be3d33_3". {"route":"_assetic_4be3d33_3","route_parameters":{"_controller":"assetic.controller:render","name":"4be3d33","pos":3,"_format":"css","_route":"_assetic_4be3d33_3"},"request_uri":"http://localhost/pokesphere/web/app_dev.php/css/4be3d33_part_1_jumbotron_4.css","method":"GET"} []
[2017-03-07 21:16:09] request.INFO: Matched route "_assetic_4be3d33_1". {"route":"_assetic_4be3d33_1","route_parameters":{"_controller":"assetic.controller:render","name":"4be3d33","pos":1,"_format":"css","_route":"_assetic_4be3d33_1"},"request_uri":"http://localhost/pokesphere/web/app_dev.php/css/4be3d33_part_1_bootstrap.min_2.css","method":"GET"} []
[2017-03-07 21:16:12] request.INFO: Matched route "_assetic_b98a068_0". {"route":"_assetic_b98a068_0","route_parameters":{"_controller":"assetic.controller:render","name":"b98a068","pos":0,"_format":"css","_route":"_assetic_b98a068_0"},"request_uri":"http://localhost/pokesphere/web/app_dev.php/css/b98a068_part_1_for_1.css","method":"GET"} []
[2017-03-07 21:16:14] request.INFO: Matched route "_assetic_b98a068_2". {"route":"_assetic_b98a068_2","route_parameters":{"_controller":"assetic.controller:render","name":"b98a068","pos":2,"_format":"css","_route":"_assetic_b98a068_2"},"request_uri":"http://localhost/pokesphere/web/app_dev.php/css/b98a068_part_1_var_3.css","method":"GET"} []
:[2017-03-07 21:16:14] request.INFO: Matched route "_assetic_0b1b56d_1". {"route":"_assetic_0b1b56d_1","route_parameters":{"_controller":"assetic.controller:render","name":"0b1b56d","pos":1,"_format":"js","_route":"_assetic_0b1b56d_1"},"request_uri":"http://localhost/pokesphere/web/app_dev.php/js/0b1b56d_part_1_main_2.js","method":"GET"} []
[2017-03-07 21:16:18] request.INFO: Matched route "_wdt". {"route":"_wdt","route_parameters":{"_controller":"web_profiler.controller.profiler:toolbarAction","token":"75b3c3","_route":"_wdt"},"request_uri":"http://localhost/pokesphere/web/app_dev.php/_wdt/75b3c3","method":"GET"} []

I tried to understand the problem with xdebug and correct it by myself. The Proxy class was correctly generated and all variables were correct (I guess). I tried to replace the unserialize function by a new instance of the Proxy class. Now the connection work but unserialization of the user session object (by symfony) fails...
I'm probably missing something... or I'm just off with the fairies...

Here is my github project :
https://github.com/Sraime/pokesphere

Fell free to fork/download it (consider the "robin" brach).

Thank you in advance for your help.

Regards

Proxy classes filenames in tmp

The proxy classes for Database entities are stored in php tmp dir with the following naming convention:

neo4j_ogm_proxy_{NAMESPACE}_{CLASSNAME}.php

If I have different installations on one machine (e.g., dev, staging, production or different client installations), deployment of one installation will affect all other installations (as it happened in my case).

So the better solution would be to add a unique id to the end of the file name in order to avoid problems.

Proposition : support DateTime type

Hello !
I actually work on a project where users have to set their birthday on registration.
As you know, in Symfony, validators are used to check if setting values are correct. The best way for the dating values is the DateTime type which is compatible with GreaterThan and LessThan asserts.

/**
* @var string
* @Assert\LessThan("-10 years", message="user.dateofbirth.tooyoung")
* @Assert\GreaterThan("-80 years", message="user.dateofbirth.tooold")
*/
 private $dateOfBirth;

This type can’t be use with the OGM because DateTime cannot by convert to a primitive type in Neo4j.
Dates are very use in many application and it’s could be nice to offer the possibility to use DateTime (and then Assert validators) instead of a simple timestamp.

I work on it and I will propose an implementation very soon in a pull request.

Add Relationship creates new node?

A question about the functionality for managing relationships: I have model that is set up very similar to the Actors / Movies model in the example.
When I do something like this:

$ActorsRepository = $NeoEntityManager->getRepository(Actors::class);
$actor = $ActorsRepository->findOneBy("name", "Johnny Depp" );
 
$moviesRepository = $NeoEntityManager->getRepository(Movies::class);
$movie = $moviesRepository->findOneBy("title", "Pirates of the Caribbean");

$movie->addActor($actor);
$NeoEntityManager->flush();

The lib will try to create a new Actor node with the Johnny Depp node data, where in this situation expected behaviour would be that a relationship is be formed between the 2 existing nodes, without creating a new one right?

Multiple labels for a node

I didn't find possibility to add multiple labels for a node. For example, I have a base node Stop then I have inherited nodes like BusStop, TramStop, TrolleybusStop. I need that stops for trolleybus have two labels (Stop:TrolleybusStop). As I understood it is impossible now to do this. Am I right?

I would like to have something like this

  1. array of labels in annotation
    @OGM\Node(labels={"Stop", "TrolleybusStop"})

  2. or like this

/**
 * @OGM\Node(label="Stop")
 */
class Stop
{
}

/**
 * @OGM\Node(label="TrolleybusStop")
 */
class TrolleybusStop extends Stop
{
    // This entity should have both labels: Stop and TrolleybusStop.
    // Because first one should be inherited from the parent class.
}

RelationshipMetadata returns wrong FQCN when entity is extended in a different namespace

Say I have an entity Foo with a relationship bar:

namespace App\Entity;
/**
 * @OGM\Node(label="Foo")
 */
class Foo
{
    /**
     * @OGM\Relationship(type="RELATED_TO", direction="OUTGOING", targetEntity="Bar", collection=false)
     * @var Bar
     */
    protected $bar;
}

Then I have a class FooBar extend Foo, but in a different namespace:

namespace App\Entity\FooBar;
use App\Entity\Foo;
/**
 * @OGM\Node(label="FooBar")
 */
class FooBar extends Foo
{
}

When RelationshipMetadata resolves the FQCN for the Bar relationship from the FooBar entity, it returns App\Entity\FooBar\Bar rather than App\Entity\Bar.

I haven't looked into it very deeply, so I'm not sure if it's easy to fix or if it should just be documented somewhere.

Removing RelationshipEntity

I was trying your library.

How do you remove the relationship if it exists?
Like the Rating of a user to a movie?

Thanks a lot.

Properties of type "array" not working

We have a user entity extending the fosuser model (yeah, we shouldn't!),
and we are having issues with the roles property. Here is the definition (pretty similar to the Role relationship example of this repo) :

<?php

namespace OGMEntityBundle\Entity;

/**
 * @OGM\Node(label="User", repository="OGMEntityBundle\Repository\Repository")
 */
class User extends BaseUser implements UserInterface
{


    /**
     * @var array
     * @OGM\Property(type="array")
     */
    protected $roles = [];

   ...

    /**
     * @return mixed
     */
    public function getRoles()
    {
        return $this->roles;
    }
    public function setRoles(array $roles)
    {
        $this->roles = $roles;
    }
}

And when trying to persist that entity we get :

Neo4j Exception with code "Neo.ClientError.Statement.TypeError" and message "Property values can only be of primitive types or arrays thereof"

Multiple properties with the same relation ship name

I don't know if this is a bug or a feature request.

I can't have two properties with the same relationship name.

Type mismatch: rel_in_love_with already defined with conflicting type Collection<T> (expected Relationship) (line 3, column 22 (offset: 276))
"OPTIONAL MATCH (n)<-[rel_in_love_with:IN_LOVE_WITH]-(lovedBy) WITH n, rel_in_love_with, CASE count(rel_in_love_with) WHEN 0 THEN [] ELSE collect({start:startNode(rel_in_love_with), end:endNode(rel_in_love_with), rel:rel_in_love_with}) END as rel_in_love_with"
/**
 * @OGM\Relationship(type="IN_LOVE_WITH", direction="OUTGOING", targetEntity="User", collection=true)
 */
protected $loves;

/**
 * @OGM\Relationship(type="IN_LOVE_WITH", direction="INCOMING", targetEntity="User", collection=true)
 */
protected $lovedBy;

Also “BOTH” as a direction is referenced in the docs but not yet implemented.

Transaction is already bound to this session

Hi I'm getting the exception a transaction is already bound to this session when calling an $em->flush();

I have tried adding $em->clear() in several parts of the application but can't seem to solve this.

What could be the reason for this exception?

Can't persist changes to an entity when relationships exist

I'm following the demo, with great success, but I've come to a halt and I have no idea what the issue is.

I've come to this part, but can't get it to work:


// Find Tom Hanks, filter his movies to find Cast Away and rename it to Cast Away 2
/** @var Person $tomHanks */
$tomHanks = $manager->getRepository(Person::class)->findOneBy('name', 'Tom Hanks');
$filter = array_values(array_filter($tomHanks->getMovies()->toArray(), function(\Movies\Movie $movie) {
    return 'Cast Away' === $movie->getTitle();
}));

/** @var \Movies\Movie $castAway */
$castAway = $filter[0];
$castAway->setTitle('Cast Away 2');
$manager->flush();

If I echo $castAway->getTitle() I sure enough get "Cast Away 2", but the save is not actually persisted in the DB.

I've tried this on my own with both Movies and Persons and here are my findings:

  • When a movie or person has NO relationships, the change WORKS.
  • When a movie or person has relationships, the change DOES NOT WORK.

The original test code in /docs/_code/movies/Movie.php seems to have worked because of an incorrect directional mapping (OUTGOING vs INCOMING), which meant relationships were not actually populating. But when I make that change and they do populate, then the code stops working.

I don't know enough to know where to begin looking on this one. I did note that Movie.php does not have a mappedBy parameter on the relationship annotation for $actors, but when I put that in it didn't affect anything.

Any clues here?

Using a QueryBuilder to manage OR clauses

Found this library and it's allowing me to get my head round Neo4J a bit better, so thanks for that!

I've used Doctrine for a while and regularly use the query builder to build up datasets based on OR conditions in a SQL query (movie = 'The Matrix' OR movie='Finding Dory')

This may not be possible in Neo4J (i'm still learning as I go), but if it is. Is it possible with this library to do these complex matches?

Another example I'm looking at is getting an object depending on whether 1 of 2 properties is equal to a value

Attempt to call "addInit" of class "GraphAware\Neo4j\OGM\Common\Collection"

I've got this error a couple of times. I have not found the cause for it yet. Im writing this issue so I do not forget.

Error: Uncaught Symfony\Component\Debug\Exception\UndefinedMethodException: 
  Attempted to call an undefined method named "addInit" of class "GraphAware\Neo4j\OGM\Common\Collection". in /home/sites/xxx/releases/20161114162645/vendor/graphaware/neo4j-php-ogm/src/Repository/BaseRepository.php:745

Stack trace:
#0 /home/sites/xxx/releases/20161114162645/vendor/graphaware/neo4j-php-ogm/src/Repository/BaseRepository.php(429): GraphAware\Neo4j\OGM\Repository\BaseRepository->setInversedAssociation(Object(AppBundle\Entity\Location), Object(AppBundle\Entity\User), 'user')
#1 /home/sites/xxx/releases/20161114162645/vendor/graphaware/neo4j-php-ogm/src/Repository/BaseRepository.php(401): GraphAware\Neo4j\OGM\Repository\BaseRepository->hydrate(Object(GraphAware\Neo4j\Client\Formatter\RecordView))
#2 /home/sites/xxx/releases/20161114162645/vendor/graphaware/neo4j-php-ogm/src/Repository/BaseRepository.php(315): GraphAware\Neo4j\OGM\Repository\BaseRepo' in /home/sites/xxx/releases/20161114162645/vendor/graphaware/neo4j-php-ogm/src/Repository/BaseRepository.php:745

Move BasicEntityPersister to OMG\Persister

We have two namespaces GraphAware\Neo4j\OGM\Persister and GraphAware\Neo4j\OGM\Persisters. Generally namespaces should be in singular.
I suggest moving the the BasicEntityPersister to GraphAware\Neo4j\OGM\Persister

EAGER annotation on node relations

If we have @LAZY, we need doctrine like @EAGER too. In some cases it will be wery usefull to have autoloaded relations.

Example case: I have labels "Object", "FieldType", "Value" they are all interlinked. So whenever I want to make list of object values with corresponded field types, I must gather values from object, then get field types from object from other relation type, and then link values to types through foreach. Its very frustrating to do so, and prefetching field types with fields would be nice thing to have.

entityManager->createQuery() result improvements

It would be good if createQuery will support collect() cypher syntax and non-Node result parameters. Basically we need to merge new QueryResultMapping that supports inly nodes with old one, that supported basic types.

Error on create node with relationshipEntity

Hi,

when i try to create a node with relationshipEntity receive this errors

Expected node.props to be a map, but it was :`[]`

I have these model:

User

/**
 * @OGM\Node(label="User")
 */
class User
{
    /**
     * @OGM\GraphId()
     * @var int
     */
    protected $id;

    /**
     * @OGM\Property(type="string")
     * @var string
     */
    protected $first_name;

    /**
     * @OGM\Property(type="string")
     * @var string
     */
    protected $last_name;

    /**
     * @OGM\Property(type="string")
     * @var int
     */
    protected $email;

    /**
     * @OGM\Property(type="boolean")
     * @var boolean
     */
    protected $active;

    /**
     * @OGM\Property(type="string")
     * @var int
     */
    protected $password;

    /**
     * @OGM\Relationship(relationshipEntity="Manager", type="MANAGE", direction="OUTGOING", collection=true)
     * @var ArrayCollection|Page[]
     */
    protected $pages;

    public function __construct($first_name, $last_name, $email, $password, $active)
    {
        $this->first_name = $first_name;
        $this->last_name = $last_name;
        $this->email = $email;
        $this->password = bcrypt($password);
        $this->active = $active;
        $this->pages = new ArrayCollection();
    }

    /**
     * @param Page $page
     * @param OGM\Entity $entity
     */
    public function addPage(Page $page, OGM\Entity $entity)
    {
        $this->pages->add(new Manager($this, $page, $entity));
    }
}

Manager

/**
 * @OGM\RelationshipEntity(type="MANAGE")
 */
class Manager
{
    /**
     * @OGM\GraphId()
     * @var int
     */
    protected $id;

    /**
     * @OGM\StartNode(targetEntity="User")
     * @var User
     */
    protected $user;

    /**
     * @OGM\EndNode(targetEntity="Page")
     * @var Page
     */
    protected $page;

    protected $entity;

    /**
     * Manage constructor.
     * @param User $user
     * @param Page $page
     * @param OGM\Entity $entity
     */
    public function __construct(User $user, Page $page, OGM\Entity $entity)
    {
        $this->user = $user;
        $this->page = $page;
        $this->entity = $entity;
    }

    /**
     * @return int
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * @param int $id
     */
    public function setId($id)
    {
        $this->id = $id;
    }

    /**
     * @return User
     */
    public function getUser()
    {
        return $this->user;
    }

    /**
     * @return Page
     */
    public function getPage()
    {
        return $this->page;
    }

    /**
     * @return string
     */
    public function getEntity()
    {
        return $this->type;
    }

    /**
     * @param OGM\Entity $entity
     * @internal param string $type
     */
    public function setEntity(OGM\Entity $entity)
    {
        $this->entity = $entity;
    }
}

Page

/**
 * @OGM\Node(label="Page")
 */
class Page
{
    /**
     * @OGM\GraphId()
     * @var int
     */
    protected $id;
}

Artist (Entity)

class Artist implements OGM\Entity
{
    /**
     * @OGM\Property(type="string")
     * @var string
     */
    protected $name;

    /**
     * @OGM\Property(type="string")
     * @var string
     */
    protected $slug;

    /**
     * @OGM\Property(type="string")
     * @var string
     */
    protected $short_description;

    /**
     * @return string
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * @param string $name
     */
    public function setName($name)
    {
        $this->name = $name;
    }

    /**
     * @return string
     */
    public function getSlug()
    {
        return $this->slug;
    }

    /**
     * @param string $slug
     */
    public function setSlug($slug)
    {
        $this->slug = $slug;
    }

    /**
     * @return string
     */
    public function getShortDescription()
    {
        return $this->short_description;
    }

    /**
     * @param string $short_description
     */
    public function setShortDescription($short_description)
    {
        $this->short_description = $short_description;
    }
}

Example

$artist = new Artist;
$artist->setName('Artist Name');
$artist->setSlug('artist-name');
$artist->setShortDescription('This is a description');

$this->user->addPage(new Page);

$manager->persist($this->user);

$manager->flush();

Where am I doing wrong?
Thanks

Implement ObjectManager

Have EntityManager implement ObjectManager so that libraries like DoctrineModule can be used.

Inheritance Problem

Hello.

I have the following model:

abstract class Accessory {
   protected $name; //+getter and setters
   protected $photol; //+getter and setters
}

class Light extends Accessory {
   protected $on; //+getter and setters
}

class BrightnessLight extends Light {
   protected $brightness; //+getter and setters
}

class ColorLight extends BrgithnessLight {
  protected $red; //+getter and setters
  protected $green; //+getter and setters
  protected $blue; //+getter and setters
}

Now if I query the neo4j database for a color light accessory I receive the following object:

TestController.php on line 46:
neo4j_ogm_proxy_AppBundle_Entity_Accessory_Accessory {#561
  -em: null
  -initialized: []
  -initializers: []
  -node: GraphAware\Neo4j\Client\Formatter\Type\Node {#575
    #id: 75
    #labels: array:4 [
      0 => "Accessory"
      1 => "Light"
      2 => "BrightnessLight"
      3 => "ColorLight"
    ]
    #properties: array:7 [
      "red" => 0
      "green" => 0
      "brightness" => 95
      "blue" => 255
      "name" => "Color Light"
      "photo" => ""
      "on" => true
    ]
  }
  #id: 75
  #name: "Color Light"
  #photo: ""
}

As you can see I have 4 labels set on my color light: Accessory, Light, BrightnessLight, ColorLight.

I am able to call getId(), getName(), and getPhoto() on the object, however I cannot call getBrightness(), getRed(), getGreen() and getBlue().

Does the OGM support class inheritance yet ?

Remove simple relationship?

I can't figure out how to remove a simple relationship. I see in the docs how to remove a RelationshipEntity if it's provided for in the model, like it is with rating (Rating has it's own class). But what about the movie dataset. How do you do something like remove Tom Hanks from Cast Away if all you have are the Person and Movie classes? I've looked in the unit tests, and all I can see are the RelationshipEntity removal tests.

I've tried to do it manually by using the removeActor and/or removeMovie methods, but when I flush it either doesn't do anything, or I get an error like:

Error: Call to undefined method neo4j_ogm_proxy_GraphAware_Neo4j_OGM_Tests_Integration_Models_MoviesDemo_Person::removeMovie()

I've also tried removeElement on the arrayCollection. That seems to work for the current in-memory objects, but flushing won't make it persist.

Can you provide a unit test in tests/Integration/MovieDatasetTest.php which would demonstrate this?

Thank you so much!

Circular reference

I have an issue where my objects are referenced in a circle. When I try to persist one node we look through all the relationships and all nodes. Which means that they will find more nodes than is originally managed. This will eventually lead to Maximum function nesting level of '250' reached.

screen shot 2016-11-20 at 15 28 53

I think the solution will be to only persist nodes that are new or managed. Never explore unmanaged relations.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.