{"id":14959413,"url":"https://github.com/vinelab/neoeloquent","last_synced_at":"2025-05-14T06:07:29.305Z","repository":{"id":16600366,"uuid":"19354920","full_name":"Vinelab/NeoEloquent","owner":"Vinelab","description":"The Neo4j OGM for Laravel","archived":false,"fork":false,"pushed_at":"2025-02-11T03:43:14.000Z","size":1667,"stargazers_count":645,"open_issues_count":21,"forks_count":196,"subscribers_count":47,"default_branch":"main","last_synced_at":"2025-04-03T13:13:50.482Z","etag":null,"topics":["eloquent","laravel","neo4j"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Vinelab.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2014-05-01T19:19:50.000Z","updated_at":"2025-03-18T06:26:20.000Z","dependencies_parsed_at":"2023-01-13T18:55:44.109Z","dependency_job_id":"e11d16a9-cd4c-409d-9f8d-d6260fe5bce6","html_url":"https://github.com/Vinelab/NeoEloquent","commit_stats":{"total_commits":60,"total_committers":7,"mean_commits":8.571428571428571,"dds":"0.41666666666666663","last_synced_commit":"a95fd1b547cf5e6c90b26d2d15597308d0c1d87b"},"previous_names":[],"tags_count":47,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Vinelab%2FNeoEloquent","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Vinelab%2FNeoEloquent/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Vinelab%2FNeoEloquent/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Vinelab%2FNeoEloquent/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Vinelab","download_url":"https://codeload.github.com/Vinelab/NeoEloquent/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248313175,"owners_count":21082812,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["eloquent","laravel","neo4j"],"created_at":"2024-09-24T13:19:39.230Z","updated_at":"2025-04-10T23:21:43.019Z","avatar_url":"https://github.com/Vinelab.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Build Status](https://travis-ci.org/Vinelab/NeoEloquent.svg?branch=master)](https://travis-ci.org/Vinelab/NeoEloquent)\n\n# NeoEloquent\n\nNeo4j Graph Eloquent Driver for Laravel.\n\n## Quick Reference\n\n - [Installation](#installation)\n - [Configuration](#configuration)\n - [Models](#models)\n - [Relationships](#relationships)\n - [Edges](#edges)\n - [Migration](#migration)\n - [Schema](#schema)\n - [Aggregates](#aggregates)\n - [Only in Neo](#only-in-neo)\n - [Things To Avoid](#avoid)\n\n## Installation\n\nRun `composer require vinelab/neoeloquent`\n\nOr add the package to your `composer.json` and run `composer update`.\n\n```json\n{\n    \"require\": {\n        \"vinelab/neoeloquent\": \"1.8.*\"\n    }\n}\n```\n\nAdd the service provider in `app/config/app.php`:\n\n```php\nVinelab\\NeoEloquent\\NeoEloquentServiceProvider::class,\n```\n\nThe service provider will register all the required classes for this package and will also alias\nthe `Model` class to `NeoEloquent` so you can simply `extend NeoEloquent` in your models.\n\n## Configuration\n\n### Connection\nin `app/config/database.php` or in case of an environment-based configuration `app/config/[env]/database.php`\nmake `neo4j` your default connection:\n\n```php\n'default' =\u003e 'neo4j',\n```\n\nAdd the connection defaults:\n\n```php\n'connections' =\u003e [\n    'neo4j' =\u003e [\n        'driver' =\u003e 'neo4j',\n        'host'   =\u003e 'localhost',\n        'port'   =\u003e 7687,\n        'username' =\u003e 'username',\n        'password' =\u003e 'password',\n    ]\n]\n```\n\n\u003e Remember to update your ENV variables (`.env`) in case you're using them.\n\n### Migration Setup\n\nIf you're willing to have migrations:\n\n- create the folder `app/database/labels`\n- modify `composer.json` and add `app/database/labels` to the `classmap` array\n- run `composer dump-autoload`\n\n\n### Documentation\n\n## Models\n\n- [Node Labels](#namespaced-models)\n- [Soft Deleting](#soft-deleting)\n\n```php\nuse NeoEloquent;\n\nclass User extends NeoEloquent {}\n```\n\nAs simple as it is, NeoEloquent will generate the default node label from the class name,\nin this case it will be `:User`. Read about [node labels here](http://docs.neo4j.org/chunked/stable/rest-api-node-labels.html)\n\n### Namespaced Models\nWhen you use namespaces with your models the label will consider the full namespace.\n\n```php\nnamespace App\\Models;\n\nuse NeoEloquent;\n\nclass Admin extends NeoEloquent { }\n```\n\nThe generated label from that relationship will be `VinelabCmsAdmin`, this is necessary to make sure\nthat labels do not clash in cases where we introduce another  `Admin` instance like\n`Vinelab\\Blog\\Admin` then things gets messy with `:Admin` in the database.\n\n### Custom Node Labels\n\nYou may specify the label(s) you wish to be used instead of the default generated, they are also\ncase sensitive so they will be stored as put here.\n\n```php\nuse NeoEloquent;\n\nclass User extends NeoEloquent {\n\n    protected $label = 'User'; // or array('User', 'Fan')\n\n    protected $fillable = ['name', 'email'];\n}\n\n$user = User::create(['name' =\u003e 'Some Name', 'email' =\u003e 'some@email.com']);\n```\n\nNeoEloquent has a fallback support for the `$table` variable that will be used if found and there was no `$label` defined on the model.\n\n```php\nuse NeoEloquent;\n\nclass User extends NeoEloquent {\n\n    protected $table = 'User';\n\n}\n```\n\nDo not worry about the labels formatting, You may specify them as `array('Label1', 'Label2')` or separate them by a column `:` and prepending them with a `:` is optional.\n\n### Soft Deleting\n\nTo enable soft deleting you'll need to `use Vinelab\\NeoEloquent\\Eloquent\\SoftDeletingTrait`\ninstead of `Illuminate\\Database\\Eloquent\\SoftDeletingTrait` and just like Eloquent you'll need the `$dates` in your models as follows:\n\n```php\nuse Vinelab\\NeoEloquent\\Eloquent\\SoftDeletingTrait;\n\nclass User extends NeoEloquent {\n\n    use SoftDeletingTrait;\n\n    protected $dates = ['deleted_at'];\n\n}\n```\n\n## Relationships\n\n- [One-To-One](#one-to-one)\n- [One-To-Many](#one-to-many)\n- [Many-To-Many](#many-to-many)\n- [Polymorphic](#polymorphic)\n\nLet's go through some examples of relationships between Nodes.\n\n### One-To-One\n\n```php\nclass User extends NeoEloquent {\n\n    public function phone()\n    {\n        return $this-\u003ehasOne('Phone');\n    }\n```\nThis represents an `OUTGOING` relationship direction from the `:User` node to a `:Phone`.\n\n##### Saving\n\n```php\n$phone = new Phone(['code' =\u003e 961, 'number' =\u003e '98765432'])\n$relation = $user-\u003ephone()-\u003esave($phone);\n```\n\nThe Cypher performed by this statement will be as follows:\n\n```\nMATCH (user:`User`)\nWHERE id(user) = 1\nCREATE (user)-[:PHONE]-\u003e(phone:`Phone` {code: 961, number: '98765432', created_at: 7543788, updated_at: 7543788})\nRETURN phone;\n```\n\n##### Defining The Inverse Of This Relation\n\n```php\nclass Phone extends NeoEloquent {\n\n    public function user()\n    {\n        return $this-\u003ebelongsTo('User');\n    }\n}\n```\n\nThis represents an `INCOMING` relationship direction from\nthe `:User` node to this `:Phone` node.\n\n##### Associating Models\n\nDue to the fact that we do not deal with **foreign keys**, in our case it is much\nmore than just setting the foreign key attribute on the parent model. In Neo4j (and Graph in general) a relationship is an entity itself that can also have attributes of its own, hence the introduction of\n[**Edges**](#Edges)\n\n\u003e *Note:* Associated models does not persist relations automatically when calling `associate()`.\n\n```php\n$account = Account::find(1986);\n\n// $relation will be Vinelab\\NeoEloquent\\Eloquent\\Edges\\EdgeIn\n$relation = $user-\u003eaccount()-\u003eassociate($account);\n\n// Save the relation\n$relation-\u003esave();\n```\n\nThe Cypher performed by this statement will be as follows:\n\n```\nMATCH (account:`Account`), (user:`User`)\nWHERE id(account) = 1986 AND id(user) = 9862\nMERGE (account)\u003c-[rel_user_account:ACCOUNT]-(user)\nRETURN rel_user_account;\n```\n\n### One-To-Many\n\n```php\nclass User extends NeoEloquent {\n\n    public function posts()\n    {\n        return $this-\u003ehasMany('Post', 'POSTED');\n    }\n}\n```\n\nThis represents an `OUTGOING` relationship direction\nfrom the `:User` node to the `:Post` node.\n\n```php\n$user = User::find(1);\n$post = new Post(['title' =\u003e 'The Title', 'body' =\u003e 'Hot Body']);\n$user-\u003eposts()-\u003esave($post);\n```\n\nSimilar to `One-To-One` relationships the returned value from a `save()` statement is an\n`Edge[In|Out]`\n\nThe Cypher performed by this statement will be as follows:\n\n```\nMATCH (user:`User`)\nWHERE id(user) = 1\nCREATE (user)-[rel_user_post:POSTED]-\u003e(post:`Post` {title: 'The Title', body: 'Hot Body', created_at: '15-05-2014', updated_at: '15-05-2014'})\nRETURN rel_user_post;\n```\n\n##### Defining The Inverse Of This Relation\n\n```php\nclass Post extends NeoEloquent {\n\n    public function author()\n    {\n        return $this-\u003ebelongsTo('User', 'POSTED');\n    }\n}\n```\n\nThis represents an `INCOMING` relationship direction from\nthe `:User` node to this `:Post` node.\n\n### Many-To-Many\n\n```php\nclass User extends NeoEloquent {\n\n    public function followers()\n    {\n        return $this-\u003ebelongsToMany('User', 'FOLLOWS');\n    }\n}\n```\n\nThis represents an `INCOMING` relationship between a `:User` node and another `:User`.\n\n```php\n$jd = User::find(1012);\n$mc = User::find(1013);\n```\n\n`$jd` follows `$mc`:\n\n```php\n$jd-\u003efollowers()-\u003esave($mc);\n```\n\nOr using the `attach()` method:\n\n```php\n$jd-\u003efollowers()-\u003eattach($mc);\n// Or..\n$jd-\u003efollowers()-\u003eattach(1013); // 1013 being the id of $mc ($mc-\u003egetKey())\n```\n\nThe Cypher performed by this statement will be as follows:\n\n```\nMATCH (user:`User`), (followers:`User`)\nWHERE id(user) = 1012 AND id(followers) = 1013\nCREATE (followers)-[:FOLLOWS]-\u003e(user)\nRETURN rel_follows;\n```\n\n`$mc` follows `$jd` back:\n\n```php\n$mc-\u003efollowers()-\u003esave($jd);\n```\n\nThe Cypher performed by this statement will be as follows:\n\n```\nMATCH (user:`User`), (followers:`User`)\nWHERE id(user) = 1013 AND id(followers) = 1012\nCREATE (user)-[rel_user_followers:FOLLOWS]-\u003e(followers)\nRETURN rel_follows;\n```\n\nget the followers of `$jd`\n\n```php\n$followers = $jd-\u003efollowers;\n```\n\nThe Cypher performed by this statement will be as follows:\n\n```\nMATCH (user:`User`), (followers:`User`), (user)-[rel_user_followers:FOLLOWS]-(followers)\nWHERE id(user) = 1012\nRETURN rel_follows;\n```\n\n### Dynamic Properties\n\n```php\nclass Phone extends NeoEloquent {\n\n    public function user()\n    {\n        return $this-\u003ebelongsTo('User');\n    }\n\n}\n\n$phone = Phone::find(1006);\n$user = $phone-\u003euser;\n// or getting an attribute out of the related model\n$name = $phone-\u003euser-\u003ename;\n```\n\n### Polymorphic\n\nThe concept behind Polymorphic relations is purely relational to the bone but when it comes\nto graph we are representing it as a [HyperEdge](http://docs.neo4j.org/chunked/stable/cypher-cookbook-hyperedges.html).\n\nHyper edges involves three models, the **parent** model, **hyper** model and **related** model\nrepresented in the following figure:\n\n![HyperEdges](https://googledrive.com/host/0BznzZ2lBbT0cLW9YcjNldlJkcXc/HyperEdge.png \"HyperEdges\")\n\nSimilarly in code this will be represented by three models `User` `Comment` and `Post`\nwhere a `User` with id 1 posts a `Post` and a `User` with id 6 `COMMENTED` a `Comment` `ON` that `Post`\nas follows:\n\n```php\nclass User extends NeoEloquent {\n\n    public function comments($morph = null)\n    {\n        return $this-\u003ehyperMorph($morph, 'Comment', 'COMMENTED', 'ON');\n    }\n\n}\n```\n\nIn order to keep things simple but still involving the three models we will have to pass the\n`$morph` which is any `commentable` model, in our case it's either a `Video` or a `Post` model.\n\n\u003e **Note:** Make sure to have it defaulting to `null` so that we can Dynamicly or Eager load\nwith `$user-\u003ecomments` later on.\n\nCreating a `Comment` with the `create()` method.\n\n```php\n$user = User::find(6);\n$post = Post::find(2);\n\n$user-\u003ecomments($post)-\u003ecreate(['text' =\u003e 'Totally agree!', 'likes' =\u003e 0, 'abuse' =\u003e 0]);\n```\n\nAs usual we will have returned an Edge, but this time it's not directed it is an instance of\n`HyperEdge`, read more about [HyperEdges here](#hyperedge).\n\nOr you may save a Comment instance:\n\n```php\n$comment = new Comment(['text' =\u003e 'Magnificent', 'likes' =\u003e 0, 'abuse' =\u003e 0]);\n\n$user-\u003ecomments($post)-\u003esave($comment);\n```\n\nAlso all the functionalities found in a `BelongsToMany` relationship are supported like\nattaching models by Ids:\n\n```php\n$user-\u003ecomments($post)-\u003eattach([$id, $otherId]);\n```\n\nOr detaching models:\n\n```php\n$user-\u003ecomments($post)-\u003edetach($comment); // or $comment-\u003eid\n```\n\nSync too:\n\n```php\n$user-\u003ecomments($post)-\u003esync([$id, $otherId, $someId]);\n```\n\n#### Retrieving Polymorphic Relations\n\nFrom our previous example we will use the `Video` model to retrieve their comments:\n\n```php\nclass Video extends NeoEloquent {\n\n    public function comments()\n    {\n        return $this-\u003emorphMany('Comment', 'ON');\n    }\n\n}\n```\n\n##### Dynamicly Loading Morph Model\n\n```php\n$video = Video::find(3);\n$comments = $video-\u003ecomments;\n```\n\n##### Eager Loading Morph Model\n\n```php\n$video = Video::with('comments')-\u003efind(3);\nforeach ($video-\u003ecomments as $comment)\n{\n    //\n}\n```\n\n#### Retrieving The Inverse of a Polymorphic Relation\n\n```php\nclass Comment extends NeoEloquent {\n\n    public function commentable()\n    {\n        return $this-\u003emorphTo();\n    }\n\n}\n```\n\n```php\n$postComment = Comment::find(7);\n$post = $comment-\u003ecommentable;\n\n$videoComment = Comment::find(5);\n$video = $comment-\u003ecommentable;\n\n// You can also eager load them\nComment::with('commentable')-\u003eget();\n```\n\nYou may also specify the type of morph you would like returned:\n\n```php\nclass Comment extends NeoEloquent {\n\n    public function post()\n    {\n        return $this-\u003emorphTo('Post', 'ON');\n    }\n\n    public function video()\n    {\n        return $this-\u003emorphTo('Video', 'ON');\n    }\n\n}\n```\n\n#### Polymorphic Relations In Short\n\nTo drill things down here's how our three models involved in a Polymorphic relationship connect:\n\n```php\nclass User extends NeoEloquent {\n\n    public function comments($morph = null)\n    {\n        return $this-\u003ehyperMorph($morph, 'Comment', 'COMMENTED', 'ON');\n    }\n\n}\n```\n\n```php\nclass Post extends NeoEloquent { // Video is the same as this one\n\n    public function comments()\n    {\n        return $this-\u003emorphMany('Comment', 'ON');\n    }\n\n}\n```\n\n```php\nclass Comment extends NeoEloquent {\n\n    public function commentable()\n    {\n        return $this-\u003emorphTo();\n    }\n\n}\n\n```\n\n### Eager Loading\n\n```php\nclass Book extends NeoEloquent {\n\n    public function author()\n    {\n        return $this-\u003ebelongsTo('Author');\n    }\n}\n```\n\nLoading authors with their books with the least performance overhead possible.\n\n```php\nforeach (Book::with('author')-\u003eget() as $book)\n{\n    echo $book-\u003eauthor-\u003ename;\n}\n```\n\nOnly two Cypher queries will be run in the loop above:\n\n```\nMATCH (book:`Book`) RETURN *;\n\nMATCH (book:`Book`), (book)\u003c-[:WROTE]-(author:`Author`) WHERE id(book) IN [1, 2, 3, 4, 5, ...] RETURN book, author;\n```\n\n## Edges\n\n- [EdgeIn](#edgein)\n- [EdgeOut](#edgeout)\n- [HyperEdge](#hyperedge)\n- [Working with Edges](#working-with-edges)\n- [Edge Attributes](#edge-attributes)\n\n### Introduction\n\nDue to the fact that relationships in Graph are much different than other database types so\nwe will have to handle them accordingly. Relationships have directions that can vary between\n**In** and **Out** respectively towards the parent node.\n\nEdges give you the ability to manipulate relationships properties the same way you do with models.\n\n```php\n$edge = $location-\u003eassociate($user);\n$edge-\u003elast_visited = 'today';\n$edge-\u003esave(); // true\n```\n\n#### EdgeIn\n\nRepresents an `INCOMING` direction relationship from the related model towards the parent model.\n\n```php\nclass Location extends NeoEloquent {\n\n    public function user()\n    {\n        return $this-\u003ebelongsTo('User', 'LOCATED_AT');\n    }\n\n}\n```\n\nTo associate a `User` to a `Location`:\n\n```php\n$location = Location::find(1922);\n$user = User::find(3876);\n$relation = $location-\u003eassociate($user);\n```\n\nwhich in Cypher land will map to `(:Location)\u003c-[:LOCATED_AT]-(:User)` and `$relation`\nbeing an instance of `EdgeIn` representing an incoming relationship towards the parent.\n\nAnd you can still access the models from the edge:\n\n```php\n$relation = $location-\u003eassociate($user);\n$location = $relation-\u003eparent();\n$user = $relation-\u003erelated();\n```\n\n#### EdgeOut\n\nRepresents an `OUTGOING` direction relationship from the parent model to the related model.\n\n```php\nclass User extends NeoEloquent {\n\n    public function posts()\n    {\n        return $this-\u003ehasMany('Post', 'POSTED');\n    }\n\n}\n```\n\nTo save an outgoing edge from `:User` to `:Post` it goes like:\n\n```php\n$post = new Post(['...']);\n$posted = $user-\u003eposts()-\u003esave($post);\n```\n\nWhich in Cypher would be `(:User)-[:POSTED]-\u003e(:Post)` and `$posted` being the `EdgeOut` instance.\n\nAnd fetch the related models:\n\n```php\n$edge = $user-\u003eposts()-\u003esave($post);\n$user = $edge-\u003eparent();\n$post = $edge-\u003erelated();\n```\n\n#### HyperEdge\n\nThis edge comes as a result of a [Polymorphic Relation](#polymorphic) representing an edge involving\ntwo other edges **left** and **right** that can be accessed through the `left()` and `right()` methods.\n\nThis edge is treated a bit different than the others since it is not a direct relationship\nbetween two models which means it has no specific direction.\n\n```php\n$edge = $user-\u003ecomments($post)-\u003eattach($comment);\n// Access the left and right edges\n$left = $edge-\u003eleft();\n$user = $left-\u003eparent();\n$comment = $left-\u003erelated();\n\n$right = $edge-\u003eright();\n$comment = $right-\u003eparent();\n$post = $right-\u003erelated();\n```\n\n### Working With Edges\n\nAs stated earlier **Edges** are entities to Graph unlike *SQL* where they are a matter of a\nforeign key having the value of the parent model as an attribute on the belonging model or in\n*Documents* where they are either embeds or ids as references. So we developed them to be *light\nmodels* which means you can work with them as if you were working with an `Eloquent` instance - to a certain extent,\nexcept [HyperEdges](#hyperedges).\n\n```php\n// Create a new relationship\n$relation = $location-\u003eassociate($user); // Vinelab\\NeoEloquent\\Eloquent\\Edges\\EdgeIn\n\n// Save the relationship to the database\n$relation-\u003esave(); // true\n```\n\nIn the case of a `HyperEdge` you can access all three models as follows:\n\n```php\n$edge    = $user-\u003ecomments($post)-\u003esave($comment);\n$user    = $edge-\u003eparent();\n$comment = $edge-\u003ehyper();\n$post    = $edge-\u003erelated();\n```\n\n#### Edge Attributes\n\nBy default, edges will have the timestamps `created_at` and `updated_at` automatically set and updated **only if** timestamps are enabled by setting `$timestamps` to `true`\non the parent model.\n\n```php\n$located_at = $location-\u003eassociate($user);\n$located_at-\u003esince = 1966;\n$located_at-\u003epresent = true;\n$located_at-\u003esave();\n\n// $created_at and $updated_at are Carbon\\Carbon instances\n$created_at = $located_at-\u003ecreated_at;\n$updated_at = $located_at-\u003eupdated_at;\n```\n\n##### Retrieve an Edge from a Relation\n\nThe same way an association will create an `EdgeIn` relationship we can retrieve\nthe edge between two models by calling the `edge($model)` method on the `belongsTo`\nrelationship.\n\n```php\n$location = Location::find(1892);\n$edge = $location-\u003euser()-\u003eedge();\n```\n\nYou may also specify the model at the other side of the edge.\n\n\u003e Note: By default NeoEloquent will try to pefrorm the `$location-\u003euser` internally to figure\nout the related side of the edge based on the relation function name, in this case it's\n`user()`.\n\n```php\n$location = Location::find(1892);\n$edge = $location-\u003euser()-\u003eedge($location-\u003euser);\n```\n\n## Only in Neo\n\n- [CreateWith](#createwith)\n\nHere you will find NeoEloquent-specific methods and implementations that with the\nwonderful Eloquent methods would make working with Graph and Neo4j a blast!\n\n### CreateWith\n\n- [Creating Relations](#creating-new-records-and-relations)\n- [Attaching Relations](#attaching-existing-records-as-relations)\n\nThis method will \"kind of\" fill the gap between relational and document databases,\nit allows the creation of multiple related models with one database hit.\n\n#### Creating New Records and Relations\n\nHere's an example of creating a post with attached photos and videos:\n\n```php\nclass Post extends NeoEloquent {\n\n    public function photos()\n    {\n        return $this-\u003ehasMany('Photo', 'PHOTO');\n    }\n\n    public function videos()\n    {\n        return $this-\u003ehasMany('Video', 'VIDEO');\n    }\n}\n```\n\n```php\n\nPost::createWith(['title' =\u003e 'the title', 'body' =\u003e 'the body'], [\n    'photos' =\u003e [\n        [\n            'url'      =\u003e 'http://url',\n            'caption'  =\u003e '...',\n            'metadata' =\u003e '...'\n        ],\n        [\n            'url' =\u003e 'http://other.url',\n            'caption' =\u003e 'the bay',\n            'metadata' =\u003e '...'\n        ]\n    ],\n\n    'videos' =\u003e [\n        'title' =\u003e 'Boats passing us by',\n        'description' =\u003e '...'\n    ]\n]);\n```\n\n\u003e The keys `photos` and `videos` must be the same as the relation method names in the\n`Post` model.\n\nThe Cypher query performed by the example above is:\n\n```\nCREATE (post:`Post` {title: 'the title', body: 'the body'}),\n(post)-[:PHOTO]-\u003e(:`Photo` {url: 'http://url', caption: '...', metadata: '...'}),\n(post)-[:PHOTO]-\u003e(:`Photo` {url: 'http://other', caption: 'the bay', metadata: '...'}),\n(post)-[:VIDEO]-\u003e(:`Video` {title: 'Boats passing us by', description: '...'});\n```\n\nWe will get the nodes created with their relations as such:\n\n![CreateWith](https://googledrive.com/host/0BznzZ2lBbT0cLW9YcjNldlJkcXc/createWith-preview.db.png \"CreateWith\")\n\nYou may also mix models and attributes as relation values but it is not necessary\nsince NeoEloquent will pass the provided attributes through the `$fillable`\nfilter pipeline:\n\n```php\n$videos = new Video(['title' =\u003e 'foo', 'description' =\u003e 'bar']);\nPost::createWith($info, compact('videos'));\n```\n\nYou may also use a single array of attributes as such:\n\n```php\nclass User extends NeoEloquent {\n\n    public function account()\n    {\n        return $this-\u003ehasOne('Account');\n    }\n}\n\nUser::createWith(['name' =\u003e 'foo'], ['account' =\u003e ['guid' =\u003e 'bar', 'email' =\u003e 'some@mail.net']]);\n```\n\n#### Attaching Existing Records as Relations\n\n`createWith` is intelligent enough to know the difference when you pass an existing model,\na model Id or new records that you need to create which allows mixing new records with existing ones.\n\n```php\nclass Post extends NeoEloquent {\n\n    public function tags()\n    {\n        return $this-\u003ehasMany('Tag', 'TAG');\n    }\n}\n```\n\n```php\n$tag1 = Tag::create(['title' =\u003e 'php']);\n$tag2 = Tag::create(['title' =\u003e 'dev']);\n\n$post = Post::createWith(['title' =\u003e 'foo', 'body' =\u003e 'bar'], ['tags' =\u003e [$tag1, $tag2]]);\n```\n\nAnd we will get the `Post` related to the existing `Tag` nodes.\n\nOr using the `id` of the model:\n\n```php\nPost::createWith(['title' =\u003e 'foo', 'body' =\u003e 'bar'], ['tags' =\u003e 1, 'privacy' =\u003e 2]);\n```\n\nThe Cypher for the query that attaches records would be:\n\n```\nCREATE (post:`Post` {title: 'foo', 'body' =\u003e 'bar'})\nWITH post\nMATCH (tag:`Tag`)\nWHERE id(tag) IN [1, 2]\nCREATE (post)-[:TAG]-\u003e(tag);\n```\n\n\n## Migration\nFor migrations to work please perform the following:\n\n- create the folder `app/database/labels`\n- modify `composer.json` and add `app/database/labels` to the `classmap` array\n\nSince Neo4j is a schema-less database you don't need to predefine types of properties for labels.\nHowever you will be able to perform [Indexing](http://neo4j.com/docs/stable/query-schema-index.html) and [Constraints](http://neo4j.com/docs/stable/query-constraints.html) using NeoEloquent's pain-less [Schema](#schema).\n\n#### Commands\nNeoEloquent introduces new commands under the `neo4j` namespace so you can still use Eloquent's migration commands side-by-side.\n\nMigration commands are the same as those of Eloquent, in the form of `neo4j:migrate[:command]`\n\n    neo4j:make:migration                 Create a new migration file\n    neo4j:migrate                        Run the database migrations\n    neo4j:migrate:reset                  Rollback all database migrations\n    neo4j:migrate:refresh                Reset and re-run all migrations\n    neo4j:migrate:rollback               Rollback the last database migration\n\n\n### Creating Migrations\n\nLike in Laravel you can create a new migration by using the `make` command with Artisan:\n\n    php artisan neo4j:make:migration create_user_label\n\nLabel migrations will be placed in `app/database/labels`\n\nYou can add additional options to commands like:\n\n    php artisan neo4j:make:migration foo --path=app/labels\n    php artisan neo4j:make:migration create_user_label --create=User\n    php artisan neo4j:make:migration create_user_label --label=User\n\n\n### Running Migrations\n\n##### Run All Outstanding Migrations\n\n    php artisan neo4j:migrate\n\n##### Run All Outstanding Migrations For A Path\n\n    php artisan neo4j:migrate --path=app/foo/labels\n\n##### Run All Outstanding Migrations For A Package\n\n    php artisan neo4j:migrate --package=vendor/package\n\n\u003eNote: If you receive a \"class not found\" error when running migrations, try running the `composer dump-autoload` command.\n\n#### Forcing Migrations In Production\n\nTo force-run migrations on a production database you can use:\n\n    php artisan neo4j:migrate --force\n\n### Rolling Back Migrations\n\n##### Rollback The Last Migration Operation\n\n    php artisan neo4j:migrate:rollback\n\n##### Rollback all migrations\n\n    php artisan neo4j:migrate:reset\n\n##### Rollback all migrations and run them all again\n\n    php artisan neo4j:migrate:refresh\n\n    php artisan neo4j:migrate:refresh --seed\n\n## Schema\nNeoEloquent will alias the `Neo4jSchema` facade automatically for you to be used in manipulating labels.\n\n```php\nNeo4jSchema::label('User', function(Blueprint $label)\n{\n    $label-\u003eunique('uuid');\n});\n```\n\nIf you decide to write Migration classes manually (not using the generator) make sure to have these `use` statements in place:\n\n- `use Vinelab\\NeoEloquent\\Schema\\Blueprint;`\n- `use Vinelab\\NeoEloquent\\Migrations\\Migration;`\n\nCurrently Neo4j supports `UNIQUE` constraint and `INDEX` on properties. You can read more about them at\n\n\u003chttp://docs.neo4j.org/chunked/stable/graphdb-neo4j-schema.html\u003e\n\n#### Schema Methods\n\nCommand                           | Description\n------------                      | -------------\n`$label-\u003eunique('email')`           | Adding a unique constraint on a property\n`$label-\u003edropUnique('email')`       | Dropping a unique constraint from property\n`$label-\u003eindex('uuid')`           | Adding index on property\n`$label-\u003edropIndex('uuid')`       | Dropping index from property\n\n### Droping Labels\n\n```php\nNeo4jSchema::drop('User');\nNeo4jSchema::dropIfExists('User');\n```\n\n### Renaming Labels\n\n```php\nNeo4jSchema::renameLabel($from, $to);\n```\n\n### Checking Label's Existence\n\n```php\nif (Neo4jSchema::hasLabel('User')) {\n\n} else {\n\n}\n```\n\n### Checking Relation's Existence\n\n```php\nif (Neo4jSchema::hasRelation('FRIEND_OF')) {\n\n} else {\n\n}\n```\n\nYou can read more about migrations and schema on:\n\n\u003chttp://laravel.com/docs/schema\u003e\n\n\u003chttp://laravel.com/docs/migrations\u003e\n\n## Aggregates\n\nIn addition to the Eloquent builder aggregates, NeoEloquent also has support for\nNeo4j specific aggregates like *percentile* and *standard deviation*, keeping the same\nfunction names for convenience.\nCheck [the docs](http://docs.neo4j.org/chunked/stable/query-aggregation.html) for more.\n\n\u003e `table()` represents the label of the model\n\n```\n$users = DB::table('User')-\u003ecount();\n\n$distinct = DB::table('User')-\u003ecountDistinct('points');\n\n$price = DB::table('Order')-\u003emax('price');\n\n$price = DB::table('Order')-\u003emin('price');\n\n$price = DB::table('Order')-\u003eavg('price');\n\n$total = DB::table('User')-\u003esum('votes');\n\n$disc = DB::table('User')-\u003epercentileDisc('votes', 0.2);\n\n$cont = DB::table('User')-\u003epercentileCont('votes', 0.8);\n\n$deviation = DB::table('User')-\u003estdev('sex');\n\n$population = DB::table('User')-\u003estdevp('sex');\n\n$emails = DB::table('User')-\u003ecollect('email');\n```\n\n## Changelog\nCheck the [Releases](https://github.com/Vinelab/NeoEloquent/releases) for details.\n\n## Avoid\n\nHere are some constraints and Graph-specific gotchas, a list of features that are either not supported or not recommended.\n\n### JOINS :confounded:\n\n- They make no sense for Graph, plus Graph hates them!\nWhich makes them unsupported on purpose. If migrating from an `SQL`-based app\nthey will be your boogie monster.\n\n### Pivot Tables in Many-To-Many Relationships\nThis is not supported, instead we will be using [Edges](#edges) to work with relationships between models.\n\n### Nested Arrays and Objects\n\n- Due to the limitations imposed by the objects map types that can be stored in a single,\nyou can never have nested *arrays* or *objects* in a single model,\nmake sure it's flat. *Example:*\n\n```php\n// Don't\nUser::create(['name' =\u003e 'Some Name', 'location' =\u003e ['lat' =\u003e 123, 'lng'=\u003e -123 ] ]);\n```\n\nCheck out the [createWith()](#createwith) method on how you can achieve this in a Graph way.\n\n## Tests\n\n- install a Neo4j instance and run it with the default configuration `localhost:7474`\n- make sure the database graph is empty to avoid conflicts\n- after running `composer install` there should be `/vendor/bin/phpunit`\n- run `./vendor/bin/phpunit` after making sure that the Neo4j instance is running\n\n\u003e Tests marked as incomplete means they are either known issues or non-supported features,\ncheck included messages for more info.\n\n## Factories\n \n  \u003e You can use default Laravel `factory()` helper for NeoEloquent models too.\n\n - define needed factories inside `database/factories/`(read more)[https://laravel.com/docs/5.6/database-testing#writing-factories];\n - use `factory()` in the same style as default Laravel `factory()`.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvinelab%2Fneoeloquent","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvinelab%2Fneoeloquent","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvinelab%2Fneoeloquent/lists"}