├── .gitignore ├── .travis.yml ├── LICENSE ├── Neo4jPhpVersionTask.php ├── README.md ├── build.xml ├── composer.json ├── docblox.dist.xml ├── examples ├── bacon.php ├── batch_benchmarks.php ├── cypher.php ├── directions.php ├── example_bootstrap.php ├── gremlin.php ├── indexing.php └── widgets.php ├── lib └── Everyman │ └── Neo4j │ ├── Batch.php │ ├── Batch │ ├── AddTo.php │ ├── Delete.php │ ├── Operation.php │ ├── RemoveFrom.php │ └── Save.php │ ├── Cache.php │ ├── Cache │ ├── EntityCache.php │ ├── Memcache.php │ ├── Memcached.php │ ├── None.php │ └── Variable.php │ ├── Client.php │ ├── Command.php │ ├── Command │ ├── AddLabels.php │ ├── AddStatementsToTransaction.php │ ├── AddToIndex.php │ ├── Batch │ │ ├── AddToIndex.php │ │ ├── Command.php │ │ ├── Commit.php │ │ ├── CreateNode.php │ │ ├── CreateRelationship.php │ │ ├── DeleteNode.php │ │ ├── DeleteRelationship.php │ │ ├── RemoveFromIndex.php │ │ ├── UpdateNode.php │ │ └── UpdateRelationship.php │ ├── CreateNode.php │ ├── CreateRelationship.php │ ├── DeleteIndex.php │ ├── DeleteNode.php │ ├── DeleteRelationship.php │ ├── ExecuteCypherQuery.php │ ├── ExecuteGremlinQuery.php │ ├── ExecutePagedTraversal.php │ ├── ExecuteTraversal.php │ ├── GetIndexes.php │ ├── GetLabels.php │ ├── GetNode.php │ ├── GetNodeRelationships.php │ ├── GetNodesForLabel.php │ ├── GetPaths.php │ ├── GetRelationship.php │ ├── GetRelationshipTypes.php │ ├── GetServerInfo.php │ ├── QueryIndex.php │ ├── RemoveFromIndex.php │ ├── RemoveLabels.php │ ├── RollbackTransaction.php │ ├── SaveIndex.php │ ├── SearchIndex.php │ ├── SetLabels.php │ ├── UpdateNode.php │ └── UpdateRelationship.php │ ├── Cypher │ └── Query.php │ ├── EntityMapper.php │ ├── Exception.php │ ├── Geoff.php │ ├── Geoff │ ├── Exporter.php │ └── Importer.php │ ├── Gremlin │ └── Query.php │ ├── Index.php │ ├── Index │ ├── NodeFulltextIndex.php │ ├── NodeIndex.php │ └── RelationshipIndex.php │ ├── Label.php │ ├── Node.php │ ├── Pager.php │ ├── Path.php │ ├── PathFinder.php │ ├── PropertyContainer.php │ ├── Query.php │ ├── Query │ ├── ResultSet.php │ └── Row.php │ ├── Relationship.php │ ├── Transaction.php │ ├── Transport.php │ ├── Transport │ ├── Curl.php │ └── Stream.php │ ├── Traversal.php │ └── Version.php ├── phpconfig.ini ├── stub.php └── tests ├── cs └── ruleset.xml ├── phpunit.xml └── unit └── lib └── Everyman └── Neo4j ├── BatchTest.php ├── Cache ├── MemcacheTest.php ├── MemcachedTest.php ├── NoneTest.php └── VariableTest.php ├── ClientTest.php ├── Client_Batch_IndexTest.php ├── Client_Batch_NodeTest.php ├── Client_Batch_RelationshipTest.php ├── Client_CacheTest.php ├── Client_CypherTest.php ├── Client_GremlinTest.php ├── Client_IndexTest.php ├── Client_LabelTest.php ├── Client_PathTest.php ├── Client_TransactionTest.php ├── Client_TraversalTest.php ├── Cypher └── QueryTest.php ├── EntityMapperTest.php ├── GeoffTest.php ├── Gremlin └── QueryTest.php ├── IndexTest.php ├── LabelTest.php ├── NodeTest.php ├── PagerTest.php ├── PathFinderTest.php ├── PathTest.php ├── PropertyContainerTest.php ├── Query ├── ResultSetTest.php └── RowTest.php ├── RelationshipTest.php ├── TransactionTest.php ├── TransportTest.php └── TraversalTest.php /.gitignore: -------------------------------------------------------------------------------- 1 | neo4jphp.phar 2 | build 3 | docs 4 | vendor/ 5 | /.idea/ 6 | composer.lock -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | php: 3 | - 5.3 4 | - 5.4 5 | - 5.5 6 | 7 | before_script: 8 | - pecl install -f memcached-2.1.0 9 | - phpenv config-add phpconfig.ini 10 | - composer install --dev 11 | 12 | script: ./vendor/bin/phing ci 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | All project code is licensed under the MIT License 2 | http://www.opensource.org/licenses/mit-license.php 3 | 4 | Copyright (c) 2011 Josh Adell 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /Neo4jPhpVersionTask.php: -------------------------------------------------------------------------------- 1 | property = $name; 13 | } 14 | 15 | public function main() 16 | { 17 | $version = \Everyman\Neo4j\Version::CURRENT; 18 | $this->log("neo4jphp version: $version"); 19 | $this->project->setProperty($this->property, $version); 20 | } 21 | } -------------------------------------------------------------------------------- /build.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "everyman/neo4jphp", 3 | "type": "library", 4 | "description": "Wrapper for the Neo4j graph database REST interface", 5 | "keywords": ["neo4j","graph","database"], 6 | "homepage": "http://github.com/jadell/neo4jphp/wiki", 7 | "license": "MIT", 8 | "authors": [ 9 | {"name": "Josh Adell", "email": "josh.adell@gmail.com", "homepage": "http://joshadell.com"} 10 | ], 11 | "require": { 12 | "php": ">=5.3.0", 13 | "ext-curl": "*" 14 | }, 15 | "require-dev": { 16 | "phing/phing": "2.6.*", 17 | "phpunit/phpunit": "3.7.*", 18 | "squizlabs/php_codesniffer": "1.5.*" 19 | }, 20 | "autoload": { 21 | "psr-0": {"Everyman\\Neo4j":"lib/"} 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /docblox.dist.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | lib 5 | 6 | 7 | docs 8 | 9 | 10 | docs 11 | 12 | -------------------------------------------------------------------------------- /examples/bacon.php: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | 24 | Find a path from one actor to another. 25 | 26 | 27 | HELP; 28 | exit(0); 29 | } 30 | 31 | $client = new Client(); 32 | $actors = new NodeIndex($client, 'actors'); 33 | 34 | // Initialize the data 35 | if ($cmd == 'init') { 36 | $keanu = $client->makeNode()->setProperty('name', 'Keanu Reeves')->save(); 37 | $laurence = $client->makeNode()->setProperty('name', 'Laurence Fishburne')->save(); 38 | $jennifer = $client->makeNode()->setProperty('name', 'Jennifer Connelly')->save(); 39 | $kevin = $client->makeNode()->setProperty('name', 'Kevin Bacon')->save(); 40 | 41 | $actors->add($keanu, 'name', $keanu->getProperty('name')); 42 | $actors->add($laurence, 'name', $laurence->getProperty('name')); 43 | $actors->add($jennifer, 'name', $jennifer->getProperty('name')); 44 | $actors->add($kevin, 'name', $kevin->getProperty('name')); 45 | 46 | $matrix = $client->makeNode()->setProperty('title', 'The Matrix')->save(); 47 | $higherLearning = $client->makeNode()->setProperty('title', 'Higher Learning')->save(); 48 | $mysticRiver = $client->makeNode()->setProperty('title', 'Mystic River')->save(); 49 | 50 | $keanu->relateTo($matrix, 'IN')->save(); 51 | $laurence->relateTo($matrix, 'IN')->save(); 52 | 53 | $laurence->relateTo($higherLearning, 'IN')->save(); 54 | $jennifer->relateTo($higherLearning, 'IN')->save(); 55 | 56 | $laurence->relateTo($mysticRiver, 'IN')->save(); 57 | $kevin->relateTo($mysticRiver, 'IN')->save(); 58 | 59 | // Find a path 60 | } else if ($cmd == 'path' && !empty($argv[2]) && !empty($argv[3])) { 61 | $from = $argv[2]; 62 | $to = $argv[3]; 63 | 64 | $fromNode = $actors->findOne('name', $from); 65 | if (!$fromNode) { 66 | echo "$from not found\n"; 67 | exit(1); 68 | } 69 | 70 | $toNode = $actors->findOne('name', $to); 71 | if (!$toNode) { 72 | echo "$to not found\n"; 73 | exit(1); 74 | } 75 | 76 | // Each degree is an actor and movie node 77 | $maxDegrees = 6; 78 | $depth = $maxDegrees * 2; 79 | 80 | $path = $fromNode->findPathsTo($toNode) 81 | ->setmaxDepth($depth) 82 | ->getSinglePath(); 83 | 84 | if ($path) { 85 | foreach ($path as $i => $node) { 86 | if ($i % 2 == 0) { 87 | $degree = $i/2; 88 | echo str_repeat("\t", $degree); 89 | echo $degree . ': ' .$node->getProperty('name'); 90 | if ($i+1 != count($path)) { 91 | echo " was in "; 92 | } 93 | } else { 94 | echo $node->getProperty('title') . " with\n"; 95 | } 96 | } 97 | echo "\n"; 98 | } 99 | } 100 | 101 | -------------------------------------------------------------------------------- /examples/batch_benchmarks.php: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | benchmark($series, $runs); 31 | } 32 | 33 | //////////////////////////////////////////////////////////////////////////////// 34 | // Benchmark trials /////////////////////////////////////////////////////////// 35 | ////////////////////////////////////////////////////////////////////////////// 36 | 37 | abstract class Benchmark 38 | { 39 | protected $client = null; 40 | protected $title = 'unknown'; 41 | 42 | abstract protected function batch($size); 43 | abstract protected function sequential($size); 44 | 45 | public function __construct(Client $client) 46 | { 47 | $this->client = $client; 48 | } 49 | 50 | public function benchmark($series, $runs) 51 | { 52 | echo "Benchmark: {$this->title}\n"; 53 | foreach ($series as $size) { 54 | $batchTotal = 0; 55 | $seqTotal = 0; 56 | for ($i=0; $i<$runs; $i++) { 57 | echo "{$size}\t{$i}\t"; 58 | 59 | $batchTotal += $batchTime = $this->batch($size); 60 | echo "{$batchTime}\t"; 61 | 62 | $seqTotal += $seqTime = $this->sequential($size); 63 | echo "{$seqTime}\n"; 64 | } 65 | $batchAvg = round($batchTotal/$runs,2); 66 | $seqAvg = round($seqTotal/$runs,2); 67 | echo "\t\t$batchAvg\t$seqAvg\n\n"; 68 | } 69 | 70 | } 71 | } 72 | 73 | class CreateNode extends Benchmark 74 | { 75 | protected $title = 'Create nodes'; 76 | 77 | protected function batch($size) 78 | { 79 | $start = time(); 80 | $this->client->startBatch(); 81 | foreach(range(1, $size) as $id) { 82 | $this->client->makeNode()->setProperty('stop_id', $id)->save(); 83 | } 84 | $this->client->commitBatch(); 85 | $end = time(); 86 | return $end - $start; 87 | } 88 | 89 | protected function sequential($size) 90 | { 91 | $start = time(); 92 | foreach(range(1, $size) as $id) { 93 | $this->client->makeNode()->setProperty('stop_id', $id)->save(); 94 | } 95 | $end = time(); 96 | return $end - $start; 97 | } 98 | } 99 | 100 | class CreateRelationship extends Benchmark 101 | { 102 | protected $title = 'Create relationships'; 103 | 104 | protected function batch($size) 105 | { 106 | $nodeA = $this->client->makeNode()->save(); 107 | $nodeB = $this->client->makeNode()->save(); 108 | 109 | $start = time(); 110 | $this->client->startBatch(); 111 | foreach(range(1, $size) as $id) { 112 | $nodeA->relateTo($nodeB, 'TEST')->setProperty('stop_id', $id)->save(); 113 | } 114 | $this->client->commitBatch(); 115 | $end = time(); 116 | return $end - $start; 117 | } 118 | 119 | protected function sequential($size) 120 | { 121 | $nodeA = $this->client->makeNode()->save(); 122 | $nodeB = $this->client->makeNode()->save(); 123 | 124 | $start = time(); 125 | foreach(range(1, $size) as $id) { 126 | $nodeA->relateTo($nodeB, 'TEST')->setProperty('stop_id', $id)->save(); 127 | } 128 | $end = time(); 129 | return $end - $start; 130 | } 131 | } 132 | 133 | class CreateFullRelationship extends Benchmark 134 | { 135 | protected $title = 'Create full relationships (start node, end node, relationship)'; 136 | 137 | protected function batch($size) 138 | { 139 | $start = time(); 140 | $this->client->startBatch(); 141 | foreach(range(1, $size) as $id) { 142 | $nodeA = $this->client->makeNode()->save(); 143 | $nodeB = $this->client->makeNode()->save(); 144 | $nodeA->relateTo($nodeB, 'TEST')->setProperty('stop_id', $id)->save(); 145 | } 146 | $this->client->commitBatch(); 147 | $end = time(); 148 | return $end - $start; 149 | } 150 | 151 | protected function sequential($size) 152 | { 153 | $start = time(); 154 | foreach(range(1, $size) as $id) { 155 | $nodeA = $this->client->makeNode()->save(); 156 | $nodeB = $this->client->makeNode()->save(); 157 | $nodeA->relateTo($nodeB, 'TEST')->setProperty('stop_id', $id)->save(); 158 | } 159 | $end = time(); 160 | return $end - $start; 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /examples/cypher.php: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | 23 | Get a list of all actors in the movie. 24 | 25 | 26 | HELP; 27 | exit(0); 28 | } 29 | 30 | $client = new Client(); 31 | $actors = new NodeIndex($client, 'actors'); 32 | 33 | // Initialize the data 34 | if ($cmd == 'init') { 35 | $keanu = $client->makeNode()->setProperty('name', 'Keanu Reeves')->save(); 36 | $laurence = $client->makeNode()->setProperty('name', 'Laurence Fishburne')->save(); 37 | $jennifer = $client->makeNode()->setProperty('name', 'Jennifer Connelly')->save(); 38 | $kevin = $client->makeNode()->setProperty('name', 'Kevin Bacon')->save(); 39 | 40 | $actors->add($keanu, 'name', $keanu->getProperty('name')); 41 | $actors->add($laurence, 'name', $laurence->getProperty('name')); 42 | $actors->add($jennifer, 'name', $jennifer->getProperty('name')); 43 | $actors->add($kevin, 'name', $kevin->getProperty('name')); 44 | 45 | $matrix = $client->makeNode()->setProperty('title', 'The Matrix')->save(); 46 | $higherLearning = $client->makeNode()->setProperty('title', 'Higher Learning')->save(); 47 | $mysticRiver = $client->makeNode()->setProperty('title', 'Mystic River')->save(); 48 | 49 | $keanu->relateTo($matrix, 'IN')->save(); 50 | $laurence->relateTo($matrix, 'IN')->save(); 51 | 52 | $laurence->relateTo($higherLearning, 'IN')->save(); 53 | $jennifer->relateTo($higherLearning, 'IN')->save(); 54 | 55 | $laurence->relateTo($mysticRiver, 'IN')->save(); 56 | $kevin->relateTo($mysticRiver, 'IN')->save(); 57 | 58 | // Find all actors in a movie 59 | } else if ($cmd == 'actors') { 60 | 61 | if(!empty($argv[2])) { 62 | $movie = implode(" ", array_slice($argv,2)); 63 | } else { 64 | $movie = "The Matrix"; 65 | } 66 | 67 | $queryTemplate = "START actor=node:actors('name:*') ". 68 | "MATCH (actor) -[:IN]- (movie)". 69 | "WHERE movie.title = {title}". 70 | "RETURN actor"; 71 | $query = new Cypher\Query($client, $queryTemplate, array('title'=>$movie)); 72 | $result = $query->getResultSet(); 73 | 74 | echo "Found ".count($result)." actors:\n"; 75 | foreach($result as $row) { 76 | echo " ".$row['actor']->getProperty('name')."\n"; 77 | } 78 | } 79 | 80 | -------------------------------------------------------------------------------- /examples/example_bootstrap.php: -------------------------------------------------------------------------------- 1 | makeNode()->setProperty('name', 'Keanu Reeves')->save(); 35 | $laurence = $client->makeNode()->setProperty('name', 'Laurence Fishburne')->save(); 36 | $jennifer = $client->makeNode()->setProperty('name', 'Jennifer Connelly')->save(); 37 | $kevin = $client->makeNode()->setProperty('name', 'Kevin Bacon')->save(); 38 | 39 | $actors->add($keanu, 'name', $keanu->getProperty('name')); 40 | $actors->add($laurence, 'name', $laurence->getProperty('name')); 41 | $actors->add($jennifer, 'name', $jennifer->getProperty('name')); 42 | $actors->add($kevin, 'name', $kevin->getProperty('name')); 43 | 44 | $matrix = $client->makeNode()->setProperty('title', 'The Matrix')->save(); 45 | $higherLearning = $client->makeNode()->setProperty('title', 'Higher Learning')->save(); 46 | $mysticRiver = $client->makeNode()->setProperty('title', 'Mystic River')->save(); 47 | 48 | $keanu->relateTo($matrix, 'IN')->save(); 49 | $laurence->relateTo($matrix, 'IN')->save(); 50 | 51 | $laurence->relateTo($higherLearning, 'IN')->save(); 52 | $jennifer->relateTo($higherLearning, 'IN')->save(); 53 | 54 | $laurence->relateTo($mysticRiver, 'IN')->save(); 55 | $kevin->relateTo($mysticRiver, 'IN')->save(); 56 | 57 | // Find all actors in a movie 58 | } else if ($cmd == 'actors') { 59 | $queryTemplate = "g.V.in(type).dedup.sort{it.name}.toList()"; 60 | $params = array('type' => 'IN'); 61 | $query = new Gremlin\Query($client, $queryTemplate, $params); 62 | $result = $query->getResultSet(); 63 | 64 | foreach ($result as $row) { 65 | echo "* " . $row[0]->getProperty('name')."\n"; 66 | } 67 | } 68 | 69 | -------------------------------------------------------------------------------- /examples/indexing.php: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | save(); 18 | 19 | $leslie = $client->makeNode() 20 | ->setProperty('name', 'Leslie Nielsen') 21 | ->save(); 22 | 23 | $airplane = $client->makeNode() 24 | ->setProperty('title', 'Airplane') 25 | ->save(); 26 | 27 | $rumack = $leslie->relateTo($airplane, 'PLAYED') 28 | ->setProperty('character', 'Dr. Rumack') 29 | ->save(); 30 | 31 | $actorIndex->add($leslie, 'name', $leslie->getProperty('name')); 32 | $roleIndex->add($rumack, 'character', $rumack->getProperty('character')); 33 | $plotIndex->add($airplane, 'synopsis', 'An airplane crew takes ill. Surely the only person capable of landing the plane is an ex-pilot afraid to fly. But don\'t call him Shirley.'); 34 | 35 | echo $actorIndex->queryOne('name:Leslie*')->getProperty('name') . "\n"; 36 | echo $roleIndex->queryOne('character:*u*')->getProperty('character') . "\n"; 37 | echo $plotIndex->queryOne('synopsis:lend~0.2')->getProperty('title') . "\n"; 38 | 39 | 40 | -------------------------------------------------------------------------------- /examples/widgets.php: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | [] 32 | Find all the stores where the given part was sold. 33 | Language can be one of: 34 | traverse: use the javascript traversal. Default. 35 | cypher: use a cypher query 36 | 37 | 38 | HELP; 39 | exit(0); 40 | } 41 | 42 | $client = new Client(); 43 | $partsIndex = new NodeIndex($client, 'parts3'); 44 | 45 | $parts = array('widget','gadget','gizmo'); 46 | $stores = array("Bob's Old Houseware","Mainstreet Hardware","Nutz N' Boltz", "Doodad Emporium"); 47 | // Store, part list 48 | $orders = array( 49 | array(0, array(0,1)), 50 | array(0, array(1)), 51 | array(1, array(1,2)), 52 | array(1, array(0,2)), 53 | array(2, array(0,1,2)), 54 | array(3, array(2)), 55 | array(3, array(0)), 56 | ); 57 | 58 | // Initialize the data 59 | if ($cmd == 'init') { 60 | echo "Initializing data.\n"; 61 | $p = array(); 62 | $s = array(); 63 | 64 | foreach ($parts as $part) { 65 | $node = $client->makeNode()->setProperty('name', $part)->save(); 66 | $partsIndex->add($node, 'name', $node->getProperty('name')); 67 | $p[] = $node; 68 | } 69 | 70 | foreach ($stores as $store) { 71 | $node = $client->makeNode()->setProperty('name', $store)->save(); 72 | $s[] = $node; 73 | } 74 | 75 | foreach ($orders as $order) { 76 | $node = $client->makeNode()->save(); 77 | 78 | $s[$order[0]]->relateTo($node, 'SOLD')->save(); 79 | foreach ($order[1] as $pi) { 80 | $node->relateTo($p[$pi], 'CONTAINS')->save(); 81 | } 82 | } 83 | 84 | // List parts 85 | } else if ($cmd == 'parts') { 86 | $partsList = $partsIndex->query('name:*'); 87 | foreach ($partsList as $part) { 88 | echo "* {$part->getProperty('name')}\n"; 89 | } 90 | 91 | // Find stores where the part was sold 92 | } else if ($cmd == 'stores' && !empty($argv[2])) { 93 | $partName = $argv[2]; 94 | 95 | // Use the Cypher query language 96 | if (!empty($argv[3]) && $argv[3] == 'cypher') { 97 | $queryTemplate = "START part=node:parts3('name:{$partName}') ". 98 | "MATCH (store)-[:SOLD]->()-[:CONTAINS]->(part) ". 99 | // Use the count(*) to force distinct values until Cypher gets DISTINCT keyword support 100 | "RETURN store, count(*)"; 101 | $query = new Cypher\Query($client, $queryTemplate); 102 | $result = $query->getResultSet(); 103 | 104 | echo "Found ".count($result)." stores:\n"; 105 | foreach($result as $row) { 106 | echo "* ".$row['store']->getProperty('name')."\n"; 107 | } 108 | 109 | // Use javascript traversal 110 | } else { 111 | $part = $partsIndex->findOne('name', $partName); 112 | if (!$part) { 113 | die("{$partName} not found.\n"); 114 | } 115 | 116 | $traversal = new Traversal($client); 117 | $traversal->addRelationship('CONTAINS', Relationship::DirectionIn) 118 | ->addRelationship('SOLD', Relationship::DirectionIn) 119 | ->setMaxDepth(4) 120 | ->setReturnFilter('javascript', '(position.length() > 0 && position.lastRelationship().getType() == "SOLD");'); 121 | 122 | $stores = $traversal->getResults($part, Traversal::ReturnTypeNode); 123 | echo "Found ".count($stores)." stores:\n"; 124 | foreach ($stores as $store) { 125 | echo "* {$store->getProperty('name')}\n"; 126 | } 127 | } 128 | } 129 | 130 | 131 | 132 | -------------------------------------------------------------------------------- /lib/Everyman/Neo4j/Batch.php: -------------------------------------------------------------------------------- 1 | client = $client; 23 | } 24 | 25 | /** 26 | * Add the given entity to the given index with the given key/value 27 | * 28 | * @param Index $index 29 | * @param PropertyContainer $entity 30 | * @param string $key 31 | * @param string $value 32 | * @return integer 33 | */ 34 | public function addToIndex(Index $index, PropertyContainer $entity, $key, $value) 35 | { 36 | return $this->addOperation(new Batch\AddTo($this, $index, $entity, $key, $value, $this->nextId())); 37 | } 38 | 39 | /** 40 | * Commit the batch to the server 41 | * 42 | * @return boolean 43 | */ 44 | public function commit() 45 | { 46 | if ($this->committed) { 47 | throw new Exception('Cannot commit the same batch more than once.'); 48 | } 49 | $this->committed = true; 50 | 51 | return $this->client->commitBatch($this); 52 | } 53 | 54 | /** 55 | * Add an entity to the batch to delete 56 | * 57 | * @param PropertyContainer $entity 58 | * @return integer 59 | */ 60 | public function delete(PropertyContainer $entity) 61 | { 62 | return $this->addOperation(new Batch\Delete($this, $entity, $this->nextId())); 63 | } 64 | 65 | /** 66 | * Get the batch's client 67 | * 68 | * @return Client 69 | */ 70 | public function getClient() 71 | { 72 | return $this->client; 73 | } 74 | 75 | /** 76 | * Return the list of operations in this batch 77 | * 78 | * @return array 79 | */ 80 | public function getOperations() 81 | { 82 | return $this->operations; 83 | } 84 | 85 | /** 86 | * Remove the given entity from the given index with the given key/value 87 | * 88 | * @param Index $index 89 | * @param PropertyContainer $entity 90 | * @param string $key 91 | * @param string $value 92 | * @return integer 93 | */ 94 | public function removeFromIndex(Index $index, PropertyContainer $entity, $key=null, $value=null) 95 | { 96 | return $this->addOperation(new Batch\RemoveFrom($this, $index, $entity, $key, $value, $this->nextId())); 97 | } 98 | 99 | /** 100 | * Reserve an operation to prevent it from being double-committed 101 | * Once an operation has been reserved, future reserve calls will 102 | * return false, indicating it has already been reserved. 103 | * This is mostly useful during commit to prevent an operation being 104 | * sent twice 105 | * 106 | * @param integer $opId 107 | * @return mixed array operation if not yet reserved, false otherwise 108 | */ 109 | public function reserve($opId) 110 | { 111 | if (isset($this->operations[$opId]) && $this->operations[$opId]->reserve()) { 112 | return $this->operations[$opId]; 113 | } 114 | return false; 115 | } 116 | 117 | /** 118 | * Add an entity to the batch to save 119 | * 120 | * @param PropertyContainer $entity 121 | * @return integer 122 | */ 123 | public function save(PropertyContainer $entity) 124 | { 125 | return $this->addOperation(new Batch\Save($this, $entity, $this->nextId())); 126 | } 127 | 128 | /** 129 | * Add an operation to the batch 130 | * 131 | * @param Batch\Operation $operation 132 | * @return integer operation index 133 | */ 134 | protected function addOperation(Batch\Operation $operation) 135 | { 136 | $opId = $operation->getId(); 137 | $matchId = $operation->matchId(); 138 | 139 | if (isset($this->matches[$matchId])) { 140 | return $this->matches[$matchId]->getId(); 141 | } 142 | 143 | $this->operations[$opId] = $operation; 144 | $this->matches[$matchId] = $operation; 145 | return $opId; 146 | } 147 | 148 | /** 149 | * Get the next unused id 150 | * 151 | * @return integer 152 | */ 153 | protected function nextId() 154 | { 155 | return count($this->operations); 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /lib/Everyman/Neo4j/Batch/AddTo.php: -------------------------------------------------------------------------------- 1 | index = $index; 33 | $this->key = $key; 34 | $this->value = $value; 35 | } 36 | 37 | /** 38 | * Get the command that represents this operation 39 | * 40 | * @return Batch\Command 41 | */ 42 | public function getCommand() 43 | { 44 | if (!$this->command) { 45 | $this->command = new Command\AddToIndex( 46 | $this->batch->getClient(), 47 | $this->index, 48 | $this->entity, 49 | $this->key, 50 | $this->value, 51 | $this->opId, 52 | $this->batch 53 | ); 54 | } 55 | return $this->command; 56 | } 57 | 58 | /** 59 | * Get the index 60 | * 61 | * @return Index 62 | */ 63 | public function getIndex() 64 | { 65 | return $this->index; 66 | } 67 | 68 | /** 69 | * Get the key being indexed 70 | * 71 | * @return string 72 | */ 73 | public function getKey() 74 | { 75 | return $this->key; 76 | } 77 | 78 | /** 79 | * Get the value being indexed 80 | * 81 | * @return mixed 82 | */ 83 | public function getValue() 84 | { 85 | return $this->value; 86 | } 87 | 88 | /** 89 | * Based on this operations parameters, generate a consistent id 90 | * 91 | * @return mixed 92 | */ 93 | public function matchId() 94 | { 95 | return parent::matchId() . spl_object_hash($this->index) . $this->key . $this->value; 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /lib/Everyman/Neo4j/Batch/Delete.php: -------------------------------------------------------------------------------- 1 | command) { 37 | $entity = $this->entity; 38 | $command = null; 39 | if ($entity instanceof Node) { 40 | $command = new Command\DeleteNode($this->batch->getClient(), $entity, $this->opId); 41 | } else if ($entity instanceof Relationship) { 42 | $command = new Command\DeleteRelationship($this->batch->getClient(), $entity, $this->opId); 43 | } 44 | 45 | $this->command = $command; 46 | } 47 | return $this->command; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /lib/Everyman/Neo4j/Batch/Operation.php: -------------------------------------------------------------------------------- 1 | batch = $batch; 30 | $this->operation = $operation; 31 | $this->entity = $entity; 32 | $this->opId = $opId; 33 | } 34 | 35 | /** 36 | * Get the underlying batch command for this operation 37 | * 38 | * @return Batch\Command 39 | */ 40 | abstract public function getCommand(); 41 | 42 | /** 43 | * Return the associated entity 44 | * 45 | * @return PropertyContainer 46 | */ 47 | public function getEntity() 48 | { 49 | return $this->entity; 50 | } 51 | 52 | /** 53 | * Get the operation id 54 | * 55 | * @return integer 56 | */ 57 | public function getId() 58 | { 59 | return $this->opId; 60 | } 61 | 62 | /** 63 | * Based on this operations parameters, generate a consistent id 64 | * 65 | * @return mixed 66 | */ 67 | public function matchId() 68 | { 69 | return $this->operation . spl_object_hash($this->entity); 70 | } 71 | 72 | /** 73 | * Reserve this operation to prevent it from being double-committed 74 | * Once an operation has been reserved, future reserve calls will 75 | * return false, indicating it has already been reserved. 76 | * This is mostly useful during commit to prevent an operation being 77 | * sent twice 78 | * 79 | * @return boolean true if reservation succeeded 80 | */ 81 | public function reserve() 82 | { 83 | if (!$this->reserved) { 84 | $this->reserved = true; 85 | return true; 86 | } 87 | return false; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /lib/Everyman/Neo4j/Batch/RemoveFrom.php: -------------------------------------------------------------------------------- 1 | index = $index; 33 | $this->key = $key; 34 | $this->value = $value; 35 | } 36 | 37 | /** 38 | * Get the command that represents this operation 39 | * 40 | * @return Batch\Command 41 | */ 42 | public function getCommand() 43 | { 44 | if (!$this->command) { 45 | $this->command = new Command\RemoveFromIndex( 46 | $this->batch->getClient(), 47 | $this->index, 48 | $this->entity, 49 | $this->key, 50 | $this->value, 51 | $this->opId 52 | ); 53 | } 54 | return $this->command; 55 | } 56 | 57 | /** 58 | * Based on this operations parameters, generate a consistent id 59 | * 60 | * @return mixed 61 | */ 62 | public function matchId() 63 | { 64 | return parent::matchId() . spl_object_hash($this->index) . $this->key . $this->value; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /lib/Everyman/Neo4j/Batch/Save.php: -------------------------------------------------------------------------------- 1 | command) { 37 | $entity = $this->entity; 38 | $command = null; 39 | if (!$entity->hasId()) { 40 | if ($entity instanceof Node) { 41 | $command = new Command\CreateNode($this->batch->getClient(), $entity, $this->opId); 42 | } else if ($entity instanceof Relationship) { 43 | $command = new Command\CreateRelationship($this->batch->getClient(), $entity, $this->opId, $this->batch); 44 | } 45 | } else { 46 | if ($entity instanceof Node) { 47 | $command = new Command\UpdateNode($this->batch->getClient(), $entity, $this->opId); 48 | } else if ($entity instanceof Relationship) { 49 | $command = new Command\UpdateRelationship($this->batch->getClient(), $entity, $this->opId); 50 | } 51 | } 52 | 53 | $this->command = $command; 54 | } 55 | return $this->command; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /lib/Everyman/Neo4j/Cache.php: -------------------------------------------------------------------------------- 1 | client = $client; 30 | $this->setCache($cache, $cacheTimeout); 31 | } 32 | 33 | /** 34 | * Delete an entity from the cache 35 | * 36 | * @param PropertyContainer $entity 37 | */ 38 | public function deleteCachedEntity(PropertyContainer $entity) 39 | { 40 | $this->getCache()->delete($this->getEntityCacheKey($entity)); 41 | } 42 | 43 | /** 44 | * Get an entity from the cache 45 | * 46 | * @param integer $id 47 | * @param string $type 48 | */ 49 | public function getCachedEntity($id, $type) 50 | { 51 | if ($type != 'node' && $type != 'relationship') { 52 | throw new Exception('Unknown entity type: '.$type); 53 | } 54 | 55 | $entity = $this->getCache()->get("{$type}-{$id}"); 56 | if ($entity) { 57 | $entity->setClient($this->client); 58 | } 59 | return $entity; 60 | } 61 | 62 | /** 63 | * Set the cache to use 64 | * 65 | * @param Cache $cache 66 | * @param integer $cacheTimeout 67 | */ 68 | public function setCache(Cache $cache=null, $cacheTimeout=null) 69 | { 70 | $this->cache = $cache; 71 | $this->cacheTimeout = (int)$cacheTimeout; 72 | } 73 | 74 | /** 75 | * Set an entity in the cache 76 | * 77 | * @param PropertyContainer $entity 78 | */ 79 | public function setCachedEntity(PropertyContainer $entity) 80 | { 81 | $this->getCache()->set($this->getEntityCacheKey($entity), $entity, $this->cacheTimeout); 82 | } 83 | 84 | /** 85 | * Get the cache plugin 86 | * 87 | * @return Cache 88 | */ 89 | protected function getCache() 90 | { 91 | if ($this->cache === null) { 92 | $this->setCache(new Cache\None(), $this->cacheTimeout); 93 | } 94 | return $this->cache; 95 | } 96 | 97 | /** 98 | * Determine the cache key used to retrieve the given entity from the cache 99 | * 100 | * @param PropertyContainer $entity 101 | * @return string 102 | */ 103 | protected function getEntityCacheKey(PropertyContainer $entity) 104 | { 105 | if ($entity instanceof Node) { 106 | return 'node-'.$entity->getId(); 107 | } else if ($entity instanceof Relationship) { 108 | return 'relationship-'.$entity->getId(); 109 | } 110 | throw new Exception('Unknown entity type: '.get_class($entity)); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /lib/Everyman/Neo4j/Cache/Memcache.php: -------------------------------------------------------------------------------- 1 | memcache = $memcache; 21 | } 22 | 23 | /** 24 | * Delete a value from the cache 25 | * 26 | * @param string $key 27 | * @return boolean true on success 28 | */ 29 | public function delete($key) 30 | { 31 | return $this->memcache->delete($key); 32 | } 33 | 34 | /** 35 | * Retrieve a value 36 | * Returns false if the key does not 37 | * exist, or the value is false 38 | * 39 | * @param string $key 40 | * @return mixed 41 | */ 42 | public function get($key) 43 | { 44 | return $this->memcache->get($key); 45 | } 46 | 47 | /** 48 | * Store a value in the cache 49 | * $expire is specified as an integer: 50 | * - less than or equal to 2592000 (the number of seconds in 30 days) 51 | * will be considered an expire time of that many seconds from the 52 | * current timestamp 53 | * - Greater than that amount will be considered as literal Unix 54 | * timestamp values 55 | * - 0 means "never expire." 56 | * 57 | * @param string $key 58 | * @param mixed $value 59 | * @param integer $expire 60 | * @return boolean true on success 61 | */ 62 | public function set($key, $value, $expire=0) 63 | { 64 | return $this->memcache->set($key, $value, 0, $expire); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /lib/Everyman/Neo4j/Cache/Memcached.php: -------------------------------------------------------------------------------- 1 | memcached = $memcached; 21 | } 22 | 23 | /** 24 | * Delete a value from the cache 25 | * 26 | * @param string $key 27 | * @return boolean true on success 28 | */ 29 | public function delete($key) 30 | { 31 | return $this->memcached->delete($key); 32 | } 33 | 34 | /** 35 | * Retrieve a value 36 | * Returns false if the key does not 37 | * exist, or the value is false 38 | * 39 | * @param string $key 40 | * @return mixed 41 | */ 42 | public function get($key) 43 | { 44 | return $this->memcached->get($key); 45 | } 46 | 47 | /** 48 | * Store a value in the cache 49 | * $expire is specified as an integer: 50 | * - less than or equal to 2592000 (the number of seconds in 30 days) 51 | * will be considered an expire time of that many seconds from the 52 | * current timestamp 53 | * - Greater than that amount will be considered as literal Unix 54 | * timestamp values 55 | * - 0 means "never expire." 56 | * 57 | * @param string $key 58 | * @param mixed $value 59 | * @param integer $expire 60 | * @return boolean true on success 61 | */ 62 | public function set($key, $value, $expire=0) 63 | { 64 | return $this->memcached->set($key, $value, $expire); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /lib/Everyman/Neo4j/Cache/None.php: -------------------------------------------------------------------------------- 1 | items[$key]); 24 | return true; 25 | } 26 | 27 | /** 28 | * Retrieve a value 29 | * Returns false if the key does not 30 | * exist, or the value is false 31 | * 32 | * @param string $key 33 | * @return mixed 34 | */ 35 | public function get($key) 36 | { 37 | $value = false; 38 | if (isset($this->items[$key])) { 39 | if ($this->items[$key]['expire'] >= time()) { 40 | $value = $this->items[$key]['value']; 41 | } else { 42 | $this->delete($key); 43 | } 44 | } 45 | 46 | return $value; 47 | } 48 | 49 | /** 50 | * Store a value in the cache 51 | * $expire is specified as an integer: 52 | * - less than or equal to 2592000 (the number of seconds in 30 days) 53 | * will be considered an expire time of that many seconds from the 54 | * current timestamp 55 | * - Greater than that amount will be considered as literal Unix 56 | * timestamp values 57 | * - 0 means "never expire." 58 | * 59 | * @param string $key 60 | * @param mixed $value 61 | * @param integer $expire 62 | * @return boolean true on success 63 | */ 64 | public function set($key, $value, $expire=0) 65 | { 66 | $expire = $this->calculateExpiration($expire); 67 | 68 | $this->items[$key] = array( 69 | 'value' => $value, 70 | 'expire' => $expire, 71 | ); 72 | return true; 73 | } 74 | 75 | /** 76 | * Determine the expiration timestamp 77 | * 78 | * @param integer $expire 79 | * @return integer 80 | */ 81 | protected function calculateExpiration($expire) 82 | { 83 | if (!$expire) { 84 | $expire = PHP_INT_MAX; 85 | } else if ($expire <= 2592000) { 86 | $expire = time() + $expire; 87 | } 88 | return $expire; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /lib/Everyman/Neo4j/Command.php: -------------------------------------------------------------------------------- 1 | client = $client; 19 | } 20 | 21 | /** 22 | * Return the data to pass 23 | * 24 | * @return mixed 25 | */ 26 | abstract protected function getData(); 27 | 28 | /** 29 | * Return the transport method to call 30 | * 31 | * @return string 32 | */ 33 | abstract protected function getMethod(); 34 | 35 | /** 36 | * Return the path to use 37 | * 38 | * @return string 39 | */ 40 | abstract protected function getPath(); 41 | 42 | /** 43 | * Use the results in some way 44 | * 45 | * @param integer $code 46 | * @param array $headers 47 | * @param array $data 48 | * @return mixed 49 | * @throws Exception on failure 50 | */ 51 | abstract protected function handleResult($code, $headers, $data); 52 | 53 | /** 54 | * Run the command and return a value signalling the result 55 | * 56 | * @return mixed 57 | * @throws Exception on failure 58 | */ 59 | public function execute() 60 | { 61 | $method = $this->getMethod(); 62 | $path = $this->getPath(); 63 | $data = $this->getData(); 64 | $result = $this->getTransport()->$method($path, $data); 65 | 66 | $resultCode = isset($result['code']) ? $result['code'] : Client::ErrorUnknown; 67 | $resultHeaders = isset($result['headers']) ? $result['headers'] : array(); 68 | $resultData = isset($result['data']) ? $result['data'] : array(); 69 | $parseResult = $this->handleResult($resultCode, $resultHeaders, $resultData); 70 | 71 | return $parseResult; 72 | } 73 | 74 | /** 75 | * Get the entity cache 76 | * 77 | * @return Cache\EntityCache 78 | */ 79 | protected function getEntityCache() 80 | { 81 | return $this->client->getEntityCache(); 82 | } 83 | 84 | /** 85 | * Get the entity mapper 86 | * 87 | * @return EntityMapper 88 | */ 89 | protected function getEntityMapper() 90 | { 91 | return $this->client->getEntityMapper(); 92 | } 93 | 94 | /** 95 | * Get the transport 96 | * 97 | * @return Transport 98 | */ 99 | protected function getTransport() 100 | { 101 | return $this->client->getTransport(); 102 | } 103 | 104 | /** 105 | * Throw an exception from handling the results 106 | * 107 | * @param string $message 108 | * @param integer $code 109 | * @param array $headers 110 | * @param array $data 111 | * @throws Exception 112 | */ 113 | protected function throwException($message, $code, $headers, $data) 114 | { 115 | $message = "{$message} [{$code}]:\nHeaders: " . print_r($headers, true) . "Body: " . print_r($data, true); 116 | throw new Exception($message, $code, $headers, $data); 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /lib/Everyman/Neo4j/Command/AddLabels.php: -------------------------------------------------------------------------------- 1 | transaction = $transaction; 32 | $this->statements = $statements; 33 | $this->commit = $commit; 34 | } 35 | 36 | /** 37 | * Return the data to pass 38 | * 39 | * @return mixed 40 | */ 41 | protected function getData() 42 | { 43 | if (!$this->statements && !$this->transaction->getId()) { 44 | throw new Exception("Cannot keep-alive a transaction without an id"); 45 | } 46 | 47 | $statements = array_map(array($this, 'formatStatement'), $this->statements); 48 | return array('statements' => $statements); 49 | } 50 | 51 | /** 52 | * Format the given query into a transactional statement 53 | * 54 | * @param Query $statement 55 | * @return array 56 | */ 57 | protected function formatStatement(Query $statement) 58 | { 59 | return array( 60 | 'statement' => $statement->getQuery(), 61 | 'parameters' => (object)$statement->getParameters(), 62 | 'resultDataContents' => array('rest'), 63 | ); 64 | } 65 | 66 | /** 67 | * Return the transport method to call 68 | * 69 | * @return string 70 | */ 71 | protected function getMethod() 72 | { 73 | return 'post'; 74 | } 75 | 76 | /** 77 | * Return the path to use 78 | * 79 | * @return string 80 | */ 81 | protected function getPath() 82 | { 83 | if (!$this->client->hasCapability(Client::CapabilityTransactions)) { 84 | throw new Exception('Transactions unavailable'); 85 | } 86 | 87 | $path = '/transaction'; 88 | 89 | $id = $this->transaction->getId(); 90 | if ($id) { 91 | $path .= '/'.$id; 92 | } 93 | 94 | if ($this->commit) { 95 | $path .= '/commit'; 96 | } 97 | 98 | return $path; 99 | } 100 | 101 | /** 102 | * Use the results 103 | * 104 | * @param integer $code 105 | * @param array $headers 106 | * @param array $data 107 | * @return integer on failure 108 | */ 109 | protected function handleResult($code, $headers, $data) 110 | { 111 | if ((int)($code / 100) != 2 || !empty($data['errors'])) { 112 | $this->throwException('Error in transaction', $code, $headers, $data); 113 | } 114 | 115 | if (!$this->transaction->getId() && !$this->commit) { 116 | $this->setTransactionId($data); 117 | } 118 | 119 | $results = array_map(array($this, 'mapResult'), $data['results']); 120 | return $results; 121 | } 122 | 123 | /** 124 | * Map the response into a ResultSet 125 | * 126 | * @param array $result 127 | * @return ResultSet 128 | */ 129 | protected function mapResult($result) 130 | { 131 | $data = array_map(function ($row) { 132 | return $row['rest']; 133 | }, $result['data']); 134 | 135 | return new ResultSet($this->client, array( 136 | 'columns' => $result['columns'], 137 | 'data' => $data, 138 | )); 139 | } 140 | 141 | /** 142 | * Parse the transaction id out of the response and set it on the transaction 143 | * 144 | * @param array $data 145 | */ 146 | protected function setTransactionId($data) 147 | { 148 | $commit = $data['commit']; 149 | $path = parse_url($commit, PHP_URL_PATH); 150 | $parts = explode('/', $path); 151 | $id = $parts[count($parts)-2]; 152 | $this->transaction->setId($id); 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /lib/Everyman/Neo4j/Command/AddToIndex.php: -------------------------------------------------------------------------------- 1 | index = $index; 35 | $this->entity = $entity; 36 | $this->key = $key; 37 | $this->value = $value; 38 | } 39 | 40 | /** 41 | * Return the data to pass 42 | * 43 | * @return mixed 44 | */ 45 | protected function getData() 46 | { 47 | if (!$this->entity || !$this->entity->hasId()) { 48 | throw new Exception('No entity to index specified'); 49 | } 50 | 51 | $data = array(); 52 | 53 | $type = trim((string)$this->index->getType()); 54 | $data['uri'] = $this->getTransport()->getEndpoint().'/'.$type.'/'.$this->entity->getId(); 55 | 56 | 57 | $key = trim((string)$this->key); 58 | if (!$key) { 59 | throw new Exception('No key specified to add to index'); 60 | } 61 | $data['key'] = $key; 62 | $data['value'] = $this->value; 63 | 64 | return $data; 65 | } 66 | 67 | /** 68 | * Return the transport method to call 69 | * 70 | * @return string 71 | */ 72 | protected function getMethod() 73 | { 74 | return 'post'; 75 | } 76 | 77 | /** 78 | * Return the path to use 79 | * 80 | * @return string 81 | */ 82 | protected function getPath() 83 | { 84 | $type = trim((string)$this->index->getType()); 85 | if ($type != Index::TypeNode && $type != Index::TypeRelationship) { 86 | throw new Exception('No type specified for index'); 87 | } else if ($type == Index::TypeNode && !($this->entity instanceof Node)) { 88 | throw new Exception('Cannot add a node to a non-node index'); 89 | } else if ($type == Index::TypeRelationship && !($this->entity instanceof Relationship)) { 90 | throw new Exception('Cannot add a relationship to a non-relationship index'); 91 | } 92 | 93 | $name = trim((string)$this->index->getName()); 94 | if (!$name) { 95 | throw new Exception('No name specified for index'); 96 | } 97 | $name = rawurlencode($name); 98 | 99 | return '/index/'.$type.'/'.$name; 100 | } 101 | 102 | /** 103 | * Use the results 104 | * 105 | * @param integer $code 106 | * @param array $headers 107 | * @param array $data 108 | * @return integer on failure 109 | */ 110 | protected function handleResult($code, $headers, $data) 111 | { 112 | if ((int)($code / 100) != 2) { 113 | $this->throwException('Unable to add entity to index', $code, $headers, $data); 114 | } 115 | return true; 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /lib/Everyman/Neo4j/Command/Batch/AddToIndex.php: -------------------------------------------------------------------------------- 1 | batch = $batch; 34 | $this->entity = $entity; 35 | } 36 | 37 | /** 38 | * Return the data to pass 39 | * 40 | * @return array 41 | */ 42 | protected function getData() 43 | { 44 | $opData = array(); 45 | 46 | // Prevent the command from throwing an Exception if an unsaved entity 47 | if (!$this->entity->hasId()) { 48 | $entityId = $this->batch->save($this->entity); 49 | $reserved = $this->batch->reserve($entityId); 50 | if ($reserved) { 51 | $opData = array_merge($opData, $reserved->getCommand()->getData()); 52 | } 53 | $this->entity->setId(-1); 54 | $body = $this->base->getData(); 55 | $this->entity->setId(null); 56 | $body['uri'] = "{{$entityId}}"; 57 | } else { 58 | $body = $this->base->getData(); 59 | } 60 | 61 | $opData[] = array( 62 | 'method' => strtoupper($this->base->getMethod()), 63 | 'to' => $this->base->getPath(), 64 | 'body' => $body, 65 | 'id' => $this->opId, 66 | ); 67 | return $opData; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /lib/Everyman/Neo4j/Command/Batch/Command.php: -------------------------------------------------------------------------------- 1 | base = $base; 26 | $this->opId = $opId; 27 | } 28 | 29 | /** 30 | * Return the transport method to call 31 | * 32 | * @return string 33 | */ 34 | protected function getMethod() 35 | { 36 | return 'post'; 37 | } 38 | 39 | /** 40 | * Return the path to use 41 | * 42 | * @return string 43 | */ 44 | protected function getPath() 45 | { 46 | return '/batch'; 47 | } 48 | 49 | /** 50 | * Use the results 51 | * 52 | * @param integer $code 53 | * @param array $headers 54 | * @param array $data 55 | * @return mixed 56 | * @throws Exception on failure 57 | */ 58 | protected function handleResult($code, $headers, $data) 59 | { 60 | if ((int)($code / 100) != 2) { 61 | $this->throwException('Unable to commit batch', $code, $headers, $data); 62 | } 63 | 64 | foreach ($data as $result) { 65 | $this->handleSingleResult($result); 66 | } 67 | return true; 68 | } 69 | 70 | /** 71 | * Handle a single result from the batch of results 72 | * 73 | * @param array $result 74 | * @return mixed 75 | * @throws Exception on failure 76 | */ 77 | protected function handleSingleResult($result) 78 | { 79 | $headers = array(); 80 | if (isset($result['location'])) { 81 | $headers['Location'] = $result['location']; 82 | } 83 | return $this->base->handleResult(200, $headers, $result); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /lib/Everyman/Neo4j/Command/Batch/Commit.php: -------------------------------------------------------------------------------- 1 | batch = $batch; 26 | } 27 | 28 | /** 29 | * Return the data to pass 30 | * 31 | * @return mixed 32 | */ 33 | protected function getData() 34 | { 35 | $operations = $this->batch->getOperations(); 36 | $data = array(); 37 | foreach ($operations as $op) { 38 | if ($op->reserve()) { 39 | $opData = $op->getCommand()->getData(); 40 | foreach ($opData as $datum) { 41 | $data[] = $datum; 42 | } 43 | } 44 | } 45 | return $data; 46 | } 47 | 48 | /** 49 | * Use the results 50 | * 51 | * @param array $result 52 | */ 53 | protected function handleSingleResult($result) 54 | { 55 | $operations = $this->batch->getOperations(); 56 | $command = $operations[$result['id']]->getCommand(); 57 | return $command->handleSingleResult($result); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /lib/Everyman/Neo4j/Command/Batch/CreateNode.php: -------------------------------------------------------------------------------- 1 | strtoupper($this->base->getMethod()), 34 | 'to' => $this->base->getPath(), 35 | 'body' => $this->base->getData(), 36 | 'id' => $this->opId, 37 | )); 38 | return $opData; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /lib/Everyman/Neo4j/Command/Batch/CreateRelationship.php: -------------------------------------------------------------------------------- 1 | batch = $batch; 30 | $this->rel = $rel; 31 | } 32 | 33 | /** 34 | * Return the data to pass 35 | * 36 | * @return array 37 | */ 38 | protected function getData() 39 | { 40 | $opData = array(); 41 | 42 | // Prevent the command from throwing an Exception if an unsaved start node 43 | $startNode = $this->rel->getStartNode(); 44 | if (!$startNode->hasId()) { 45 | $startId = $this->batch->save($startNode); 46 | $reserved = $this->batch->reserve($startId); 47 | if ($reserved) { 48 | $opData = array_merge($opData, $reserved->getCommand()->getData()); 49 | } 50 | $start = "{{$startId}}/relationships"; 51 | } else { 52 | $start = $this->base->getPath(); 53 | } 54 | 55 | // Prevent the command from throwing an Exception if an unsaved end node 56 | $endNode = $this->rel->getEndNode(); 57 | if (!$endNode->hasId()) { 58 | $endId = $this->batch->save($endNode); 59 | $reserved = $this->batch->reserve($endId); 60 | if ($reserved) { 61 | $opData = array_merge($opData, $reserved->getCommand()->getData()); 62 | } 63 | $endNode->setId('temp'); 64 | $data = $this->base->getData(); 65 | $endNode->setId(null); 66 | $data['to'] = "{{$endId}}"; 67 | } else { 68 | $data = $this->base->getData(); 69 | } 70 | 71 | $opData[] = array( 72 | 'method' => strtoupper($this->base->getMethod()), 73 | 'to' => $start, 74 | 'body' => $data, 75 | 'id' => $this->opId, 76 | ); 77 | return $opData; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /lib/Everyman/Neo4j/Command/Batch/DeleteNode.php: -------------------------------------------------------------------------------- 1 | strtoupper($this->base->getMethod()), 34 | 'to' => $this->base->getPath(), 35 | 'id' => $this->opId, 36 | )); 37 | return $opData; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /lib/Everyman/Neo4j/Command/Batch/DeleteRelationship.php: -------------------------------------------------------------------------------- 1 | strtoupper($this->base->getMethod()), 34 | 'to' => $this->base->getPath(), 35 | 'id' => $this->opId, 36 | )); 37 | return $opData; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /lib/Everyman/Neo4j/Command/Batch/RemoveFromIndex.php: -------------------------------------------------------------------------------- 1 | strtoupper($this->base->getMethod()), 39 | 'to' => $this->base->getPath(), 40 | 'id' => $this->opId, 41 | )); 42 | return $opData; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /lib/Everyman/Neo4j/Command/Batch/UpdateNode.php: -------------------------------------------------------------------------------- 1 | strtoupper($this->base->getMethod()), 34 | 'to' => $this->base->getPath(), 35 | 'body' => $this->base->getData(), 36 | 'id' => $this->opId, 37 | )); 38 | return $opData; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /lib/Everyman/Neo4j/Command/Batch/UpdateRelationship.php: -------------------------------------------------------------------------------- 1 | strtoupper($this->base->getMethod()), 34 | 'to' => $this->base->getPath(), 35 | 'body' => $this->base->getData(), 36 | 'id' => $this->opId, 37 | )); 38 | return $opData; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /lib/Everyman/Neo4j/Command/CreateNode.php: -------------------------------------------------------------------------------- 1 | node = $node; 25 | } 26 | 27 | /** 28 | * Return the data to pass 29 | * 30 | * @return mixed 31 | */ 32 | protected function getData() 33 | { 34 | return $this->node->getProperties() ?: null; 35 | } 36 | 37 | /** 38 | * Return the transport method to call 39 | * 40 | * @return string 41 | */ 42 | protected function getMethod() 43 | { 44 | return 'post'; 45 | } 46 | 47 | /** 48 | * Return the path to use 49 | * 50 | * @return string 51 | */ 52 | protected function getPath() 53 | { 54 | return '/node'; 55 | } 56 | 57 | /** 58 | * Use the results 59 | * 60 | * @param integer $code 61 | * @param array $headers 62 | * @param array $data 63 | * @return boolean true on success 64 | * @throws Exception on failure 65 | */ 66 | protected function handleResult($code, $headers, $data) 67 | { 68 | if ((int)($code / 100) != 2) { 69 | $this->throwException('Unable to create node', $code, $headers, $data); 70 | } 71 | 72 | $nodeId = $this->getEntityMapper()->getIdFromUri($headers['Location']); 73 | $this->node->setId($nodeId); 74 | $this->getEntityCache()->setCachedEntity($this->node); 75 | return true; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /lib/Everyman/Neo4j/Command/CreateRelationship.php: -------------------------------------------------------------------------------- 1 | rel = $rel; 27 | } 28 | 29 | /** 30 | * Return the data to pass 31 | * 32 | * @return mixed 33 | */ 34 | protected function getData() 35 | { 36 | $end = $this->rel->getEndNode(); 37 | $type = $this->rel->getType(); 38 | if (!$end || !$end->hasId()) { 39 | throw new Exception('No relationship end node specified'); 40 | } else if (!$type) { 41 | throw new Exception('No relationship type specified'); 42 | } 43 | 44 | $endUri = $this->getTransport()->getEndpoint().'/node/'.$end->getId(); 45 | $data = array( 46 | 'type' => $type, 47 | 'to' => $endUri, 48 | ); 49 | 50 | $properties = $this->rel->getProperties(); 51 | if ($properties) { 52 | $data['data'] = $properties; 53 | } 54 | 55 | return $data; 56 | } 57 | 58 | /** 59 | * Return the transport method to call 60 | * 61 | * @return string 62 | */ 63 | protected function getMethod() 64 | { 65 | return 'post'; 66 | } 67 | 68 | /** 69 | * Return the path to use 70 | * 71 | * @return string 72 | */ 73 | protected function getPath() 74 | { 75 | $start = $this->rel->getStartNode(); 76 | if (!$start || !$start->hasId()) { 77 | throw new Exception('No relationship start node specified'); 78 | } 79 | return '/node/'.$start->getId().'/relationships'; 80 | } 81 | 82 | /** 83 | * Use the results 84 | * 85 | * @param integer $code 86 | * @param array $headers 87 | * @param array $data 88 | * @return boolean true on success 89 | * @throws Exception on failure 90 | */ 91 | protected function handleResult($code, $headers, $data) 92 | { 93 | if ((int)($code / 100) != 2) { 94 | $this->throwException('Unable to create relationship', $code, $headers, $data); 95 | } 96 | 97 | $relId = $this->getEntityMapper()->getIdFromUri($headers['Location']); 98 | $this->rel->setId($relId); 99 | $this->getEntityCache()->setCachedEntity($this->rel); 100 | return true; 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /lib/Everyman/Neo4j/Command/DeleteIndex.php: -------------------------------------------------------------------------------- 1 | index = $index; 26 | } 27 | 28 | /** 29 | * Return the data to pass 30 | * 31 | * @return mixed 32 | */ 33 | protected function getData() 34 | { 35 | return null; 36 | } 37 | 38 | /** 39 | * Return the transport method to call 40 | * 41 | * @return string 42 | */ 43 | protected function getMethod() 44 | { 45 | return 'delete'; 46 | } 47 | 48 | /** 49 | * Return the path to use 50 | * 51 | * @return string 52 | */ 53 | protected function getPath() 54 | { 55 | $type = trim((string)$this->index->getType()); 56 | if ($type != Index::TypeNode && $type != Index::TypeRelationship) { 57 | throw new Exception('No type specified for index'); 58 | } 59 | 60 | $name = trim((string)$this->index->getName()); 61 | if (!$name) { 62 | throw new Exception('No name specified for index'); 63 | } 64 | $name = rawurlencode($name); 65 | 66 | return '/index/'.$type.'/'.$name; 67 | } 68 | 69 | /** 70 | * Use the results 71 | * 72 | * @param integer $code 73 | * @param array $headers 74 | * @param array $data 75 | * @return integer on failure 76 | */ 77 | protected function handleResult($code, $headers, $data) 78 | { 79 | if ((int)($code / 100) != 2 && (int)$code != 404) { 80 | $this->throwException('Unable to delete index', $code, $headers, $data); 81 | } 82 | return true; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /lib/Everyman/Neo4j/Command/DeleteNode.php: -------------------------------------------------------------------------------- 1 | node = $node; 26 | } 27 | 28 | /** 29 | * Return the data to pass 30 | * 31 | * @return mixed 32 | */ 33 | protected function getData() 34 | { 35 | return null; 36 | } 37 | 38 | /** 39 | * Return the transport method to call 40 | * 41 | * @return string 42 | */ 43 | protected function getMethod() 44 | { 45 | return 'delete'; 46 | } 47 | 48 | /** 49 | * Return the path to use 50 | * 51 | * @return string 52 | */ 53 | protected function getPath() 54 | { 55 | if (!$this->node->hasId()) { 56 | throw new Exception('No node id specified for delete'); 57 | } 58 | return '/node/'.$this->node->getId(); 59 | } 60 | 61 | /** 62 | * Use the results 63 | * 64 | * @param integer $code 65 | * @param array $headers 66 | * @param array $data 67 | * @return boolean true on success 68 | * @throws Exception on failure 69 | */ 70 | protected function handleResult($code, $headers, $data) 71 | { 72 | if ((int)($code / 100) == 2) { 73 | $this->getEntityCache()->deleteCachedEntity($this->node); 74 | return true; 75 | } else { 76 | $this->throwException('Unable to delete node', $code, $headers, $data); 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /lib/Everyman/Neo4j/Command/DeleteRelationship.php: -------------------------------------------------------------------------------- 1 | rel = $rel; 26 | } 27 | 28 | /** 29 | * Return the data to pass 30 | * 31 | * @return mixed 32 | */ 33 | protected function getData() 34 | { 35 | return null; 36 | } 37 | 38 | /** 39 | * Return the transport method to call 40 | * 41 | * @return string 42 | */ 43 | protected function getMethod() 44 | { 45 | return 'delete'; 46 | } 47 | 48 | /** 49 | * Return the path to use 50 | * 51 | * @return string 52 | */ 53 | protected function getPath() 54 | { 55 | if (!$this->rel->hasId()) { 56 | throw new Exception('No relationship id specified for delete'); 57 | } 58 | return '/relationship/'.$this->rel->getId(); 59 | } 60 | 61 | /** 62 | * Use the results 63 | * 64 | * @param integer $code 65 | * @param array $headers 66 | * @param array $data 67 | * @return boolean true on success 68 | * @throws Exception on failure 69 | */ 70 | protected function handleResult($code, $headers, $data) 71 | { 72 | if ((int)($code / 100) == 2) { 73 | $this->getEntityCache()->deleteCachedEntity($this->rel); 74 | return true; 75 | } else { 76 | $this->throwException('Unable to delete relationship', $code, $headers, $data); 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /lib/Everyman/Neo4j/Command/ExecuteCypherQuery.php: -------------------------------------------------------------------------------- 1 | query = $query; 28 | } 29 | 30 | /** 31 | * Return the data to pass 32 | * 33 | * @return mixed 34 | */ 35 | protected function getData() 36 | { 37 | $data = array('query' => $this->query->getQuery()); 38 | $params = $this->query->getParameters(); 39 | if ($params) { 40 | $data['params'] = $params; 41 | } 42 | return $data; 43 | } 44 | 45 | /** 46 | * Return the transport method to call 47 | * 48 | * @return string 49 | */ 50 | protected function getMethod() 51 | { 52 | return 'post'; 53 | } 54 | 55 | /** 56 | * Return the path to use 57 | * 58 | * @return string 59 | */ 60 | protected function getPath() 61 | { 62 | $url = $this->client->hasCapability(Client::CapabilityCypher); 63 | if (!$url) { 64 | throw new Exception('Cypher unavailable'); 65 | } 66 | 67 | return preg_replace('/^.+\/db\/data/', '', $url); 68 | } 69 | 70 | /** 71 | * Use the results 72 | * 73 | * @param integer $code 74 | * @param array $headers 75 | * @param array $data 76 | * @return integer on failure 77 | */ 78 | protected function handleResult($code, $headers, $data) 79 | { 80 | if ((int)($code / 100) != 2) { 81 | $this->throwException('Unable to execute query', $code, $headers, $data); 82 | } 83 | 84 | return new ResultSet($this->client, $data); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /lib/Everyman/Neo4j/Command/ExecuteGremlinQuery.php: -------------------------------------------------------------------------------- 1 | query = $query; 28 | } 29 | 30 | /** 31 | * Return the data to pass 32 | * 33 | * @return mixed 34 | */ 35 | protected function getData() 36 | { 37 | $data = array('script' => $this->query->getQuery()); 38 | $params = $this->query->getParameters(); 39 | if ($params) { 40 | $data['params'] = $params; 41 | } 42 | return $data; 43 | } 44 | 45 | /** 46 | * Return the transport method to call 47 | * 48 | * @return string 49 | */ 50 | protected function getMethod() 51 | { 52 | return 'post'; 53 | } 54 | 55 | /** 56 | * Return the path to use 57 | * 58 | * @return string 59 | */ 60 | protected function getPath() 61 | { 62 | $url = $this->client->hasCapability(Client::CapabilityGremlin); 63 | if (!$url) { 64 | throw new Exception('Gremlin unavailable'); 65 | } 66 | 67 | return preg_replace('/^.+\/db\/data/', '', $url); 68 | } 69 | 70 | /** 71 | * Use the results 72 | * 73 | * @param integer $code 74 | * @param array $headers 75 | * @param array $data 76 | * @return integer on failure 77 | */ 78 | protected function handleResult($code, $headers, $data) 79 | { 80 | if ((int)($code / 100) != 2) { 81 | $this->throwException('Unable to execute query', $code, $headers, $data); 82 | } 83 | 84 | return new ResultSet($this->client, $this->normalizeData($data)); 85 | } 86 | 87 | /** 88 | * Normalize the data so a proper ResultSet can be built 89 | * Normalized data has 'data' and 'columns' keys for result set. 90 | * 91 | * @param array $data 92 | * @return array 93 | */ 94 | protected function normalizeData($data) 95 | { 96 | if (is_scalar($data)) { 97 | $data = array($data); 98 | } 99 | 100 | if (!array_key_exists('columns', $data)) { 101 | $columns = array(0); 102 | 103 | if (array_key_exists('self', $data)) { 104 | $data = array(array($data)); 105 | } else { 106 | foreach ($data as $i => $entity) { 107 | $data[$i] = array($entity); 108 | } 109 | } 110 | 111 | $data = array( 112 | 'columns' => $columns, 113 | 'data' => $data 114 | ); 115 | } 116 | 117 | return $data; 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /lib/Everyman/Neo4j/Command/ExecutePagedTraversal.php: -------------------------------------------------------------------------------- 1 | getTraversal(), $pager->getStartNode(), $pager->getReturnType()); 23 | $this->pager = $pager; 24 | } 25 | 26 | /** 27 | * Return the data to pass 28 | * 29 | * @return mixed 30 | */ 31 | protected function getData() 32 | { 33 | return $this->pager->getId() ? null : parent::getData(); 34 | } 35 | 36 | /** 37 | * Return the transport method to call 38 | * 39 | * @return string 40 | */ 41 | protected function getMethod() 42 | { 43 | return $this->pager->getId() ? 'get' : parent::getMethod(); 44 | } 45 | 46 | /** 47 | * Return the path to use 48 | * 49 | * @return string 50 | */ 51 | protected function getPath() 52 | { 53 | $path = parent::getPath(); 54 | $path = str_replace('traverse', 'paged/traverse', $path); 55 | 56 | $id = $this->pager->getId(); 57 | if ($id) { 58 | $path .= "/{$id}"; 59 | } else { 60 | $queryParams = array(); 61 | $pageSize = $this->pager->getPageSize(); 62 | $leaseTime = $this->pager->getLeaseTime(); 63 | if ($pageSize) { 64 | $queryParams['pageSize'] = $pageSize; 65 | } 66 | if ($leaseTime) { 67 | $queryParams['leaseTime'] = $leaseTime; 68 | } 69 | $queryString = http_build_query($queryParams); 70 | $path .= $queryString ? "?{$queryString}" : ''; 71 | } 72 | 73 | return $path; 74 | } 75 | 76 | /** 77 | * Use the results 78 | * 79 | * @param integer $code 80 | * @param array $headers 81 | * @param array $data 82 | * @return integer on failure 83 | */ 84 | protected function handleResult($code, $headers, $data) 85 | { 86 | if (isset($headers['Location'])) { 87 | $traversalId = $this->getEntityMapper()->getIdFromUri($headers['Location']); 88 | $this->pager->setId($traversalId); 89 | } 90 | 91 | // No results found or end of result set indicated by not found 92 | if ($code == Client::ErrorNotFound) { 93 | return null; 94 | } 95 | return parent::handleResult($code, $headers, $data); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /lib/Everyman/Neo4j/Command/GetIndexes.php: -------------------------------------------------------------------------------- 1 | type = $type; 26 | } 27 | 28 | /** 29 | * Return the data to pass 30 | * 31 | * @return mixed 32 | */ 33 | protected function getData() 34 | { 35 | return null; 36 | } 37 | 38 | /** 39 | * Return the transport method to call 40 | * 41 | * @return string 42 | */ 43 | protected function getMethod() 44 | { 45 | return 'get'; 46 | } 47 | 48 | /** 49 | * Return the path to use 50 | * 51 | * @return string 52 | */ 53 | protected function getPath() 54 | { 55 | $type = trim((string)$this->type); 56 | if ($type != Index::TypeNode && $type != Index::TypeRelationship) { 57 | throw new Exception('No type specified for index'); 58 | } 59 | 60 | return '/index/'.$type; 61 | } 62 | 63 | /** 64 | * Use the results 65 | * 66 | * @param integer $code 67 | * @param array $headers 68 | * @param array $data 69 | * @return integer on failure 70 | */ 71 | protected function handleResult($code, $headers, $data) 72 | { 73 | if ((int)($code / 100) != 2) { 74 | $this->throwException('Unable to retrieve indexes', $code, $headers, $data); 75 | } 76 | 77 | if (!$data) { 78 | $data = array(); 79 | } 80 | 81 | $indexes = array(); 82 | foreach ($data as $name => $indexData) { 83 | $indexes[] = new Index($this->client, $this->type, $name, $indexData); 84 | } 85 | return $indexes; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /lib/Everyman/Neo4j/Command/GetLabels.php: -------------------------------------------------------------------------------- 1 | node = $node; 25 | } 26 | 27 | /** 28 | * Return the data to pass 29 | * 30 | * @return mixed 31 | */ 32 | protected function getData() 33 | { 34 | return null; 35 | } 36 | 37 | /** 38 | * Return the transport method to call 39 | * 40 | * @return string 41 | */ 42 | protected function getMethod() 43 | { 44 | return 'get'; 45 | } 46 | 47 | /** 48 | * Return the path to use 49 | * 50 | * @return string 51 | */ 52 | protected function getPath() 53 | { 54 | if (!$this->client->hasCapability(Client::CapabilityLabel)) { 55 | throw new \RuntimeException('The connected Neo4j version does not have label capability'); 56 | } 57 | 58 | $path = "/labels"; 59 | if ($this->node) { 60 | $id = $this->node->getId(); 61 | if (!is_numeric($id)) { 62 | throw new \InvalidArgumentException("Node given with no id"); 63 | } 64 | 65 | $path = "/node/{$id}{$path}"; 66 | } 67 | return $path; 68 | } 69 | 70 | /** 71 | * Use the results 72 | * 73 | * @param integer $code 74 | * @param array $headers 75 | * @param array $data 76 | * @return Row 77 | * @throws Exception on failure 78 | */ 79 | protected function handleResult($code, $headers, $data) 80 | { 81 | if ((int)($code / 100) != 2) { 82 | $this->throwException('Unable to labels', $code, $headers, $data); 83 | } 84 | 85 | $labels = array_map(array($this->client, 'makeLabel'), $data); 86 | 87 | return $labels; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /lib/Everyman/Neo4j/Command/GetNode.php: -------------------------------------------------------------------------------- 1 | node = $node; 26 | } 27 | 28 | /** 29 | * Return the data to pass 30 | * 31 | * @return mixed 32 | */ 33 | protected function getData() 34 | { 35 | return null; 36 | } 37 | 38 | /** 39 | * Return the transport method to call 40 | * 41 | * @return string 42 | */ 43 | protected function getMethod() 44 | { 45 | return 'get'; 46 | } 47 | 48 | /** 49 | * Return the path to use 50 | * 51 | * @return string 52 | */ 53 | protected function getPath() 54 | { 55 | if (!$this->node->hasId()) { 56 | throw new Exception('No node id specified'); 57 | } 58 | return '/node/'.$this->node->getId(); 59 | } 60 | 61 | /** 62 | * Use the results 63 | * 64 | * @param integer $code 65 | * @param array $headers 66 | * @param array $data 67 | * @return boolean true on success 68 | * @throws Exception on failure 69 | */ 70 | protected function handleResult($code, $headers, $data) 71 | { 72 | if ((int)($code / 100) == 2) { 73 | $this->node = $this->getEntityMapper()->populateNode($this->node, $data); 74 | $this->getEntityCache()->setCachedEntity($this->node); 75 | return true; 76 | } else { 77 | $this->throwException('Unable to retrieve node', $code, $headers, $data); 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /lib/Everyman/Neo4j/Command/GetNodeRelationships.php: -------------------------------------------------------------------------------- 1 | node = $node; 41 | $this->dir = $dir; 42 | $this->types = $types; 43 | } 44 | 45 | /** 46 | * Return the data to pass 47 | * 48 | * @return mixed 49 | */ 50 | protected function getData() 51 | { 52 | return null; 53 | } 54 | 55 | /** 56 | * Return the transport method to call 57 | * 58 | * @return string 59 | */ 60 | protected function getMethod() 61 | { 62 | return 'get'; 63 | } 64 | 65 | /** 66 | * Return the path to use 67 | * 68 | * @return string 69 | */ 70 | protected function getPath() 71 | { 72 | if (!$this->node->hasId()) { 73 | throw new Exception('No node id specified'); 74 | } 75 | 76 | $path = '/node/'.$this->node->getId().'/relationships/'.$this->dir; 77 | if (!empty($this->types)) { 78 | $types = array_map('rawurlencode', $this->types); 79 | $path .= '/'.join('&', $types); 80 | } 81 | 82 | return $path; 83 | } 84 | 85 | /** 86 | * Use the results 87 | * 88 | * @param integer $code 89 | * @param array $headers 90 | * @param array $data 91 | * @return integer on failure 92 | */ 93 | protected function handleResult($code, $headers, $data) 94 | { 95 | if ((int)($code / 100) == 2) { 96 | $rels = array(); 97 | foreach ($data as $relData) { 98 | $rels[] = $this->getEntityMapper()->makeRelationship($relData); 99 | } 100 | return $rels; 101 | } else { 102 | $this->throwException('Unable to retrieve node relationships', $code, $headers, $data); 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /lib/Everyman/Neo4j/Command/GetNodesForLabel.php: -------------------------------------------------------------------------------- 1 | label = $label; 31 | $this->propertyName = $propertyName; 32 | $this->propertyValue = $propertyValue; 33 | } 34 | 35 | /** 36 | * Return the data to pass 37 | * 38 | * @return mixed 39 | */ 40 | protected function getData() 41 | { 42 | return null; 43 | } 44 | 45 | /** 46 | * Return the transport method to call 47 | * 48 | * @return string 49 | */ 50 | protected function getMethod() 51 | { 52 | return 'get'; 53 | } 54 | 55 | /** 56 | * Return the path to use 57 | * 58 | * @return string 59 | */ 60 | protected function getPath() 61 | { 62 | if (!$this->client->hasCapability(Client::CapabilityLabel)) { 63 | throw new \RuntimeException('The connected Neo4j version does not have label capability'); 64 | } 65 | 66 | $labelName = rawurlencode($this->label->getName()); 67 | $path = "/label/{$labelName}/nodes"; 68 | if ($this->propertyName || $this->propertyValue) { 69 | if (!$this->propertyName || !$this->propertyValue) { 70 | throw new \InvalidArgumentException('Cannot specify a property name without a value, or vice versa'); 71 | } 72 | 73 | $propertyName = rawurlencode($this->propertyName); 74 | 75 | if (is_numeric($this->propertyValue)) { 76 | $propertyValue = rawurlencode($this->propertyValue); 77 | } else { 78 | $propertyValue = rawurlencode('"'.$this->propertyValue.'"'); 79 | } 80 | 81 | $path .= "?{$propertyName}={$propertyValue}"; 82 | } 83 | return $path; 84 | } 85 | 86 | /** 87 | * Use the results 88 | * 89 | * @param integer $code 90 | * @param array $headers 91 | * @param array $data 92 | * @return Row 93 | * @throws Exception on failure 94 | */ 95 | protected function handleResult($code, $headers, $data) 96 | { 97 | if ((int)($code / 100) != 2) { 98 | $this->throwException('Unable to retrieve nodes for label', $code, $headers, $data); 99 | } 100 | 101 | return new Row($this->client, array_keys($data), $data); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /lib/Everyman/Neo4j/Command/GetPaths.php: -------------------------------------------------------------------------------- 1 | finder = $finder; 28 | } 29 | 30 | /** 31 | * Return the data to pass 32 | * 33 | * @return mixed 34 | */ 35 | protected function getData() 36 | { 37 | $data = array(); 38 | 39 | $end = $this->finder->getEndNode(); 40 | if (!$end || !$end->hasId()) { 41 | throw new Exception('No end node id specified'); 42 | } 43 | 44 | $endUri = $this->getTransport()->getEndpoint().'/node/'.$end->getId(); 45 | $data['to'] = $endUri; 46 | 47 | $algo = $this->finder->getAlgorithm(); 48 | if ($algo == PathFinder::AlgoDijkstra) { 49 | $property = $this->finder->getCostProperty(); 50 | if (!$property) { 51 | throw new Exception('No cost property specified for Dijkstra path search'); 52 | } 53 | $data['cost_property'] = $property; 54 | $data['cost property'] = $property; 55 | 56 | $cost = $this->finder->getDefaultCost(); 57 | if ($cost) { 58 | $data['default_cost'] = $cost; 59 | $data['default cost'] = $cost; 60 | } 61 | } 62 | $data['algorithm'] = $algo; 63 | 64 | 65 | 66 | $max = $this->finder->getMaxDepth(); 67 | if (!$max) { 68 | $max = 1; 69 | } 70 | $data['max_depth'] = $max; 71 | $data['max depth'] = $max; 72 | 73 | $type = $this->finder->getType(); 74 | $dir = $this->finder->getDirection(); 75 | if ($dir && !$type) { 76 | throw new Exception('No relationship type specified'); 77 | } else if ($type) { 78 | $rel = array('type'=>$type); 79 | if ($dir) { 80 | $rel['direction'] = $dir; 81 | } 82 | $data['relationships'] = $rel; 83 | } 84 | 85 | return $data; 86 | } 87 | 88 | /** 89 | * Return the transport method to call 90 | * 91 | * @return string 92 | */ 93 | protected function getMethod() 94 | { 95 | return 'post'; 96 | } 97 | 98 | /** 99 | * Return the path to use 100 | * 101 | * @return string 102 | */ 103 | protected function getPath() 104 | { 105 | $start = $this->finder->getStartNode(); 106 | if (!$start || !$start->hasId()) { 107 | throw new Exception('No start node id specified'); 108 | } 109 | 110 | return '/node/'.$start->getId().'/paths'; 111 | } 112 | 113 | /** 114 | * Use the results 115 | * 116 | * @param integer $code 117 | * @param array $headers 118 | * @param array $data 119 | * @return integer on failure 120 | */ 121 | protected function handleResult($code, $headers, $data) 122 | { 123 | if ((int)($code / 100) != 2) { 124 | $this->throwException('Unable to retrieve paths', $code, $headers, $data); 125 | } 126 | 127 | $paths = array(); 128 | foreach ($data as $pathData) { 129 | $paths[] = $this->getEntityMapper()->populatePath(new Path($this->client), $pathData); 130 | } 131 | return $paths; 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /lib/Everyman/Neo4j/Command/GetRelationship.php: -------------------------------------------------------------------------------- 1 | rel = $rel; 27 | } 28 | 29 | /** 30 | * Return the data to pass 31 | * 32 | * @return mixed 33 | */ 34 | protected function getData() 35 | { 36 | return null; 37 | } 38 | 39 | /** 40 | * Return the transport method to call 41 | * 42 | * @return string 43 | */ 44 | protected function getMethod() 45 | { 46 | return 'get'; 47 | } 48 | 49 | /** 50 | * Return the path to use 51 | * 52 | * @return string 53 | */ 54 | protected function getPath() 55 | { 56 | if (!$this->rel->hasId()) { 57 | throw new Exception('No relationship id specified'); 58 | } 59 | return '/relationship/'.$this->rel->getId(); 60 | } 61 | 62 | /** 63 | * Use the results 64 | * 65 | * @param integer $code 66 | * @param array $headers 67 | * @param array $data 68 | * @return boolean true on success 69 | * @throws Exception on failure 70 | */ 71 | protected function handleResult($code, $headers, $data) 72 | { 73 | if ((int)($code / 100) == 2) { 74 | $this->rel = $this->getEntityMapper()->populateRelationship($this->rel, $data); 75 | $this->getEntityCache()->setCachedEntity($this->rel); 76 | return true; 77 | } else { 78 | $this->throwException('Unable to retrieve relationship', $code, $headers, $data); 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /lib/Everyman/Neo4j/Command/GetRelationshipTypes.php: -------------------------------------------------------------------------------- 1 | throwException('Unable to retrieve relationship types', $code, $headers, $data); 54 | } 55 | return $data; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /lib/Everyman/Neo4j/Command/GetServerInfo.php: -------------------------------------------------------------------------------- 1 | throwException('Unable to retrieve server info', $code, $headers, $data); 54 | } 55 | $data['version'] = $this->parseVersion($data['neo4j_version']); 56 | return $data; 57 | } 58 | 59 | /** 60 | * Parse the version into usable bits 61 | * 62 | * @param string $fullVersion 63 | * @return array 64 | */ 65 | protected function parseVersion($fullVersion) 66 | { 67 | $parts = explode('.', $fullVersion); 68 | $versionInfo = array( 69 | 'full' => $fullVersion, 70 | 'major' => $parts[0], 71 | 'minor' => $parts[1], 72 | ); 73 | if (empty($parts[2])) { 74 | $versionInfo['release'] = 'GA'; 75 | } else { 76 | $versionInfo['release'] = current(explode('-', $parts[2], 2)); 77 | } 78 | return $versionInfo; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /lib/Everyman/Neo4j/Command/QueryIndex.php: -------------------------------------------------------------------------------- 1 | key); 38 | return $path . '?query=' . $query; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /lib/Everyman/Neo4j/Command/RemoveFromIndex.php: -------------------------------------------------------------------------------- 1 | index = $index; 39 | $this->entity = $entity; 40 | $this->key = $key; 41 | $this->value = $value; 42 | } 43 | 44 | /** 45 | * Return the data to pass 46 | * 47 | * @return mixed 48 | */ 49 | protected function getData() 50 | { 51 | return null; 52 | } 53 | 54 | /** 55 | * Return the transport method to call 56 | * 57 | * @return string 58 | */ 59 | protected function getMethod() 60 | { 61 | return 'delete'; 62 | } 63 | 64 | /** 65 | * Return the path to use 66 | * 67 | * @return string 68 | */ 69 | protected function getPath() 70 | { 71 | if (!$this->entity || !$this->entity->hasId()) { 72 | throw new Exception('No entity to index specified'); 73 | } 74 | 75 | $type = trim((string)$this->index->getType()); 76 | if ($type != Index::TypeNode && $type != Index::TypeRelationship) { 77 | throw new Exception('No type specified for index'); 78 | } else if ($type == Index::TypeNode && !($this->entity instanceof Node)) { 79 | throw new Exception('Cannot remove a node from a non-node index'); 80 | } else if ($type == Index::TypeRelationship && !($this->entity instanceof Relationship)) { 81 | throw new Exception('Cannot remove a relationship from a non-relationship index'); 82 | } 83 | 84 | $name = trim((string)$this->index->getName()); 85 | if (!$name) { 86 | throw new Exception('No name specified for index'); 87 | } 88 | 89 | $name = rawurlencode($name); 90 | $key = trim((string)$this->key); 91 | $value = trim((string)$this->value); 92 | 93 | $uri = '/index/'.$type.'/'.$name.'/'; 94 | if ($key) { 95 | $uri .= rawurlencode($key).'/'; 96 | if ($value) { 97 | $uri .= rawurlencode($value).'/'; 98 | } 99 | } 100 | $uri .= $this->entity->getId(); 101 | 102 | return $uri; 103 | } 104 | 105 | /** 106 | * Use the results 107 | * 108 | * @param integer $code 109 | * @param array $headers 110 | * @param array $data 111 | * @return integer on failure 112 | */ 113 | protected function handleResult($code, $headers, $data) 114 | { 115 | if ((int)($code / 100) != 2) { 116 | $this->throwException('Unable to remove entity from index', $code, $headers, $data); 117 | } 118 | return true; 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /lib/Everyman/Neo4j/Command/RemoveLabels.php: -------------------------------------------------------------------------------- 1 | transaction = $transaction; 26 | } 27 | 28 | /** 29 | * Return the data to pass 30 | * 31 | * @return mixed 32 | */ 33 | protected function getData() 34 | { 35 | return null; 36 | } 37 | 38 | /** 39 | * Return the transport method to call 40 | * 41 | * @return string 42 | */ 43 | protected function getMethod() 44 | { 45 | return 'delete'; 46 | } 47 | 48 | /** 49 | * Return the path to use 50 | * 51 | * @return string 52 | */ 53 | protected function getPath() 54 | { 55 | if (!$this->client->hasCapability(Client::CapabilityTransactions)) { 56 | throw new Exception('Transactions unavailable'); 57 | } 58 | 59 | $id = $this->transaction->getId(); 60 | if (!$id) { 61 | throw new Exception('Cannot rollback a transaction without a transaction id'); 62 | } 63 | 64 | $path = '/transaction/'.$id; 65 | 66 | return $path; 67 | } 68 | 69 | /** 70 | * Use the results 71 | * 72 | * @param integer $code 73 | * @param array $headers 74 | * @param array $data 75 | * @return integer on failure 76 | */ 77 | protected function handleResult($code, $headers, $data) 78 | { 79 | if ((int)($code / 100) != 2) { 80 | $this->throwException('Error during transaction rollback', $code, $headers, $data); 81 | } 82 | 83 | return true; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /lib/Everyman/Neo4j/Command/SaveIndex.php: -------------------------------------------------------------------------------- 1 | index = $index; 26 | } 27 | 28 | /** 29 | * Return the data to pass 30 | * 31 | * @return mixed 32 | */ 33 | protected function getData() 34 | { 35 | $name = trim((string)$this->index->getName()); 36 | if (!$name) { 37 | throw new Exception('No name specified for index'); 38 | } 39 | $data = array('name' => $name); 40 | 41 | $config = $this->index->getConfig(); 42 | if ($config) { 43 | $data['config'] = $config; 44 | } 45 | 46 | return $data; 47 | } 48 | 49 | /** 50 | * Return the transport method to call 51 | * 52 | * @return string 53 | */ 54 | protected function getMethod() 55 | { 56 | return 'post'; 57 | } 58 | 59 | /** 60 | * Return the path to use 61 | * 62 | * @return string 63 | */ 64 | protected function getPath() 65 | { 66 | $type = trim((string)$this->index->getType()); 67 | if ($type != Index::TypeNode && $type != Index::TypeRelationship) { 68 | throw new Exception('No type specified for index'); 69 | } 70 | 71 | return '/index/'.$type; 72 | } 73 | 74 | /** 75 | * Use the results 76 | * 77 | * @param integer $code 78 | * @param array $headers 79 | * @param array $data 80 | * @return integer on failure 81 | */ 82 | protected function handleResult($code, $headers, $data) 83 | { 84 | if ((int)($code / 100) != 2) { 85 | $this->throwException('Unable to save index', $code, $headers, $data); 86 | } 87 | return true; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /lib/Everyman/Neo4j/Command/SearchIndex.php: -------------------------------------------------------------------------------- 1 | index = $index; 32 | $this->key = $key; 33 | $this->value = $value; 34 | } 35 | 36 | /** 37 | * Return the data to pass 38 | * 39 | * @return mixed 40 | */ 41 | protected function getData() 42 | { 43 | return null; 44 | } 45 | 46 | /** 47 | * Return the transport method to call 48 | * 49 | * @return string 50 | */ 51 | protected function getMethod() 52 | { 53 | return 'get'; 54 | } 55 | 56 | /** 57 | * Return the path to use 58 | * 59 | * @return string 60 | */ 61 | protected function getPath() 62 | { 63 | $type = trim((string)$this->index->getType()); 64 | if ($type != Index::TypeNode && $type != Index::TypeRelationship) { 65 | throw new Exception('No type specified for index'); 66 | } 67 | 68 | $name = trim((string)$this->index->getName()); 69 | if (!$name) { 70 | throw new Exception('No name specified for index'); 71 | } 72 | 73 | $key = trim((string)$this->key); 74 | if (!$key) { 75 | throw new Exception('No key specified to search index'); 76 | } 77 | 78 | $name = rawurlencode($name); 79 | $key = rawurlencode($key); 80 | $value = rawurlencode($this->value); 81 | 82 | return '/index/'.$type.'/'.$name.'/'.$key.'/'.$value; 83 | } 84 | 85 | /** 86 | * Use the results 87 | * 88 | * @param integer $code 89 | * @param array $headers 90 | * @param array $data 91 | * @return integer on failure 92 | */ 93 | protected function handleResult($code, $headers, $data) 94 | { 95 | if ((int)($code / 100) != 2) { 96 | $this->throwException('Unable to search index', $code, $headers, $data); 97 | } 98 | 99 | $buildMethod = $this->index->getType() == Index::TypeNode ? 'makeNode' : 'makeRelationship'; 100 | $results = array(); 101 | foreach ($data as $entityData) { 102 | $results[] = $this->getEntityMapper()->$buildMethod($entityData); 103 | } 104 | return $results; 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /lib/Everyman/Neo4j/Command/SetLabels.php: -------------------------------------------------------------------------------- 1 | hasCapability(Client::CapabilityLabel)) { 29 | throw new \RuntimeException('The connected Neo4j version does not have label capability'); 30 | } 31 | 32 | $nodeId = $node->getId(); 33 | if (!is_numeric($nodeId)) { 34 | throw new \InvalidArgumentException("Cannot set labels on an unsaved node"); 35 | } 36 | 37 | if (!$labels) { 38 | throw new \InvalidArgumentException("No labels given to set on node"); 39 | } 40 | 41 | $labelSet = implode(':', array_map(function ($label) { 42 | if (!($label instanceof Label)) { 43 | throw new \InvalidArgumentException("Cannot set a non-label"); 44 | } 45 | $name = str_replace('`', '``', $label->getName()); 46 | return "`{$name}`"; 47 | }, $labels)); 48 | 49 | $setCommand = $remove ? 'REMOVE' : 'SET'; 50 | 51 | $query = "START n=node({nodeId}) {$setCommand} n:{$labelSet} RETURN labels(n) AS labels"; 52 | $params = array('nodeId' => $nodeId); 53 | 54 | $cypher = new Query($client, $query, $params); 55 | parent::__construct($client, $cypher); 56 | } 57 | 58 | /** 59 | * Use the results 60 | * 61 | * @param integer $code 62 | * @param array $headers 63 | * @param array $data 64 | * @return array of Label 65 | */ 66 | protected function handleResult($code, $headers, $data) 67 | { 68 | $results = parent::handleResult($code, $headers, $data); 69 | 70 | $nodeLabels = array(); 71 | foreach ($results[0]['labels'] as $labelName) { 72 | $nodeLabels[] = $this->client->makeLabel($labelName); 73 | } 74 | return $nodeLabels; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /lib/Everyman/Neo4j/Command/UpdateNode.php: -------------------------------------------------------------------------------- 1 | node = $node; 26 | } 27 | 28 | /** 29 | * Return the data to pass 30 | * 31 | * @return mixed 32 | */ 33 | protected function getData() 34 | { 35 | return $this->node->getProperties(); 36 | } 37 | 38 | /** 39 | * Return the transport method to call 40 | * 41 | * @return string 42 | */ 43 | protected function getMethod() 44 | { 45 | return 'put'; 46 | } 47 | 48 | /** 49 | * Return the path to use 50 | * 51 | * @return string 52 | */ 53 | protected function getPath() 54 | { 55 | if (!$this->node->hasId()) { 56 | throw new Exception('No node id specified'); 57 | } 58 | return '/node/'.$this->node->getId().'/properties'; 59 | } 60 | 61 | /** 62 | * Use the results 63 | * 64 | * @param integer $code 65 | * @param array $headers 66 | * @param array $data 67 | * @return boolean true on success 68 | * @throws Exception on failure 69 | */ 70 | protected function handleResult($code, $headers, $data) 71 | { 72 | if ((int)($code / 100) == 2) { 73 | $this->getEntityCache()->setCachedEntity($this->node); 74 | return true; 75 | } else { 76 | $this->throwException('Unable to update node', $code, $headers, $data); 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /lib/Everyman/Neo4j/Command/UpdateRelationship.php: -------------------------------------------------------------------------------- 1 | rel = $rel; 26 | } 27 | 28 | /** 29 | * Return the data to pass 30 | * 31 | * @return mixed 32 | */ 33 | protected function getData() 34 | { 35 | return $this->rel->getProperties(); 36 | } 37 | 38 | /** 39 | * Return the transport method to call 40 | * 41 | * @return string 42 | */ 43 | protected function getMethod() 44 | { 45 | return 'put'; 46 | } 47 | 48 | /** 49 | * Return the path to use 50 | * 51 | * @return string 52 | */ 53 | protected function getPath() 54 | { 55 | if (!$this->rel->hasId()) { 56 | throw new Exception('No relationship id specified'); 57 | } 58 | return '/relationship/'.$this->rel->getId().'/properties'; 59 | } 60 | 61 | /** 62 | * Use the results 63 | * 64 | * @param integer $code 65 | * @param array $headers 66 | * @param array $data 67 | * @return boolean true on success 68 | * @throws Exception on failure 69 | */ 70 | protected function handleResult($code, $headers, $data) 71 | { 72 | if ((int)($code / 100) == 2) { 73 | $this->getEntityCache()->setCachedEntity($this->rel); 74 | return true; 75 | } else { 76 | $this->throwException('Unable to update relationship', $code, $headers, $data); 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /lib/Everyman/Neo4j/Cypher/Query.php: -------------------------------------------------------------------------------- 1 | client = $client; 32 | $this->template = $template; 33 | $this->vars = $vars; 34 | } 35 | 36 | /** 37 | * Get the query script 38 | * 39 | * @return string 40 | */ 41 | public function getQuery() 42 | { 43 | return $this->template; 44 | } 45 | 46 | /** 47 | * Get the template parameters 48 | * 49 | * @return array 50 | */ 51 | public function getParameters() 52 | { 53 | return $this->vars; 54 | } 55 | 56 | /** 57 | * Retrieve the query results 58 | * 59 | * @return Neo4j\Query\ResultSet 60 | */ 61 | public function getResultSet() 62 | { 63 | if ($this->result === null) { 64 | $this->result = $this->client->executeCypherQuery($this); 65 | } 66 | 67 | return $this->result; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /lib/Everyman/Neo4j/EntityMapper.php: -------------------------------------------------------------------------------- 1 | client = $client; 20 | } 21 | 22 | /** 23 | * Given any object, see if it fulfills the contract 24 | * for being a path, node or relationship data returned by the 25 | * server. If so, return a full Path, Node or Relationship instance. 26 | * Else, return the value untainted. 27 | * 28 | * @param mixed $value 29 | * @return mixed 30 | */ 31 | public function getEntityFor($value) 32 | { 33 | if (is_array($value)) { 34 | if (array_key_exists('self', $value)) { 35 | if (array_key_exists('type', $value)) { 36 | $value = $this->makeRelationship($value); 37 | } else { 38 | $value = $this->makeNode($value); 39 | } 40 | } else if (array_key_exists('nodes', $value) && array_key_exists('relationships', $value)) { 41 | $value = $this->populatePath(new Path($this->client), $value); 42 | } 43 | } 44 | return $value; 45 | } 46 | 47 | /** 48 | * Get an id from a URI 49 | * 50 | * @param string $uri 51 | * @return mixed 52 | */ 53 | public function getIdFromUri($uri) 54 | { 55 | $uriParts = explode('/', $uri); 56 | return array_pop($uriParts); 57 | } 58 | 59 | /** 60 | * Generate and populate a node from the given data 61 | * 62 | * @param array $data 63 | * @return Node 64 | */ 65 | public function makeNode($data) 66 | { 67 | $node = $this->getNodeFromUri($data['self']); 68 | return $this->populateNode($node, $data); 69 | } 70 | 71 | /** 72 | * Generate and populate a relationship from the given data 73 | * 74 | * @param array $data 75 | * @return Relationship 76 | */ 77 | public function makeRelationship($data) 78 | { 79 | $rel = $this->getRelationshipFromUri($data['self']); 80 | return $this->populateRelationship($rel, $data); 81 | } 82 | 83 | /** 84 | * Fill a node with data 85 | * 86 | * @param Node $node 87 | * @param array $data 88 | * @return Node 89 | */ 90 | public function populateNode(Node $node, $data) 91 | { 92 | $node->useLazyLoad(false); 93 | $node->setProperties($data['data']); 94 | return $node; 95 | } 96 | 97 | /** 98 | * Fill a path with data 99 | * 100 | * @param Path $path 101 | * @param array $data 102 | * @param boolean $full 103 | * @return Path 104 | */ 105 | public function populatePath(Path $path, $data, $full=false) 106 | { 107 | foreach ($data['relationships'] as $relData) { 108 | $relUri = $full ? $relData['self'] : $relData; 109 | $rel = $this->getRelationshipFromUri($relUri); 110 | if ($full) { 111 | $rel = $this->populateRelationship($rel, $relData); 112 | } 113 | $path->appendRelationship($rel); 114 | } 115 | 116 | foreach ($data['nodes'] as $nodeData) { 117 | $nodeUri = $full ? $nodeData['self'] : $nodeData; 118 | $node = $this->getNodeFromUri($nodeUri); 119 | if ($full) { 120 | $node = $this->populateNode($node, $nodeData); 121 | } 122 | $path->appendNode($node); 123 | } 124 | 125 | return $path; 126 | } 127 | 128 | /** 129 | * Fill a relationship with data 130 | * 131 | * @param Relationship $rel 132 | * @param array $data 133 | * @return Relationship 134 | */ 135 | public function populateRelationship(Relationship $rel, $data) 136 | { 137 | $rel->useLazyLoad(false); 138 | $rel->setProperties($data['data']); 139 | $rel->setType($data['type']); 140 | 141 | $rel->setStartNode($this->getNodeFromUri($data['start'])); 142 | $rel->setEndNode($this->getNodeFromUri($data['end'])); 143 | 144 | return $rel; 145 | } 146 | 147 | /** 148 | * Retrieve a node by it's 'self' uri 149 | * 150 | * @param string $uri 151 | * @return Node 152 | */ 153 | protected function getNodeFromUri($uri) 154 | { 155 | $nodeId = $this->getIdFromUri($uri); 156 | return $this->client->getNode($nodeId, true); 157 | } 158 | 159 | /** 160 | * Retrieve a relationship by it's 'self' uri 161 | * 162 | * @param string $uri 163 | * @return Relationship 164 | */ 165 | protected function getRelationshipFromUri($uri) 166 | { 167 | $relId = $this->getIdFromUri($uri); 168 | return $this->client->getRelationship($relId, true); 169 | } 170 | } 171 | -------------------------------------------------------------------------------- /lib/Everyman/Neo4j/Exception.php: -------------------------------------------------------------------------------- 1 | headers = $headers; 12 | $this->data = $data; 13 | parent::__construct($message, $code); 14 | } 15 | 16 | /** 17 | * Return response headers 18 | * @return array Response headers 19 | */ 20 | public function getHeaders() 21 | { 22 | return $this->headers; 23 | } 24 | 25 | /** 26 | * Return response data 27 | * @return array Response data 28 | */ 29 | public function getData() 30 | { 31 | return $this->data; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /lib/Everyman/Neo4j/Geoff.php: -------------------------------------------------------------------------------- 1 | client = $client; 21 | } 22 | 23 | /** 24 | * Dump path information to a GEOFF string or file 25 | * 26 | * @param mixed $paths a single Path object or an array of Path objects 27 | * @param stream $handle 28 | * @return mixed stream or string 29 | */ 30 | public function dump($paths, $handle=null) 31 | { 32 | $returnString = false; 33 | if (!$handle) { 34 | $returnString = true; 35 | $handle = fopen('data:text/plain,', 'w+'); 36 | } 37 | 38 | $exporter = new Geoff\Exporter(); 39 | $exporter->dump($paths, $handle); 40 | 41 | if ($returnString) { 42 | return stream_get_contents($handle, -1, 0); 43 | } 44 | return $handle; 45 | } 46 | 47 | /** 48 | * Load a GEOFF string or file 49 | * 50 | * @param mixed $handle 51 | * @param Batch $batch 52 | * @return Batch 53 | */ 54 | public function load($handle, Batch $batch=null) 55 | { 56 | if (is_string($handle)) { 57 | $handle = fopen('data:text/plain,'.urlencode($handle), 'r'); 58 | } 59 | 60 | $importer = new Geoff\Importer($this->client); 61 | return $importer->load($handle, $batch); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /lib/Everyman/Neo4j/Geoff/Exporter.php: -------------------------------------------------------------------------------- 1 | getNodes(); 36 | foreach ($pathNodes as $node) { 37 | $nodes[$node->getId()] = $node; 38 | } 39 | 40 | $pathRels = $path->getRelationships(); 41 | foreach ($pathRels as $rel) { 42 | $rels[$rel->getId()] = $rel; 43 | } 44 | } 45 | 46 | foreach ($nodes as $id => $node) { 47 | $properties = $node->getProperties(); 48 | $format = $properties ? "(%s)\t%s\n" : "(%s)\n"; 49 | fprintf( 50 | $handle, 51 | $format, 52 | $id, 53 | json_encode($properties) 54 | ); 55 | } 56 | 57 | foreach ($rels as $id => $rel) { 58 | $properties = $rel->getProperties(); 59 | $format = "(%s)-[%s:%s]->(%s)"; 60 | $format .= $properties ? "\t%s\n" : "\n"; 61 | fprintf( 62 | $handle, 63 | $format, 64 | $rel->getStartNode()->getId(), 65 | $id, 66 | $rel->getType(), 67 | $rel->getEndNode()->getId(), 68 | json_encode($properties) 69 | ); 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /lib/Everyman/Neo4j/Gremlin/Query.php: -------------------------------------------------------------------------------- 1 | client = $client; 32 | $this->script = $script; 33 | $this->vars = $vars; 34 | } 35 | 36 | /** 37 | * Get the query script 38 | * 39 | * @return string 40 | */ 41 | public function getQuery() 42 | { 43 | return $this->script; 44 | } 45 | 46 | /** 47 | * Get the template parameters 48 | * 49 | * @return array 50 | */ 51 | public function getParameters() 52 | { 53 | return $this->vars; 54 | } 55 | 56 | /** 57 | * Retrieve the query results 58 | * 59 | * @return Neo4j\Query\ResultSet 60 | */ 61 | public function getResultSet() 62 | { 63 | if ($this->result === null) { 64 | $this->result = $this->client->executeGremlinQuery($this); 65 | } 66 | 67 | return $this->result; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /lib/Everyman/Neo4j/Index.php: -------------------------------------------------------------------------------- 1 | client = $client; 28 | $this->type = $type; 29 | $this->name = $name; 30 | $this->config = $config; 31 | } 32 | 33 | /** 34 | * Add an entity to the index 35 | * 36 | * @param PropertyContainer $entity 37 | * @param string $key 38 | * @param string $value 39 | * @return boolean 40 | */ 41 | public function add($entity, $key, $value) 42 | { 43 | return $this->client->addToIndex($this, $entity, $key, $value); 44 | } 45 | 46 | /** 47 | * Delete this index 48 | * 49 | * @return boolean 50 | */ 51 | public function delete() 52 | { 53 | return $this->client->deleteIndex($this); 54 | } 55 | 56 | /** 57 | * Find entities 58 | * 59 | * @param string $key 60 | * @param string $value 61 | * @return array 62 | */ 63 | public function find($key, $value) 64 | { 65 | return $this->client->searchIndex($this, $key, $value); 66 | } 67 | 68 | /** 69 | * Find a single entity 70 | * 71 | * @param string $key 72 | * @param string $value 73 | * @return PropertyContainer 74 | */ 75 | public function findOne($key, $value) 76 | { 77 | $entities = $this->client->searchIndex($this, $key, $value); 78 | return $entities ? $entities[0] : null; 79 | } 80 | 81 | /** 82 | * Get the configuration options for this index 83 | * 84 | * Configuration options are only used during index creation, 85 | * see `save` 86 | * 87 | * @return array 88 | */ 89 | public function getConfig() 90 | { 91 | return $this->config; 92 | } 93 | 94 | /** 95 | * Get the index name 96 | * 97 | * @return string 98 | */ 99 | public function getName() 100 | { 101 | return $this->name; 102 | } 103 | 104 | /** 105 | * Get the index type 106 | * 107 | * @return string 108 | */ 109 | public function getType() 110 | { 111 | return $this->type; 112 | } 113 | 114 | /** 115 | * Query index to find entities 116 | * 117 | * @param string $query 118 | * @return array 119 | */ 120 | public function query($query) 121 | { 122 | return $this->client->queryIndex($this, $query); 123 | } 124 | 125 | /** 126 | * Query index to find a single entity 127 | * 128 | * @param string $query 129 | * @return PropertyContainer 130 | */ 131 | public function queryOne($query) 132 | { 133 | $entities = $this->client->queryIndex($this, $query); 134 | return $entities ? $entities[0] : null; 135 | } 136 | 137 | /** 138 | * Remove an entity from the index 139 | * If $value is not given, all reference of the entity for the key 140 | * are removed. 141 | * If $key is not given, all reference of the entity are removed. 142 | * 143 | * @param PropertyContainer $entity 144 | * @param string $key 145 | * @param string $value 146 | * @return boolean 147 | */ 148 | public function remove($entity, $key=null, $value=null) 149 | { 150 | return $this->client->removeFromIndex($this, $entity, $key, $value); 151 | } 152 | 153 | /** 154 | * Save this index 155 | * 156 | * @return boolean 157 | */ 158 | public function save() 159 | { 160 | return $this->client->saveIndex($this); 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /lib/Everyman/Neo4j/Index/NodeFulltextIndex.php: -------------------------------------------------------------------------------- 1 | setClient($client); 35 | $this->name = (string)$name; 36 | } 37 | 38 | /** 39 | * Set the client to use with this Label object 40 | * 41 | * @param Client $client 42 | * @return Label 43 | */ 44 | public function setClient(Client $client) 45 | { 46 | $this->client = $client; 47 | return $this; 48 | } 49 | 50 | /** 51 | * Get our client 52 | * 53 | * @return Client 54 | */ 55 | public function getClient() 56 | { 57 | return $this->client; 58 | } 59 | 60 | /** 61 | * Return the label name 62 | * 63 | * @return string 64 | */ 65 | public function getName() 66 | { 67 | return $this->name; 68 | } 69 | 70 | /** 71 | * Get the nodes with this label 72 | * 73 | * If a property and value are given, only return 74 | * nodes where the given property equals the value 75 | * 76 | * @param string $propertyName 77 | * @param mixed $propertyValue 78 | * @return Query\Row 79 | * @throws Exception on failure 80 | */ 81 | public function getNodes($propertyName=null, $propertyValue=null) 82 | { 83 | return $this->client->getNodesForLabel($this, $propertyName, $propertyValue); 84 | } 85 | 86 | /** 87 | * Only serialize our name property 88 | * 89 | * @return array 90 | */ 91 | public function __sleep() 92 | { 93 | return array('name'); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /lib/Everyman/Neo4j/Node.php: -------------------------------------------------------------------------------- 1 | labels) { 25 | foreach ($this->labels as $label) { 26 | if (!$label->getClient()) { 27 | $label->setClient($client); 28 | } 29 | } 30 | } 31 | return $this; 32 | } 33 | 34 | /** 35 | * Add labels to this node 36 | * 37 | * @param array $labels 38 | * @return array of all the Labels on this node, including those just added 39 | */ 40 | public function addLabels($labels) 41 | { 42 | $this->labels = $this->client->addLabels($this, $labels); 43 | return $this->labels; 44 | } 45 | 46 | /** 47 | * Delete this node 48 | * 49 | * @return PropertyContainer 50 | * @throws Exception on failure 51 | */ 52 | public function delete() 53 | { 54 | $this->client->deleteNode($this); 55 | return $this; 56 | } 57 | 58 | /** 59 | * Find paths from this node to the given node 60 | * 61 | * @param Node $to 62 | * @param string $type 63 | * @param string $dir 64 | * @return PathFinder 65 | */ 66 | public function findPathsTo(Node $to, $type=null, $dir=null) 67 | { 68 | $finder = new PathFinder($this->client); 69 | $finder->setStartNode($this); 70 | $finder->setEndNode($to); 71 | if ($dir) { 72 | $finder->setDirection($dir); 73 | } 74 | 75 | if ($type) { 76 | $finder->setType($type); 77 | } 78 | 79 | return $finder; 80 | } 81 | 82 | /** 83 | * Get the first relationship of this node that matches the given criteria 84 | * 85 | * @param mixed $types string or array of strings 86 | * @param string $dir 87 | * @return Relationship 88 | */ 89 | public function getFirstRelationship($types=array(), $dir=null) 90 | { 91 | $rels = $this->client->getNodeRelationships($this, $types, $dir); 92 | if (count($rels) < 1) { 93 | return null; 94 | } 95 | return $rels[0]; 96 | } 97 | 98 | /** 99 | * Get relationships of this node 100 | * 101 | * @param mixed $types string or array of strings 102 | * @param string $dir 103 | * @return array of Relationship 104 | */ 105 | public function getRelationships($types=array(), $dir=null) 106 | { 107 | return $this->client->getNodeRelationships($this, $types, $dir); 108 | } 109 | 110 | /** 111 | * List labels for this node 112 | * 113 | * @return array 114 | * @throws Exception on failure 115 | */ 116 | public function getLabels() 117 | { 118 | if (is_null($this->labels)) { 119 | $this->labels = $this->client->getLabels($this); 120 | } 121 | return $this->labels; 122 | } 123 | 124 | /** 125 | * Load this node 126 | * 127 | * @return PropertyContainer 128 | * @throws Exception on failure 129 | */ 130 | public function load() 131 | { 132 | $this->client->loadNode($this); 133 | return $this; 134 | } 135 | 136 | /** 137 | * Make a new relationship 138 | * 139 | * @param Node $to 140 | * @param string $type 141 | * @return Relationship 142 | */ 143 | public function relateTo(Node $to, $type) 144 | { 145 | $rel = $this->client->makeRelationship(); 146 | $rel->setStartNode($this); 147 | $rel->setEndNode($to); 148 | $rel->setType($type); 149 | 150 | return $rel; 151 | } 152 | 153 | /** 154 | * Remove labels from this node 155 | * 156 | * @param array $labels 157 | * @return array of all the Labels on this node, after removing the given labels 158 | */ 159 | public function removeLabels($labels) 160 | { 161 | $this->labels = $this->client->removeLabels($this, $labels); 162 | return $this->labels; 163 | } 164 | 165 | /** 166 | * Save this node 167 | * 168 | * @return PropertyContainer 169 | * @throws Exception on failure 170 | */ 171 | public function save() 172 | { 173 | $this->client->saveNode($this); 174 | $this->useLazyLoad(false); 175 | return $this; 176 | } 177 | 178 | /** 179 | * Be sure to add our properties to the things to serialize 180 | * 181 | * @return array 182 | */ 183 | public function __sleep() 184 | { 185 | return array_merge(parent::__sleep(), array('labels')); 186 | } 187 | } 188 | -------------------------------------------------------------------------------- /lib/Everyman/Neo4j/Pager.php: -------------------------------------------------------------------------------- 1 | traversal = $traversal; 27 | $this->startNode = $startNode; 28 | $this->returnType = $returnType; 29 | } 30 | 31 | /** 32 | * Get the paged traversal id 33 | * 34 | * @return string 35 | */ 36 | public function getId() 37 | { 38 | return $this->id; 39 | } 40 | 41 | /** 42 | * Get the lease time, in secods 43 | * 44 | * @return integer 45 | */ 46 | public function getLeaseTime() 47 | { 48 | return $this->leaseTime; 49 | } 50 | 51 | /** 52 | * Get the next page of results 53 | * If the traversal hasn't been run yet, this will run it 54 | * 55 | * @return array 56 | */ 57 | public function getNextResults() 58 | { 59 | return $this->traversal->getClient()->executePagedTraversal($this); 60 | } 61 | 62 | /** 63 | * Get the maximum result page set size 64 | * 65 | * @return integer 66 | */ 67 | public function getPageSize() 68 | { 69 | return $this->pageSize; 70 | } 71 | 72 | /** 73 | * Get the return type 74 | * 75 | * @return string 76 | */ 77 | public function getReturnType() 78 | { 79 | return $this->returnType; 80 | } 81 | 82 | /** 83 | * Return the start node of the traversal 84 | * 85 | * @return Node 86 | */ 87 | public function getStartNode() 88 | { 89 | return $this->startNode; 90 | } 91 | 92 | /** 93 | * Get the traversal being paginated 94 | * 95 | * @return Traversal 96 | */ 97 | public function getTraversal() 98 | { 99 | return $this->traversal; 100 | } 101 | 102 | /** 103 | * Set the paged traversal id 104 | * 105 | * @param string $id 106 | * @return Traversal 107 | */ 108 | public function setId($id) 109 | { 110 | $this->id = $id; 111 | return $this; 112 | } 113 | 114 | /** 115 | * Set the lease time 116 | * 117 | * @param integer $leaseTime 118 | * @return Traversal 119 | */ 120 | public function setLeaseTime($leaseTime) 121 | { 122 | $this->leaseTime = $leaseTime; 123 | return $this; 124 | } 125 | 126 | /** 127 | * Set the page size 128 | * 129 | * @param integer $pageSize 130 | * @return Traversal 131 | */ 132 | public function setPageSize($pageSize) 133 | { 134 | $this->pageSize = $pageSize; 135 | return $this; 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /lib/Everyman/Neo4j/Path.php: -------------------------------------------------------------------------------- 1 | nodes[] = $node; 25 | } 26 | 27 | /** 28 | * Add another relationship to the end of this path 29 | * 30 | * @param Relationship $rel 31 | * @return Path 32 | */ 33 | public function appendRelationship(Relationship $rel) 34 | { 35 | $this->relationships[] = $rel; 36 | } 37 | 38 | /** 39 | * Get the number of relationships in this path 40 | * 41 | * @return integer 42 | */ 43 | public function count() 44 | { 45 | return $this->context == self::ContextNode ? count($this->nodes) : count($this->relationships); 46 | } 47 | 48 | /** 49 | * Get the current context for iteration 50 | * 51 | * @return string 52 | */ 53 | public function getContext() 54 | { 55 | return $this->context; 56 | } 57 | 58 | /** 59 | * Get the end node 60 | * 61 | * @return Node 62 | */ 63 | public function getEndNode() 64 | { 65 | $length = count($this->nodes); 66 | if ($length) { 67 | return $this->nodes[$length-1]; 68 | } 69 | return null; 70 | } 71 | 72 | /** 73 | * Get the number of relationships in this path 74 | * 75 | * @return integer 76 | */ 77 | public function getLength() 78 | { 79 | return $this->count(); 80 | } 81 | 82 | /** 83 | * Return an iterator for iterating through the path 84 | * 85 | * @return Iterator 86 | */ 87 | public function getIterator() 88 | { 89 | return $this->context == self::ContextNode 90 | ? new \ArrayIterator($this->nodes) 91 | : new \ArrayIterator($this->relationships); 92 | } 93 | 94 | /** 95 | * Get the list of nodes that make up this path 96 | * 97 | * @return array 98 | */ 99 | public function getNodes() 100 | { 101 | return $this->nodes; 102 | } 103 | 104 | /** 105 | * Get the list of relationships that make up this path 106 | * 107 | * @return array 108 | */ 109 | public function getRelationships() 110 | { 111 | return $this->relationships; 112 | } 113 | 114 | /** 115 | * Get the start node 116 | * 117 | * @return Node 118 | */ 119 | public function getStartNode() 120 | { 121 | $length = count($this->nodes); 122 | if ($length) { 123 | return $this->nodes[0]; 124 | } 125 | return null; 126 | } 127 | 128 | /** 129 | * Set the context for iteration 130 | * 131 | * @param string $context 132 | * @return Path 133 | */ 134 | public function setContext($context) 135 | { 136 | if ($context != self::ContextNode && $context != self::ContextRelationship) { 137 | $context = self::ContextNode; 138 | } 139 | $this->context = $context; 140 | return $this; 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /lib/Everyman/Neo4j/Query.php: -------------------------------------------------------------------------------- 1 | client = $client; 28 | if (is_array($result) && array_key_exists('data', $result)) { 29 | $this->data = $result['data']; 30 | $this->columns = $result['columns']; 31 | } 32 | } 33 | 34 | /** 35 | * Return the list of column names 36 | * 37 | * @return array 38 | */ 39 | public function getColumns() 40 | { 41 | return $this->columns; 42 | } 43 | 44 | // ArrayAccess API 45 | 46 | public function offsetExists($offset) 47 | { 48 | return isset($this->data[$offset]); 49 | } 50 | 51 | public function offsetGet($offset) 52 | { 53 | if (!isset($this->rows[$offset])) { 54 | $this->rows[$offset] = new Row($this->client, $this->columns, $this->data[$offset]); 55 | } 56 | return $this->rows[$offset]; 57 | } 58 | 59 | public function offsetSet($offset, $value) 60 | { 61 | throw new \BadMethodCallException("You cannot modify a query result."); 62 | } 63 | 64 | public function offsetUnset($offset) 65 | { 66 | throw new \BadMethodCallException("You cannot modify a query result."); 67 | } 68 | 69 | 70 | // Countable API 71 | 72 | public function count() 73 | { 74 | return count($this->data); 75 | } 76 | 77 | 78 | // Iterator API 79 | 80 | public function rewind() 81 | { 82 | $this->position = 0; 83 | } 84 | 85 | public function current() 86 | { 87 | return $this[$this->position]; 88 | } 89 | 90 | public function key() 91 | { 92 | return $this->position; 93 | } 94 | 95 | public function next() 96 | { 97 | ++$this->position; 98 | } 99 | 100 | public function valid() 101 | { 102 | return isset($this->data[$this->position]); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /lib/Everyman/Neo4j/Query/Row.php: -------------------------------------------------------------------------------- 1 | client = $client; 30 | $this->raw = $rowData; 31 | $this->data = array(); 32 | $this->columns = $columns; 33 | } 34 | 35 | // ArrayAccess API 36 | 37 | public function offsetExists($offset) 38 | { 39 | if (!is_integer($offset)) { 40 | 41 | $rawOffset = array_search($offset, $this->columns); 42 | 43 | if ($rawOffset === false) { 44 | return false; 45 | } 46 | 47 | return isset($this->raw[$rawOffset]); 48 | } 49 | 50 | return isset($this->raw[$offset]); 51 | } 52 | 53 | public function offsetGet($offset) 54 | { 55 | if (!is_integer($offset)) { 56 | $offset = array_search($offset, $this->columns); 57 | } 58 | 59 | if (!isset($this->data[$offset])) { 60 | $raw = $this->raw[$offset]; 61 | $data = $this->client->getEntityMapper()->getEntityFor($raw); 62 | if (is_array($data)) { 63 | $data = new Row($this->client, array_keys($raw), array_values($raw)); 64 | } 65 | $this->data[$offset] = $data; 66 | } 67 | 68 | return $this->data[$offset]; 69 | } 70 | 71 | public function offsetSet($offset, $value) 72 | { 73 | throw new \BadMethodCallException("You cannot modify a result row."); 74 | } 75 | 76 | public function offsetUnset($offset) 77 | { 78 | throw new \BadMethodCallException("You cannot modify a result row."); 79 | } 80 | 81 | 82 | // Countable API 83 | 84 | public function count() 85 | { 86 | return count($this->raw); 87 | } 88 | 89 | 90 | // Iterator API 91 | 92 | public function rewind() 93 | { 94 | $this->position = 0; 95 | } 96 | 97 | public function current() 98 | { 99 | return $this[$this->position]; 100 | } 101 | 102 | public function key() 103 | { 104 | return $this->columns[$this->position]; 105 | } 106 | 107 | public function next() 108 | { 109 | ++$this->position; 110 | } 111 | 112 | public function valid() 113 | { 114 | return $this->position < count($this->raw); 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /lib/Everyman/Neo4j/Relationship.php: -------------------------------------------------------------------------------- 1 | start && !$this->start->getClient()) { 37 | $this->start->setClient($client); 38 | } 39 | if ($this->end && !$this->end->getClient()) { 40 | $this->end->setClient($client); 41 | } 42 | return $this; 43 | } 44 | 45 | /** 46 | * Delete this relationship 47 | * 48 | * @return PropertyContainer 49 | * @throws Exception on failure 50 | */ 51 | public function delete() 52 | { 53 | $this->client->deleteRelationship($this); 54 | return $this; 55 | } 56 | 57 | /** 58 | * Get the end node 59 | * 60 | * @return Node 61 | */ 62 | public function getEndNode() 63 | { 64 | if (null === $this->end) { 65 | $this->loadProperties(); 66 | } 67 | return $this->end; 68 | } 69 | 70 | /** 71 | * Get the start node 72 | * 73 | * @return Node 74 | */ 75 | public function getStartNode() 76 | { 77 | if (null === $this->start) { 78 | $this->loadProperties(); 79 | } 80 | return $this->start; 81 | } 82 | 83 | /** 84 | * Get the relationship type 85 | * 86 | * @return string 87 | */ 88 | public function getType() 89 | { 90 | $this->loadProperties(); 91 | return $this->type; 92 | } 93 | 94 | /** 95 | * Load this relationship 96 | * 97 | * @return PropertyContainer 98 | * @throws Exception on failure 99 | */ 100 | public function load() 101 | { 102 | $this->client->loadRelationship($this); 103 | return $this; 104 | } 105 | 106 | /** 107 | * Save this node 108 | * 109 | * @return PropertyContainer 110 | * @throws Exception on failure 111 | */ 112 | public function save() 113 | { 114 | $this->client->saveRelationship($this); 115 | $this->useLazyLoad(false); 116 | return $this; 117 | } 118 | 119 | /** 120 | * Set the end node 121 | * 122 | * @param Node $end 123 | * @return Relationship 124 | */ 125 | public function setEndNode(Node $end) 126 | { 127 | $this->end = $end; 128 | return $this; 129 | } 130 | 131 | /** 132 | * Set the start node 133 | * 134 | * @param Node $start 135 | * @return Relationship 136 | */ 137 | public function setStartNode(Node $start) 138 | { 139 | $this->start = $start; 140 | return $this; 141 | } 142 | 143 | /** 144 | * Set the type 145 | * 146 | * @param string $type 147 | * @return Relationship 148 | */ 149 | public function setType($type) 150 | { 151 | $this->type = $type; 152 | return $this; 153 | } 154 | 155 | 156 | /** 157 | * Be sure to add our properties to the things to serialize 158 | * 159 | * @return array 160 | */ 161 | public function __sleep() 162 | { 163 | return array_merge(parent::__sleep(), array('start', 'end', 'type')); 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /lib/Everyman/Neo4j/Transaction.php: -------------------------------------------------------------------------------- 1 | client = $client; 22 | } 23 | 24 | /** 25 | * Add statements to this transaction 26 | * 27 | * @param mixed $statements a single or list of Cypher\Query objects to add to the transaction 28 | * @param boolean $commit should this transaction be committed with these statements? 29 | * @return Query\ResultSet 30 | */ 31 | public function addStatements($statements, $commit=false) 32 | { 33 | $unwrap = false; 34 | if (!is_array($statements)) { 35 | $statements = array($statements); 36 | $unwrap = true; 37 | } 38 | 39 | $result = $this->performClientAction(function ($client, $transaction) use ($statements, $commit) { 40 | return $client->addStatementsToTransaction($transaction, $statements, $commit); 41 | }, $commit, false); 42 | 43 | if ($unwrap) { 44 | $result = reset($result); 45 | } 46 | 47 | return $result; 48 | } 49 | 50 | /** 51 | * Commit this transaction immediately, without adding any new statements 52 | * 53 | * @return Transaction 54 | */ 55 | public function commit() 56 | { 57 | $this->performClientAction(function ($client, $transaction) { 58 | $client->addStatementsToTransaction($transaction, array(), true); 59 | }, true); 60 | return $this; 61 | } 62 | 63 | /** 64 | * Return the transaction id 65 | * 66 | * @return integer 67 | */ 68 | public function getId() 69 | { 70 | return $this->id; 71 | } 72 | 73 | /** 74 | * Has this transaction been closed? 75 | * 76 | * @return boolean 77 | */ 78 | public function isClosed() 79 | { 80 | return $this->isClosed; 81 | } 82 | 83 | /** 84 | * Has this transaction experienced an error? 85 | * 86 | * @return boolean 87 | */ 88 | public function isError() 89 | { 90 | return $this->isError; 91 | } 92 | 93 | /** 94 | * Ask for more time to keep this transaction open 95 | * 96 | * @return Transaction 97 | */ 98 | public function keepAlive() 99 | { 100 | $this->performClientAction(function ($client, $transaction) { 101 | $client->addStatementsToTransaction($transaction); 102 | }, false); 103 | return $this; 104 | } 105 | 106 | /** 107 | * Rollback the transaction 108 | * 109 | * @return Transaction 110 | */ 111 | public function rollback() 112 | { 113 | $this->performClientAction(function ($client, $transaction) { 114 | $client->rollbackTransaction($transaction); 115 | }, true); 116 | return $this; 117 | } 118 | 119 | /** 120 | * Set the transaction id 121 | * 122 | * Once an id has been set, the same id can be set again. 123 | * Attempting to set a different id will throw an InvalidArgumentException. 124 | * 125 | * @param integer $id 126 | * @return Transaction 127 | * @throws InvalidArgumentException if an id is given that is different from the existing id 128 | */ 129 | public function setId($id) 130 | { 131 | if ($this->id && $this->id != $id) { 132 | throw new \InvalidArgumentException("Cannot set a new id on a transaction once an id has been set"); 133 | } 134 | 135 | $this->id = $id; 136 | return $this; 137 | } 138 | 139 | /** 140 | * Perform an action against the client 141 | * 142 | * @param callable $action 143 | * @param boolean $shouldClose 144 | * @param boolean $requireId 145 | */ 146 | protected function performClientAction($action, $shouldClose, $requireId=true) 147 | { 148 | if ($this->isClosed()) { 149 | throw new Exception('Transaction is already closed'); 150 | } 151 | 152 | $result = null; 153 | if (!$requireId || $this->getId()) { 154 | try { 155 | $result = $action($this->client, $this); 156 | } catch (\Exception $e) { 157 | $this->isClosed = true; 158 | $this->isError = true; 159 | throw $e; 160 | } 161 | } 162 | 163 | $this->isClosed = $shouldClose; 164 | 165 | return $result; 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /lib/Everyman/Neo4j/Transport.php: -------------------------------------------------------------------------------- 1 | host = $host; 32 | $this->port = $port; 33 | } 34 | 35 | /** 36 | * Return the Neo4j REST endpoint 37 | * 38 | * @return string 39 | */ 40 | public function getEndpoint() 41 | { 42 | return "{$this->scheme}://{$this->host}:{$this->port}{$this->path}"; 43 | } 44 | 45 | /** 46 | * Encode data for transport 47 | * 48 | * @param mixed $data 49 | * @return string 50 | */ 51 | public function encodeData($data) 52 | { 53 | $encoded = ''; 54 | if (!is_scalar($data)) { 55 | if ($data) { 56 | $keys = array_keys($data); 57 | $nonNumeric = array_filter($keys, function ($var) { 58 | return !is_int($var); 59 | }); 60 | if ($nonNumeric) { 61 | $data = (object)$data; 62 | } 63 | } else { 64 | $data = (object)$data; 65 | } 66 | } 67 | 68 | $encoded = json_encode($data); 69 | return $encoded; 70 | } 71 | 72 | /** 73 | * Make a request against the endpoint 74 | * Returned array has the following elements: 75 | * 'code' => the HTTP status code returned 76 | * 'headers' => array of HTTP headers, indexed by header name 77 | * 'data' => array return data 78 | * 79 | * @param string $method 80 | * @param string $path 81 | * @param array $data 82 | * @return array 83 | */ 84 | abstract public function makeRequest($method, $path, $data=array()); 85 | 86 | /** 87 | * Make a GET request 88 | * 89 | * @param $path 90 | * @param $data 91 | * @return array see 'makeRequest' 92 | */ 93 | public function get($path, $data=array()) 94 | { 95 | return $this->makeRequest(self::GET, $path, $data); 96 | } 97 | 98 | /** 99 | * Make a POST request 100 | * 101 | * @param $path 102 | * @param $data 103 | * @return array see 'makeRequest' 104 | */ 105 | public function post($path, $data=array()) 106 | { 107 | return $this->makeRequest(self::POST, $path, $data); 108 | } 109 | 110 | /** 111 | * Make a PUT request 112 | * 113 | * @param $path 114 | * @param $data 115 | * @return array see 'makeRequest' 116 | */ 117 | public function put($path, $data=array()) 118 | { 119 | return $this->makeRequest(self::PUT, $path, $data); 120 | } 121 | 122 | /** 123 | * Make a DELETE request 124 | * 125 | * @param $path 126 | * @return array see 'makeRequest' 127 | */ 128 | public function delete($path) 129 | { 130 | return $this->makeRequest(self::DELETE, $path); 131 | } 132 | 133 | /** 134 | * Set username and password to use with HTTP Basic Auth 135 | * 136 | * Returns this Trnasport object 137 | * 138 | * @param string $username 139 | * @param string $password 140 | * @return Transport 141 | */ 142 | public function setAuth($username=null, $password=null) 143 | { 144 | $this->username = $username; 145 | $this->password = $password; 146 | return $this; 147 | } 148 | 149 | /** 150 | * Turn HTTPS on or off 151 | * 152 | * Returns this Trnasport object 153 | * 154 | * @param boolean $useHttps 155 | * @return Transport 156 | */ 157 | public function useHttps($useHttps=true) 158 | { 159 | $this->scheme = $useHttps ? 'https' : 'http'; 160 | return $this; 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /lib/Everyman/Neo4j/Transport/Curl.php: -------------------------------------------------------------------------------- 1 | handle) { 33 | curl_close($this->handle); 34 | } 35 | } 36 | 37 | /** 38 | * @inherit 39 | */ 40 | public function makeRequest($method, $path, $data=array()) 41 | { 42 | $url = $this->getEndpoint().$path; 43 | 44 | $options = array( 45 | CURLOPT_URL => $url, 46 | CURLOPT_RETURNTRANSFER => true, 47 | CURLOPT_HEADER => true, 48 | CURLOPT_HTTPHEADER => array( 49 | 'Accept: application/json;stream=true', 50 | 'Content-type: application/json', 51 | 'User-Agent: '.Version::userAgent(), 52 | 'X-Stream: true' 53 | ), 54 | CURLOPT_CUSTOMREQUEST => self::GET, 55 | CURLOPT_POST => false, 56 | CURLOPT_POSTFIELDS => null, 57 | CURLOPT_IPRESOLVE => CURL_IPRESOLVE_V4, 58 | ); 59 | 60 | if ($this->username && $this->password) { 61 | $options[CURLOPT_HTTPAUTH] = CURLAUTH_BASIC; 62 | $options[CURLOPT_USERPWD] = $this->username.':'.$this->password; 63 | } 64 | 65 | switch ($method) { 66 | case self::DELETE: 67 | $options[CURLOPT_CUSTOMREQUEST] = self::DELETE; 68 | break; 69 | 70 | case self::POST: 71 | case self::PUT: 72 | $dataString = $this->encodeData($data); 73 | $options[CURLOPT_CUSTOMREQUEST] = $method; 74 | $options[CURLOPT_POSTFIELDS] = $dataString; 75 | $options[CURLOPT_HTTPHEADER][] = 'Content-Length: '.strlen($dataString); 76 | 77 | if (self::POST == $method) { 78 | $options[CURLOPT_POST] = true; 79 | } 80 | break; 81 | } 82 | 83 | $ch = $this->getHandle(); 84 | curl_setopt_array($ch, $options); 85 | 86 | $response = curl_exec($ch); 87 | $code = curl_getinfo($ch, CURLINFO_HTTP_CODE); 88 | $headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE); 89 | 90 | if ($response === false) { 91 | throw new Exception("Can't open connection to ".$url); 92 | } 93 | 94 | if (!$code) { 95 | $code = 500; 96 | $headerSize = 0; 97 | $response = json_encode(array("error"=>curl_error($ch).' ['.curl_errno($ch).']')); 98 | } 99 | 100 | $bodyString = substr($response, $headerSize); 101 | $bodyData = json_decode($bodyString, true); 102 | 103 | $headerString = substr($response, 0, $headerSize); 104 | $headers = explode("\r\n", $headerString); 105 | foreach ($headers as $i => $header) { 106 | unset($headers[$i]); 107 | $parts = explode(':', $header); 108 | if (isset($parts[1])) { 109 | $name = trim(array_shift($parts)); 110 | $value = join(':', $parts); 111 | $headers[$name] = $value; 112 | } 113 | } 114 | 115 | return array( 116 | 'code' => $code, 117 | 'headers' => $headers, 118 | 'data' => $bodyData, 119 | ); 120 | } 121 | 122 | /** 123 | * Get the cURL handle 124 | * 125 | * @return resource cURL handle 126 | */ 127 | protected function getHandle() 128 | { 129 | if (!$this->handle) { 130 | $this->handle = curl_init(); 131 | } 132 | return $this->handle; 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /lib/Everyman/Neo4j/Transport/Stream.php: -------------------------------------------------------------------------------- 1 | getEndpoint().$path; 19 | 20 | $context_options = array ( 21 | $this->scheme => array ( 22 | 'method' => 'GET', 23 | 'ignore_errors' => true, 24 | 'header'=> 25 | "Content-type: application/json\r\n" 26 | . "Accept: application/json;stream=true\r\n" 27 | . "User-Agent: ".Version::userAgent()."\r\n" 28 | . "X-Stream: true\r\n" 29 | ) 30 | ); 31 | 32 | if ($this->username && $this->password) { 33 | $encodedAuth = base64_encode($this->username.':'.$this->password); 34 | $context_options[$this->scheme]['header'] .= 'Authorization: Basic ' . $encodedAuth . "\r\n"; 35 | } 36 | 37 | switch ($method) { 38 | case self::DELETE: 39 | $context_options[$this->scheme]['method'] = self::DELETE; 40 | break; 41 | 42 | case self::POST: 43 | case self::PUT: 44 | $dataString = $this->encodeData($data); 45 | $context_options[$this->scheme]['method'] = $method; 46 | $context_options[$this->scheme]['content'] = $dataString; 47 | $context_options[$this->scheme]['header'] .= 'Context-Length: ' . strlen($dataString) . "\r\n"; 48 | break; 49 | } 50 | 51 | $context = stream_context_create($context_options); 52 | $response = file_get_contents($url, false, $context); 53 | 54 | if ($response === false) { 55 | throw new Exception("Can't open connection to ".$url); 56 | } 57 | 58 | // $http_response_header is set by file_get_contents with the http:// wrapper 59 | 60 | preg_match('/^HTTP\/1\.[0-1] (\d{3})/', $http_response_header[0], $parts); 61 | $code = $parts[1]; 62 | 63 | if (!$code) { 64 | $code = 500; 65 | $response = json_encode(array("error"=>'error [' . $code . ']')); 66 | } 67 | 68 | $bodyData = json_decode($response, true); 69 | 70 | $headers = array(); 71 | foreach ($http_response_header as $header) { 72 | $parts = explode(':', $header, 2); 73 | 74 | if (count($parts) == 2) { 75 | $headers[$parts[0]] = $parts[1]; 76 | } 77 | } 78 | 79 | return array( 80 | 'code' => $code, 81 | 'headers' => $headers, 82 | 'data' => $bodyData, 83 | ); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /lib/Everyman/Neo4j/Version.php: -------------------------------------------------------------------------------- 1 | getMetaData(); 21 | 22 | if ($command == '-help') { 23 | echo <<] 27 | -help Display help text 28 | -license Display software license 29 | -readme Display README 30 | -version Display version information 31 | () Test connection to Neo4j instance on host (port defaults to 7474) 32 | 33 | HELP; 34 | 35 | } else if ($command == '-license') { 36 | echo file_get_contents('phar://neo4jphp.phar/LICENSE')."\n\n"; 37 | 38 | } else if ($command == '-readme') { 39 | echo file_get_contents('phar://neo4jphp.phar/README.md')."\n\n"; 40 | 41 | } else if ($command == '-version') { 42 | echo "Neo4jPHP version {$meta['version']}\n\n"; 43 | 44 | } else { 45 | $port = empty($_SERVER['argv'][2]) ? 7474 : $_SERVER['argv'][2]; 46 | $client = new Everyman\Neo4j\Client($command, $port); 47 | print_r($client->getServerInfo()); 48 | } 49 | 50 | exit(0); 51 | } 52 | __HALT_COMPILER(); 53 | -------------------------------------------------------------------------------- /tests/cs/ruleset.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Code style guidelines for the Neo4jPHP library 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /tests/phpunit.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 10 | 11 | 12 | ./unit 13 | 14 | 15 | -------------------------------------------------------------------------------- /tests/unit/lib/Everyman/Neo4j/Cache/MemcacheTest.php: -------------------------------------------------------------------------------- 1 | markTestSkipped('Memcache extension not enabled/installed'); 13 | } 14 | 15 | $this->memcache = $this->getMock('\Memcache'); 16 | $this->cache = new Memcache($this->memcache); 17 | } 18 | 19 | public function testSet_PassesThroughToMemcache() 20 | { 21 | $this->memcache->expects($this->once()) 22 | ->method('set') 23 | ->with('somekey', 'somevalue', 0, 12345) 24 | ->will($this->returnValue(true)); 25 | 26 | $this->assertTrue($this->cache->set('somekey', 'somevalue', 12345)); 27 | } 28 | 29 | public function testGet_PassesThroughToMemcache() 30 | { 31 | $this->memcache->expects($this->once()) 32 | ->method('get') 33 | ->with('somekey') 34 | ->will($this->returnValue('somevalue')); 35 | 36 | $this->assertEquals('somevalue', $this->cache->get('somekey')); 37 | } 38 | 39 | public function testDelete_PassesThroughToMemcache() 40 | { 41 | $this->memcache->expects($this->once()) 42 | ->method('delete') 43 | ->with('somekey') 44 | ->will($this->returnValue(true)); 45 | 46 | $this->assertTrue($this->cache->delete('somekey')); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /tests/unit/lib/Everyman/Neo4j/Cache/MemcachedTest.php: -------------------------------------------------------------------------------- 1 | markTestSkipped('Memcached extension not enabled/installed'); 14 | } else if (version_compare($memcachedVersion, '2.2.0', '>=')) { 15 | $this->markTestSkipped('Memcached tests can only be run with memcached extension 2.1.0 or lower'); 16 | } 17 | 18 | $this->memcached = $this->getMock('\Memcached'); 19 | $this->cache = new Memcached($this->memcached); 20 | } 21 | 22 | public function testSet_PassesThroughToMemcached() 23 | { 24 | $this->memcached->expects($this->once()) 25 | ->method('set') 26 | ->with('somekey', 'somevalue', 12345) 27 | ->will($this->returnValue(true)); 28 | 29 | $this->assertTrue($this->cache->set('somekey', 'somevalue', 12345)); 30 | } 31 | 32 | public function testGet_PassesThroughToMemcached() 33 | { 34 | $this->memcached->expects($this->once()) 35 | ->method('get') 36 | ->with('somekey') 37 | ->will($this->returnValue('somevalue')); 38 | 39 | $this->assertEquals('somevalue', $this->cache->get('somekey')); 40 | } 41 | 42 | public function testDelete_PassesThroughToMemcached() 43 | { 44 | $this->memcached->expects($this->once()) 45 | ->method('delete') 46 | ->with('somekey') 47 | ->will($this->returnValue(true)); 48 | 49 | $this->assertTrue($this->cache->delete('somekey')); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /tests/unit/lib/Everyman/Neo4j/Cache/NoneTest.php: -------------------------------------------------------------------------------- 1 | cache = new None(); 11 | } 12 | 13 | public function testDelete_ReturnsTrue() 14 | { 15 | $this->assertTrue($this->cache->delete('somekey')); 16 | } 17 | 18 | public function testGet_ReturnsFalse() 19 | { 20 | $this->assertFalse($this->cache->get('somekey')); 21 | } 22 | 23 | public function testSet_ReturnsTrue() 24 | { 25 | $this->assertTrue($this->cache->set('somekey', 'somevalue', 12345)); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /tests/unit/lib/Everyman/Neo4j/Cache/VariableTest.php: -------------------------------------------------------------------------------- 1 | cache = new Variable(); 11 | } 12 | 13 | public function testSet_ReturnsTrue() 14 | { 15 | $this->assertTrue($this->cache->set('somekey', 'somevalue', 12345)); 16 | } 17 | 18 | public function testGet_KeyDoesNotExist_ReturnsFalse() 19 | { 20 | $this->assertFalse($this->cache->get('somekey')); 21 | } 22 | 23 | public function testGet_KeyExists_ReturnsValue() 24 | { 25 | $this->cache->set('somekey', 'somevalue', 12345); 26 | $this->assertEquals('somevalue', $this->cache->get('somekey')); 27 | } 28 | 29 | public function testGet_ExpiredValue_ReturnsFalse() 30 | { 31 | $this->cache->set('somekey', 'somevalue', time()-10000); 32 | $this->assertFalse($this->cache->get('somekey')); 33 | } 34 | 35 | public function testDelete_KeyDoesNotExist_ReturnsTrue() 36 | { 37 | $this->assertTrue($this->cache->delete('somekey')); 38 | } 39 | 40 | public function testDelete_KeyExists_ReturnsTrue() 41 | { 42 | $this->cache->set('somekey', 'somevalue', 12345); 43 | $this->assertTrue($this->cache->delete('somekey')); 44 | $this->assertFalse($this->cache->get('somekey')); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /tests/unit/lib/Everyman/Neo4j/Client_Batch_NodeTest.php: -------------------------------------------------------------------------------- 1 | transport = $this->getMock('Everyman\Neo4j\Transport'); 13 | $this->client = new Client($this->transport); 14 | 15 | $this->batch = new Batch($this->client); 16 | 17 | $this->client->getEntityCache()->setCache(new Cache\Variable()); 18 | } 19 | 20 | public function testCommitBatch_TransportError_ThrowsException() 21 | { 22 | $node = new Node($this->client); 23 | $request = array(array('id' => 0, 'method' => 'POST', 'to' => '/node', 'body' => null)); 24 | 25 | $this->batch->save($node); 26 | $this->setupTransportExpectation($request, $this->returnValue(array('code' => 400))); 27 | 28 | $this->setExpectedException('\Everyman\Neo4j\Exception'); 29 | $this->client->commitBatch($this->batch); 30 | } 31 | 32 | public function testCommitBatch_CreateNode_Success_ReturnsTrue() 33 | { 34 | $node = new Node($this->client); 35 | $node->setProperties(array('foo' => 'bar','baz' => 'qux')); 36 | 37 | $request = array(array('id' => 0, 'method' => 'POST', 'to' => '/node', 38 | 'body' => array('foo' => 'bar','baz' => 'qux'))); 39 | 40 | $return = array('code' => 200, 'data' => array( 41 | array('id' => 0, 'location' => 'http://foo:1234/db/data/node/123'))); 42 | 43 | $this->batch->save($node); 44 | $this->setupTransportExpectation($request, $this->returnValue($return)); 45 | $result = $this->client->commitBatch($this->batch); 46 | 47 | $this->assertTrue($result); 48 | $this->assertEquals(123, $node->getId()); 49 | 50 | $this->assertSame($node, $this->client->getEntityCache()->getCachedEntity(123, 'node')); 51 | } 52 | 53 | public function testCommitBatch_UpdateNode_Success_ReturnsTrue() 54 | { 55 | $node = new Node($this->client); 56 | $node->useLazyLoad(false) 57 | ->setId(123) 58 | ->setProperties(array('foo' => 'bar','baz' => 'qux')); 59 | 60 | $request = array(array('id' => 0, 'method' => 'PUT', 'to' => '/node/123/properties', 61 | 'body' => array('foo' => 'bar','baz' => 'qux'))); 62 | 63 | $return = array('code' => 200, 'data' => array( 64 | array('id' => 0))); 65 | 66 | $this->batch->save($node); 67 | $this->setupTransportExpectation($request, $this->returnValue($return)); 68 | $result = $this->client->commitBatch($this->batch); 69 | 70 | $this->assertTrue($result); 71 | 72 | $this->assertSame($node, $this->client->getEntityCache()->getCachedEntity(123, 'node')); 73 | } 74 | 75 | public function testCommitBatch_DeleteNode_Success_ReturnsTrue() 76 | { 77 | $node = new Node($this->client); 78 | $node->setId(123); 79 | $this->client->getEntityCache()->setCachedEntity($node); 80 | 81 | $request = array(array('id' => 0, 'method' => 'DELETE', 'to' => '/node/123')); 82 | 83 | $return = array('code' => 200, 'data' => array( 84 | array('id' => 0))); 85 | 86 | $this->batch->delete($node); 87 | $this->setupTransportExpectation($request, $this->returnValue($return)); 88 | $result = $this->client->commitBatch($this->batch); 89 | 90 | $this->assertTrue($result); 91 | 92 | $this->assertFalse($this->client->getEntityCache()->getCachedEntity(123, 'node')); 93 | } 94 | 95 | protected function setupTransportExpectation($request, $will) 96 | { 97 | $this->transport->expects($this->once()) 98 | ->method('post') 99 | ->with('/batch', $request) 100 | ->will($will); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /tests/unit/lib/Everyman/Neo4j/Cypher/QueryTest.php: -------------------------------------------------------------------------------- 1 | client = $this->getMock('Everyman\Neo4j\Client', array(), array(), '', false); 15 | $this->template = 'START a=({start}) RETURN a'; 16 | $this->vars = array('start' => 0); 17 | 18 | $this->query = new Query($this->client, $this->template, $this->vars); 19 | } 20 | 21 | public function testGetQuery_ReturnsString() 22 | { 23 | $result = $this->query->getQuery(); 24 | $this->assertEquals($result, $this->template); 25 | } 26 | 27 | public function testGetParameters_ReturnsArray() 28 | { 29 | $result = $this->query->getParameters(); 30 | $this->assertEquals($result, $this->vars); 31 | } 32 | 33 | public function testGetResultSet_OnlyExecutesOnce_ReturnsResultSet() 34 | { 35 | $return = $this->getMock('Everyman\Neo4j\Query\ResultSet', array(), array(), '', false); 36 | 37 | $this->client->expects($this->once()) 38 | ->method('executeCypherQuery') 39 | ->will($this->returnValue($return)); 40 | 41 | $this->assertSame($return, $this->query->getResultSet()); 42 | $this->assertSame($return, $this->query->getResultSet()); 43 | } 44 | 45 | public function testGetResultSet_ClientReturnsFalse_ReturnsFalse() 46 | { 47 | $return = false; 48 | 49 | $this->client->expects($this->once()) 50 | ->method('executeCypherQuery') 51 | ->will($this->returnValue($return)); 52 | 53 | $this->assertFalse($this->query->getResultSet()); 54 | $this->assertFalse($this->query->getResultSet()); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /tests/unit/lib/Everyman/Neo4j/Gremlin/QueryTest.php: -------------------------------------------------------------------------------- 1 | client = $this->getMock('Everyman\Neo4j\Client', array(), array(), '', false); 15 | $this->queryString = 'i = g.v(start);i.outE.inV'; 16 | $this->params = array('start' => 123); 17 | 18 | $this->query = new Query($this->client, $this->queryString, $this->params); 19 | } 20 | 21 | public function testGetQuery_ReturnsString() 22 | { 23 | $result = $this->query->getQuery(); 24 | $this->assertEquals($result, $this->queryString); 25 | } 26 | 27 | public function testGetParameters_ReturnsArray() 28 | { 29 | $result = $this->query->getParameters(); 30 | $this->assertEquals($result, $this->params); 31 | } 32 | 33 | public function testGetResultSet_OnlyExecutesOnce_ReturnsResultSet() 34 | { 35 | $return = $this->getMock('Everyman\Neo4j\Query\ResultSet', array(), array(), '', false); 36 | 37 | $this->client->expects($this->once()) 38 | ->method('executeGremlinQuery') 39 | ->will($this->returnValue($return)); 40 | 41 | $this->assertSame($return, $this->query->getResultSet()); 42 | $this->assertSame($return, $this->query->getResultSet()); 43 | } 44 | 45 | public function testGetResultSet_ClientReturnsFalse_ReturnsFalse() 46 | { 47 | $return = false; 48 | 49 | $this->client->expects($this->once()) 50 | ->method('executeGremlinQuery') 51 | ->will($this->returnValue($return)); 52 | 53 | $this->assertFalse($this->query->getResultSet()); 54 | $this->assertFalse($this->query->getResultSet()); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /tests/unit/lib/Everyman/Neo4j/LabelTest.php: -------------------------------------------------------------------------------- 1 | client = $this->getMock('Everyman\Neo4j\Client'); 11 | } 12 | 13 | public function dataProvider_ValidNames() 14 | { 15 | return array( 16 | array('TEST LABEL NAME'), 17 | array(123), 18 | array(123.45), 19 | ); 20 | } 21 | 22 | /** 23 | * @dataProvider dataProvider_ValidNames 24 | */ 25 | public function testContruct_ValidNameGiven_SetsNameCastAsString($name) 26 | { 27 | $label = new Label($this->client, $name); 28 | self::assertEquals($name, $label->getName()); 29 | self::assertInternalType('string', $label->getName()); 30 | } 31 | 32 | public function dataProvider_InvalidNames() 33 | { 34 | return array( 35 | array(null), 36 | array(''), 37 | array(true), 38 | array(array()), 39 | array(array('foo')), 40 | array(new \stdClass()), 41 | ); 42 | } 43 | 44 | /** 45 | * @dataProvider dataProvider_InvalidNames 46 | */ 47 | public function testContruct_InvalidNameGiven_ThrowsException($name) 48 | { 49 | $this->setExpectedException('InvalidArgumentException'); 50 | $label = new Label($this->client, $name); 51 | } 52 | 53 | public function testGetNodes_NoPropertyGiven_CallsClientMethod() 54 | { 55 | $label = new Label($this->client, 'foobar'); 56 | 57 | $this->client->expects($this->once()) 58 | ->method('getNodesForLabel') 59 | ->with($label, null, null); 60 | 61 | $label->getNodes(); 62 | } 63 | 64 | public function testGetNodes_PropertyGiven_CallsClientMethod() 65 | { 66 | $label = new Label($this->client, 'foobar'); 67 | $property = 'baz'; 68 | $value = 'qux'; 69 | 70 | $this->client->expects($this->once()) 71 | ->method('getNodesForLabel') 72 | ->with($label, $property, $value); 73 | 74 | $label->getNodes($property, $value); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /tests/unit/lib/Everyman/Neo4j/PagerTest.php: -------------------------------------------------------------------------------- 1 | client = $this->getMock('Everyman\Neo4j\Client', array(), array(), '', false); 15 | $this->traversal = new Traversal($this->client); 16 | 17 | $this->node = new Node($this->client); 18 | $this->node->setId(123); 19 | 20 | $this->returnType = Traversal::ReturnTypeNode; 21 | 22 | $this->pager = new Pager($this->traversal, $this->node, $this->returnType); 23 | } 24 | 25 | public function testConstruct_SetsParametersCorrectly_ReturnsCorrectValues() 26 | { 27 | $this->assertSame($this->traversal, $this->pager->getTraversal()); 28 | $this->assertSame($this->node, $this->pager->getStartNode()); 29 | $this->assertEquals($this->returnType, $this->pager->getReturnType()); 30 | } 31 | 32 | public function testPageSize_NoneGiven_ReturnsNull() 33 | { 34 | $this->assertNull($this->pager->getPageSize()); 35 | } 36 | 37 | public function testPageSize_PageSizeGiven_ReturnsInteger() 38 | { 39 | $this->pager->setPageSize(10); 40 | $this->assertEquals(10, $this->pager->getPageSize()); 41 | } 42 | 43 | public function testLeaseTime_NoneGiven_ReturnsNull() 44 | { 45 | $this->assertNull($this->pager->getLeaseTime()); 46 | } 47 | 48 | public function testLeaseTime_LeaseTimeGiven_ReturnsInteger() 49 | { 50 | $this->pager->setLeaseTime(30); 51 | $this->assertEquals(30, $this->pager->getLeaseTime()); 52 | } 53 | 54 | public function testId_NoneGiven_ReturnsNull() 55 | { 56 | $this->assertNull($this->pager->getId()); 57 | } 58 | 59 | public function testId_IdGiven_ReturnsString() 60 | { 61 | $this->pager->setId('thisistheid'); 62 | $this->assertEquals('thisistheid', $this->pager->getId()); 63 | } 64 | 65 | public function testGetNextResults_PassesThroughToClient() 66 | { 67 | $expectedNodes = array(new Node($this->client), new Node($this->client)); 68 | 69 | $this->client->expects($this->once()) 70 | ->method('executePagedTraversal') 71 | ->with($this->pager) 72 | ->will($this->returnValue($expectedNodes)); 73 | 74 | $nodes = $this->pager->getNextResults(); 75 | $this->assertEquals($expectedNodes, $nodes); 76 | } 77 | } 78 | 79 | -------------------------------------------------------------------------------- /tests/unit/lib/Everyman/Neo4j/PathFinderTest.php: -------------------------------------------------------------------------------- 1 | client = $this->getMock('Everyman\Neo4j\Client', array(), array(), '', false); 12 | $this->finder = new PathFinder($this->client); 13 | } 14 | 15 | public function testGetClient_ClientSetCorrectly_ReturnsClient() 16 | { 17 | $this->assertSame($this->client, $this->finder->getClient()); 18 | } 19 | 20 | public function testGetPaths_PassesThroughToClient() 21 | { 22 | $expectedPaths = array(new Path($this->client), new Path($this->client)); 23 | 24 | $this->client->expects($this->once()) 25 | ->method('getPaths') 26 | ->with($this->finder) 27 | ->will($this->returnValue($expectedPaths)); 28 | 29 | $paths = $this->finder->getPaths(); 30 | $this->assertEquals($expectedPaths, $paths); 31 | } 32 | 33 | public function testGetSinglePath_PassesThroughToClient() 34 | { 35 | $firstPath = new Path($this->client); 36 | $expectedPaths = array($firstPath, new Path($this->client)); 37 | 38 | $this->client->expects($this->once()) 39 | ->method('getPaths') 40 | ->with($this->finder) 41 | ->will($this->returnValue($expectedPaths)); 42 | 43 | $path = $this->finder->getSinglePath(); 44 | $this->assertEquals($firstPath, $path); 45 | } 46 | 47 | public function testGetSinglePath_NoPaths_ReturnsNull() 48 | { 49 | $this->client->expects($this->once()) 50 | ->method('getPaths') 51 | ->with($this->finder) 52 | ->will($this->returnValue(array())); 53 | 54 | $path = $this->finder->getSinglePath(); 55 | $this->assertNull($path); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /tests/unit/lib/Everyman/Neo4j/PathTest.php: -------------------------------------------------------------------------------- 1 | client = $this->getMock('Everyman\Neo4j\Client', array(), array(), '', false); 15 | $this->path = new Path($this->client); 16 | 17 | $rel = new Relationship($this->client); 18 | $rel->setStartNode(new Node($this->client)); 19 | $rel->setEndNode(new Node($this->client)); 20 | $this->path->appendRelationship($rel); 21 | $this->rels[0] = $rel; 22 | 23 | $rel = new Relationship($this->client); 24 | $rel->setStartNode(new Node($this->client)); 25 | $rel->setEndNode(new Node($this->client)); 26 | $this->path->appendRelationship($rel); 27 | $this->rels[1] = $rel; 28 | 29 | $node = new Node($this->client); 30 | $this->path->appendNode($node); 31 | $this->nodes[0] = $node; 32 | 33 | $node = new Node($this->client); 34 | $this->path->appendNode($node); 35 | $this->nodes[1] = $node; 36 | 37 | $node = new Node($this->client); 38 | $this->path->appendNode($node); 39 | $this->nodes[2] = $node; 40 | 41 | $node = new Node($this->client); 42 | $this->path->appendNode($node); 43 | $this->nodes[3] = $node; 44 | } 45 | 46 | public function testGetLength_ReturnsInteger() 47 | { 48 | $this->assertEquals(count($this->nodes), $this->path->getLength()); 49 | $this->assertEquals(count($this->nodes), count($this->path)); 50 | 51 | $this->path->setContext(Path::ContextRelationship); 52 | 53 | $this->assertEquals(count($this->rels), $this->path->getLength()); 54 | $this->assertEquals(count($this->rels), count($this->path)); 55 | } 56 | 57 | public function testEndpoints_ReturnsCorrectNodes() 58 | { 59 | $this->assertSame($this->nodes[0], $this->path->getStartNode()); 60 | $this->assertSame($this->nodes[3], $this->path->getEndNode()); 61 | } 62 | 63 | public function testEndpoints_NoRelationship_ReturnsNull() 64 | { 65 | $this->path = new Path($this->client); 66 | $this->assertNull($this->path->getStartNode()); 67 | $this->assertNull($this->path->getEndNode()); 68 | } 69 | 70 | public function testGetRelationships_ReturnsArray() 71 | { 72 | $rels = $this->path->getRelationships(); 73 | $this->assertEquals(count($this->rels), count($rels)); 74 | $this->assertSame($this->rels[0], $rels[0]); 75 | $this->assertSame($this->rels[1], $rels[1]); 76 | } 77 | 78 | public function testGetNodes_ReturnsArray() 79 | { 80 | $nodes = $this->path->getNodes(); 81 | $this->assertEquals(count($this->nodes), count($nodes)); 82 | $this->assertSame($this->nodes[0], $nodes[0]); 83 | $this->assertSame($this->nodes[1], $nodes[1]); 84 | $this->assertSame($this->nodes[2], $nodes[2]); 85 | $this->assertSame($this->nodes[3], $nodes[3]); 86 | } 87 | 88 | public function testIteration_PathCanBeIteratedOver() 89 | { 90 | $this->assertInstanceOf('Traversable', $this->path); 91 | foreach ($this->path as $i => $node) { 92 | $this->assertSame($this->nodes[$i], $node); 93 | } 94 | 95 | $this->path->setContext(Path::ContextRelationship); 96 | foreach ($this->path as $i => $rel) { 97 | $this->assertSame($this->rels[$i], $rel); 98 | } 99 | } 100 | 101 | public function testContext_UnknownContextSet_SetsContextToNode() 102 | { 103 | $this->path->setContext('FOO'); 104 | $this->assertEquals(Path::ContextNode, $this->path->getContext()); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /tests/unit/lib/Everyman/Neo4j/PropertyContainerTest.php: -------------------------------------------------------------------------------- 1 | client = $this->getMock('Everyman\Neo4j\Client', array(), array(), '', false); 12 | $this->entity = $this->getMock('Everyman\Neo4j\PropertyContainer', 13 | array('delete','save','load'), array($this->client)); 14 | } 15 | 16 | public function testProperties_MagicNotSet_ReturnsNull() 17 | { 18 | $this->assertNull($this->entity->notset); 19 | } 20 | 21 | public function testProperties_MagicSet_ReturnsValue() 22 | { 23 | $this->entity->somekey = 'someval'; 24 | $this->assertEquals('someval', $this->entity->getProperty('somekey')); 25 | } 26 | 27 | public function testProperties_MagicRemoved_ReturnsNull() 28 | { 29 | $this->entity->setProperty('somekey', 'someval'); 30 | unset($this->entity->somekey); 31 | $this->assertNull($this->entity->getProperty('somekey')); 32 | } 33 | 34 | public function testProperties_PropertyNotSet_ReturnsNull() 35 | { 36 | $this->assertNull($this->entity->getProperty('notset')); 37 | } 38 | 39 | public function testProperties_PropertySet_ReturnsValue() 40 | { 41 | $this->entity->setProperty('somekey','someval'); 42 | $this->assertEquals('someval', $this->entity->getProperty('somekey')); 43 | } 44 | 45 | public function testProperties_PropertyRemoved_ReturnsNull() 46 | { 47 | $this->entity->setProperty('somekey','someval'); 48 | $this->entity->removeProperty('somekey'); 49 | $this->assertNull($this->entity->getProperty('somekey')); 50 | } 51 | 52 | public function testProperties_BatchSet_ReturnsValues() 53 | { 54 | $this->entity->setProperties(array( 55 | 'somekey' => 'someval', 56 | 'yakey' => 'yaval', 57 | )); 58 | $this->assertEquals('someval', $this->entity->getProperty('somekey')); 59 | $this->assertEquals('yaval', $this->entity->getProperty('yakey')); 60 | } 61 | 62 | public function testProperties_GetAllProperties_ReturnsValues() 63 | { 64 | $this->entity->setProperties(array( 65 | 'somekey' => 'someval', 66 | 'yakey' => 'yaval', 67 | )); 68 | $this->assertEquals(array( 69 | 'somekey' => 'someval', 70 | 'yakey' => 'yaval', 71 | ), $this->entity->getProperties()); 72 | } 73 | 74 | public function testProperties_SetPropertyNullValue_ReturnsNullAndPropertyRemoved() 75 | { 76 | $this->entity->setProperties(array( 77 | 'somekey' => 'someval', 78 | 'yakey' => 'yaval', 79 | )); 80 | 81 | $this->entity->setProperty('somekey', null); 82 | $this->assertNull($this->entity->getProperty('somekey')); 83 | 84 | $this->assertEquals(array( 85 | 'yakey' => 'yaval', 86 | ), $this->entity->getProperties()); 87 | } 88 | 89 | public function testProperties_LazyLoad_OnlyLoadsTheFirstTime() 90 | { 91 | $this->entity->expects($this->once()) 92 | ->method('load'); 93 | 94 | $this->entity->setId(123); 95 | $this->entity->getProperties(); 96 | $this->entity->getProperties(); 97 | } 98 | 99 | public function testSetGetId_IntegerId_ReturnsInteger() 100 | { 101 | $this->entity->setId(123); 102 | $this->assertTrue($this->entity->hasId()); 103 | $this->assertEquals(123, $this->entity->getId()); 104 | } 105 | 106 | public function testSetGetId_ZeroIdIsValid_ReturnsInteger() 107 | { 108 | $this->entity->setId(0); 109 | $this->assertTrue($this->entity->hasId()); 110 | $this->assertEquals(0, $this->entity->getId()); 111 | } 112 | 113 | public function testSetGetId_NullValid_ReturnsNull() 114 | { 115 | $this->entity->setId(null); 116 | $this->assertFalse($this->entity->hasId()); 117 | $this->assertNull($this->entity->getId()); 118 | } 119 | 120 | public function testSetGetId_NonIntegerCastToInteger_ReturnsInteger() 121 | { 122 | $this->entity->setId('temp'); 123 | $this->assertTrue($this->entity->hasId()); 124 | $this->assertEquals(0, $this->entity->getId()); 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /tests/unit/lib/Everyman/Neo4j/Query/ResultSetTest.php: -------------------------------------------------------------------------------- 1 | client = new Client($this->getMock('Everyman\Neo4j\Transport')); 13 | } 14 | 15 | public function testCount() 16 | { 17 | $data = array( 18 | 'columns' => array('name','age'), 19 | 'data' => array( 20 | array('Bob', 12), 21 | array('Lotta', 0), 22 | array('Brenda', 14) 23 | ) 24 | ); 25 | 26 | $result = new ResultSet($this->client, $data); 27 | $this->assertEquals(3, count($result)); 28 | } 29 | 30 | public function testIterate() 31 | { 32 | $data = array( 33 | 'columns' => array('name','age'), 34 | 'data' => array( 35 | array('Bob', 12), 36 | array('Lotta', 0), 37 | array('Brenda', 14) 38 | ) 39 | ); 40 | 41 | $result = new ResultSet($this->client, $data); 42 | foreach($result as $index => $row) { 43 | $this->assertEquals($data['data'][$index][0], $row['name']); 44 | $this->assertEquals($data['data'][$index][0], $row[0]); 45 | $this->assertTrue($row instanceof Row); 46 | } 47 | } 48 | 49 | public function testArrayAccess() 50 | { 51 | $data = array( 52 | 'columns' => array('name','age'), 53 | 'data' => array( 54 | array('Bob', 12), 55 | array('Lotta', 0), 56 | array('Brenda', 14), 57 | array('Jimmy', null) 58 | ) 59 | ); 60 | 61 | $result = new ResultSet($this->client, $data); 62 | for($i=0,$l=4; $i<$l; $i++) { 63 | $this->assertEquals(true, isset($result[$i])); 64 | $this->assertEquals($data['data'][$i][0], $result[$i][0]); 65 | } 66 | 67 | //issue #83 68 | $this->assertFalse(isset($result[3]['age'])); 69 | $this->assertTrue(is_null($result[3]['age'])); 70 | $this->assertEquals(null, $result[3]['age']); 71 | 72 | $this->assertEquals(false, isset($result[4])); 73 | } 74 | 75 | public function testArrayAccess_CacheResultRows() 76 | { 77 | $data = array( 78 | 'columns' => array('name','age'), 79 | 'data' => array( 80 | array('Bob', 12), 81 | array('Lotta', 0), 82 | array('Brenda', 14) 83 | ) 84 | ); 85 | 86 | $result = new ResultSet($this->client, $data); 87 | $row = $result[0]; 88 | $again = $result[0]; 89 | $this->assertSame($row, $again); 90 | } 91 | 92 | public function testArrayAccess_Set_ThrowsException() 93 | { 94 | $data = array( 95 | 'columns' => array('name','age'), 96 | 'data' => array( 97 | array('Bob', 12), 98 | array('Lotta', 0), 99 | array('Brenda', 14) 100 | ) 101 | ); 102 | 103 | $result = new ResultSet($this->client, $data); 104 | 105 | $this->setExpectedException('BadMethodCallException'); 106 | $result[3] = 'value'; 107 | } 108 | 109 | public function testArrayAccess_Unset_ThrowsException() 110 | { 111 | $data = array( 112 | 'columns' => array('name','age'), 113 | 'data' => array( 114 | array('Bob', 12), 115 | array('Lotta', 0), 116 | array('Brenda', 14) 117 | ) 118 | ); 119 | 120 | $result = new ResultSet($this->client, $data); 121 | 122 | $this->setExpectedException('BadMethodCallException'); 123 | unset($result[0]); 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /tests/unit/lib/Everyman/Neo4j/RelationshipTest.php: -------------------------------------------------------------------------------- 1 | client = $this->getMock('Everyman\Neo4j\Client', array(), array(), '', false); 13 | $this->relationship = new Relationship($this->client); 14 | } 15 | 16 | public function testSave_SavesSelfUsingClient() 17 | { 18 | $expected = $this->relationship; 19 | $matched = false; 20 | 21 | $this->client->expects($this->once()) 22 | ->method('saveRelationship') 23 | // Have to do it this way because PHPUnit clones object parameters 24 | ->will($this->returnCallback(function (Relationship $actual) use ($expected, &$matched) { 25 | $matched = $expected->getId() == $actual->getId(); 26 | return true; 27 | })); 28 | 29 | $this->assertSame($this->relationship, $this->relationship->save()); 30 | $this->assertTrue($matched); 31 | } 32 | 33 | /** 34 | * Test for https://github.com/jadell/neo4jphp/issues/58 35 | */ 36 | public function testSave_FollowedByPropertyGet_DoesNotLazyLoad() 37 | { 38 | $this->client->expects($this->once()) 39 | ->method('saveRelationship') 40 | ->will($this->returnValue(true)); 41 | 42 | $this->client->expects($this->never()) 43 | ->method('loadRelationship'); 44 | 45 | $this->relationship->setId(123); 46 | $this->relationship->save(); 47 | $this->relationship->getProperty('foo'); 48 | } 49 | 50 | public function testDelete_DeletesSelfUsingClient() 51 | { 52 | $this->client->expects($this->once()) 53 | ->method('deleteRelationship') 54 | ->with($this->relationship) 55 | ->will($this->returnValue(true)); 56 | 57 | $this->assertSame($this->relationship, $this->relationship->delete()); 58 | } 59 | 60 | public function testLoad_LoadsSelfUsingClient() 61 | { 62 | $this->client->expects($this->once()) 63 | ->method('loadRelationship') 64 | ->with($this->relationship) 65 | ->will($this->returnValue(true)); 66 | 67 | $this->assertSame($this->relationship, $this->relationship->load()); 68 | } 69 | 70 | public function testGetStartNode_NodeNotSet_LazyLoad() 71 | { 72 | $this->relationship->setId(123); 73 | $this->client->expects($this->once()) 74 | ->method('loadRelationship'); 75 | 76 | $this->relationship->getStartNode(); 77 | } 78 | 79 | public function testGetEndNode_NodeNotSet_LazyLoad() 80 | { 81 | $this->relationship->setId(123); 82 | $this->client->expects($this->once()) 83 | ->method('loadRelationship'); 84 | 85 | $this->relationship->getEndNode(); 86 | } 87 | 88 | public function testGetStartAndEndNode_NodesSet_DoesNotLazyLoad() 89 | { 90 | $startNode = new Node($this->client); 91 | $endNode = new Node($this->client); 92 | 93 | $this->relationship->setId(123); 94 | $this->relationship->setStartNode($startNode); 95 | $this->relationship->setEndNode($endNode); 96 | 97 | $this->client->expects($this->never()) 98 | ->method('loadRelationship'); 99 | 100 | $this->assertSame($startNode, $this->relationship->getStartNode()); 101 | $this->assertSame($endNode, $this->relationship->getEndNode()); 102 | } 103 | 104 | public function testSerialize_KeepsStartEndAndType() 105 | { 106 | $expectedStart = new Node($this->client); 107 | $expectedStart->setId(123); 108 | $expectedEnd = new Node($this->client); 109 | $expectedEnd->setId(456); 110 | $this->relationship 111 | ->setType($this->type) 112 | ->setStartNode($expectedStart) 113 | ->setEndNode($expectedEnd); 114 | 115 | // serialize and unserialize 116 | $data = serialize($this->relationship); 117 | $rel = unserialize($data); 118 | // we must reset the client 119 | $rel->setClient($this->client); 120 | $start = $rel->getStartNode(); 121 | $end = $rel->getEndNode(); 122 | 123 | $this->assertEquals($this->relationship, $rel, 'The relationship is restored by unserialize'); 124 | $this->assertEquals($expectedStart, $start, 'The start node should be restored by unserialize'); 125 | $this->assertEquals($expectedEnd, $end, 'The end node should be restored by unserialize'); 126 | $this->assertEquals($this->type, $rel->getType(), 'The type should be restored by unserialize'); 127 | $this->assertEquals($this->client, $start->getClient(), 'The client should be restored in the start node by setClient on the relation'); 128 | $this->assertEquals($this->client, $end->getClient(), 'The client should be restored in the end node by setClient on the relation'); 129 | } 130 | } 131 | --------------------------------------------------------------------------------