├── .gitignore ├── README.md ├── acl ├── index.md ├── installation.md ├── introduction.md ├── lumen.md ├── organisations.md ├── permissions.md ├── roles.md └── upgrade.md ├── extensions ├── blameable.md ├── custom-functions.md ├── index.md ├── installation.md ├── introduction.md ├── iptraceable.md ├── loggable.md ├── lumen.md ├── sluggable.md ├── softdeletes.md ├── sortable.md ├── timestamps.md ├── translatable.md ├── tree.md ├── upgrade.md └── uploadable.md ├── fluent ├── embeddables.md ├── entities.md ├── extensions.md ├── first-mapping.md ├── index.md ├── introduction.md ├── laravel-installation.md ├── mapped-superclass.md ├── reference.md └── standalone-installation.md ├── migrations ├── builder.md ├── configuration.md ├── diff.md ├── execute.md ├── generate.md ├── index.md ├── installation.md ├── introduction.md ├── latest.md ├── lumen.md ├── migrate.md ├── refresh.md ├── reset.md ├── rollback.md ├── status.md ├── upgrade.md └── version.md ├── orm ├── auth.md ├── caching.md ├── config-file.md ├── config-migrator.md ├── connections.md ├── console.md ├── contributions.md ├── default-table-options.md ├── doctrine-manager.md ├── entities.md ├── entity-manager.md ├── index.md ├── installation.md ├── introduction.md ├── lumen.md ├── meta-data-configuration.md ├── meta-data.md ├── multiple-connections.md ├── notifications.md ├── passwords.md ├── repositories.md ├── testing.md ├── troubleshooting.md ├── upgrade.md └── validation.md └── scout ├── index.md ├── indexing.md ├── installation.md ├── introduction.md └── searching.md /.gitignore: -------------------------------------------------------------------------------- 1 | /1.0.iml 2 | /docs.iml 3 | .idea 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Laravel Doctrine Documentation 2 | 3 | 4 | 5 | ## Contribution Guidelines 6 | 7 | If you are submitting documentation for the **current stable release**, submit it to the corresponding branch. For example, documentation for Laravel Doctrine 1.0 would be submitted to the `1.0` branch. Documentation intended for the next release of Laravel Doctrine should be submitted to the `master` branch. 8 | -------------------------------------------------------------------------------- /acl/index.md: -------------------------------------------------------------------------------- 1 | - Prologue 2 | - [Introduction](/docs/{{version}}/acl/introduction) 3 | - [Upgrade Guide](/docs/{{version}}/acl/upgrade) 4 | - Setup 5 | - [Laravel](/docs/{{version}}/acl/installation) 6 | - [Lumen](/docs/{{version}}/acl/lumen) 7 | - Features 8 | - [Roles](/docs/{{version}}/acl/roles) 9 | - [Permissions](/docs/{{version}}/acl/permissions) 10 | - [Organisations](/docs/{{version}}/acl/organisations) 11 | -------------------------------------------------------------------------------- /acl/installation.md: -------------------------------------------------------------------------------- 1 | # Installation in Laravel 6+ 2 | 3 | Install this package with composer: 4 | 5 | ``` 6 | composer require laravel-doctrine/acl 7 | ``` 8 | 9 | After updating composer, add the ServiceProvider to the providers array in `config/app.php` 10 | 11 | ```php 12 | LaravelDoctrine\ACL\AclServiceProvider::class, 13 | ``` 14 | 15 | To publish the config use: 16 | 17 | ```php 18 | php artisan vendor:publish --tag="config" --provider="LaravelDoctrine\ACL\AclServiceProvider" 19 | ``` 20 | -------------------------------------------------------------------------------- /acl/introduction.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | #### ACL functionality for Laravel powered by Doctrine 4 | 5 | In addition to providing authentication services out of the box, Laravel also provides a simple way to organize authorization logic and control access to resources. 6 | There are a variety of methods and helpers to assist you in organizing your authorization logic, and we'll cover each of them in this document. 7 | Laravel Doctrine offers an easy way to combine Doctrine with this system. 8 | 9 | *Laravel Doctrine ACL offers:* 10 | 11 | * User can belong to Organisation(s) 12 | * User can have Roles 13 | * User and Roles can have Permissions 14 | * Seamless integration with Laravel's Authorization system 15 | -------------------------------------------------------------------------------- /acl/lumen.md: -------------------------------------------------------------------------------- 1 | # Installation in Lumen 6+ 2 | 3 | To set up Laravel Doctrine ACL in Lumen, we need some additional steps. 4 | 5 | Install this package with composer: 6 | 7 | ``` 8 | composer require laravel-doctrine/acl 9 | ``` 10 | 11 | After updating composer, open `bootstrap/app.php` and register the Service Provider after `LaravelDoctrine\ORM\DoctrineServiceProvider::class` 12 | 13 | ```php 14 | $app->register(LaravelDoctrine\ACL\AclServiceProvider::class); 15 | ``` 16 | 17 | ### Config 18 | 19 | If you want to overrule the Doctrine config. You will have to create a `config/acl.php` file and copy the contents from the package config. 20 | -------------------------------------------------------------------------------- /acl/organisations.md: -------------------------------------------------------------------------------- 1 | # Organisations 2 | 3 | A lot of applications have an organisations structure. Teams, Organisations, Offices, ... To add this functionality to your Application, you will have 4 | to create an entity that implements `LaravelDoctrine\ACL\Contracts\Organisation`. Next change `acl.organisations.entity` to your entity. 5 | 6 | ```php 7 | id; 38 | } 39 | 40 | /** 41 | * @return string 42 | */ 43 | public function getName() 44 | { 45 | return $this->name; 46 | } 47 | } 48 | ``` 49 | 50 | ### User can belong to one organisation 51 | 52 | The User class should implement `LaravelDoctrine\ACL\Contracts\BelongsToOrganisation`. You can use the `@ACL\BelongsToOrganisation` annotation to define the relation. 53 | 54 | ```php 55 | organisation; 78 | } 79 | } 80 | ``` 81 | 82 | ### User can belong to multiple organisations 83 | 84 | The User class should implement `LaravelDoctrine\ACL\Contracts\BelongsToOrganisations`. You can use the `@ACL\BelongsToOrganisations` annotation to define the relation. 85 | 86 | ```php 87 | organisations; 110 | } 111 | } 112 | ``` 113 | 114 | ### Checking if a User has a certain Organisation 115 | 116 | The `LaravelDoctrine\ACL\Organisations\BelongsToOrganisation` trait provides methods to check if the User has a certain Organisation. 117 | 118 | ```php 119 | $user->belongsToOrganisation($org); 120 | ``` 121 | 122 | An array of Organisations or Organisation names can also be checked for. 123 | 124 | ```php 125 | $user->belongsToOrganisation([$org1,$org2,$org3]); 126 | $user->belongsToOrganisation(['Company 1','Company 2','Company 3']); 127 | ``` 128 | 129 | Specifying `true` for the second argument will check that **all** roles are present. 130 | 131 | ```php 132 | $user->belongsToOrganisation([$org1,$org2,$org3], true); //User must belong to all three organisations to return true 133 | $user->belongsToOrganisation(['Company 1','Company 2','Company 3'], true); 134 | ``` 135 | -------------------------------------------------------------------------------- /acl/permissions.md: -------------------------------------------------------------------------------- 1 | # Permissions 2 | 3 | Both User and Role can have permissions. 4 | To add this behaviour we can simply add the `LaravelDoctrine\ACL\Contracts\HasPermissions` interface to them. 5 | We can also add the `LaravelDoctrine\ACL\Permissions\HasPermissions` trait to have some nice helpers. 6 | We can use the `@ACL\HasPermissions` annotations to define the permissions relation. 7 | 8 | ```php 9 | getAllPermissions(); 32 | ``` 33 | 34 | ### Config Permissions 35 | 36 | By setting the permissions driver to `config`, no additional `permissions` table will be created, but permissions will be expected to be added inside the config: `acl.permissions.list` The given permissions will now be stored in the Entity as json. 37 | 38 | ```php 39 | [ 43 | 'driver' => 'config', 44 | 'list' => [ 45 | 'create.posts' 46 | ] 47 | ] 48 | ]; 49 | ``` 50 | 51 | ### Database Permissions 52 | 53 | By setting the permissions driver to `doctrine`, an additional `permissions` table will be created. Permissions will be stored in Pivot tables for roles and users. A default `Permission` entity is included in this package. 54 | You can replace that one by your own inside the config as long as it implements the ` LaravelDoctrine\ACL\Contracts\Permission` interface. 55 | 56 | ### Checking if a User or Role has permission 57 | 58 | #### On the User or Role entity 59 | 60 | When adding the `LaravelDoctrine\ACL\Permissions\HasPermissions` you will get a `hasPermissionTo` method. 61 | First the `User` entity will check if it has the right permission itself. If not it will search in its roles. If none of them has permission, it will return false. 62 | 63 | ```php 64 | $user->hasPermissionTo('create.posts'); 65 | $role->hasPermissionTo('create.posts'); 66 | ``` 67 | 68 | An array of permissions can also checked for. 69 | 70 | ```php 71 | $user->hasPermissionTo(['create.posts','create.page']); 72 | $role->hasPermissionTo(['create.posts','create.page']); 73 | ``` 74 | 75 | Specifying `true` for the second argument will check that **all** permissions are present. 76 | 77 | ```php 78 | $user->hasPermissionTo(['create.posts','create.page'], true); //all permissions are required to return true 79 | $role->hasPermissionTo(['create.posts','create.page'], true); 80 | ``` 81 | 82 | 83 | #### Using the Gate helper 84 | 85 | All permissions are automatically defined inside Laravel's Gate helper. 86 | 87 | ```php 88 | Gate::allows('create.posts'); 89 | @can('create.posts'); 90 | $user->can('create.posts'); 91 | ``` 92 | -------------------------------------------------------------------------------- /acl/roles.md: -------------------------------------------------------------------------------- 1 | # Roles 2 | 3 | ### Role Entity 4 | 5 | To add Roles to your application, you'll have to create a `Role` entity. This entity should implement `LaravelDoctrine\ACL\Contracts\Role`. 6 | Next you should change the class name the `acl.roles.entity` config to your class, by default this is set to `App\Entities\Role`. 7 | 8 | ``` 9 | id; 40 | } 41 | 42 | /** 43 | * @return string 44 | */ 45 | public function getName() 46 | { 47 | return $this->name; 48 | } 49 | } 50 | ``` 51 | 52 | ### A User has Roles 53 | 54 | Inside your `User` entity, you have to define the relation with the role. The `User` entity should implement the `LaravelDoctrine\ACL\Contracts\HasRoles` interface. 55 | If you are using annotations, you can use the `@ACL\HasRoles` annotations to define the relations (instead of defining the ManyToMany manually). Import `use LaravelDoctrine\ACL\Mappings as ACL;` in top of the class. 56 | 57 | ```php 58 | roles; 88 | } 89 | } 90 | ``` 91 | 92 | ### Checking if a User has a certain Role 93 | 94 | The `LaravelDoctrine\ACL\Roles\HasRoles` trait provides methods to check if the User has a certain Role. 95 | 96 | ```php 97 | $user->hasRole($role); 98 | $user->hasRoleByName('Super Admin'); 99 | ``` 100 | 101 | An array of roles or role names can also checked for. 102 | 103 | ```php 104 | $user->hasRole([$role1,$role2,$role3]); 105 | $user->hasRoleByName(['User','Admin','Manager']); 106 | ``` 107 | 108 | Specifying `true` for the second argument will check that **all** roles are present. 109 | 110 | ```php 111 | $user->hasRole([$role1,$role2,$role3], true); //User must have all roles 112 | $user->hasRoleByName(['User','Admin','Manager'], true); 113 | ``` 114 | -------------------------------------------------------------------------------- /acl/upgrade.md: -------------------------------------------------------------------------------- 1 | # Upgrade Guide 2 | -------------------------------------------------------------------------------- /extensions/blameable.md: -------------------------------------------------------------------------------- 1 | # Blameable 2 | 3 | Blameable behavior will automate the update of username or user reference fields on your Entities or Documents. It works through annotations and can update fields on creation, update, property subset update, or even on specific property value change. 4 | 5 | * Automatic predefined user field update on creation, update, property subset update, and even on record property changes 6 | * Specific annotations for properties, and no interface required 7 | * Can react to specific property or relation changes to specific value 8 | * Can be nested with other behaviors 9 | * Annotation, Yaml and Xml mapping support for extensions 10 | 11 | ### Installation 12 | 13 | Add `LaravelDoctrine\Extensions\Blameable\BlameableExtension` to `doctrine.extensions` config. 14 | 15 | ### Property annotation 16 | 17 | > @Gedmo\Mapping\Annotation\Blameable 18 | 19 | This annotation tells that this column is blameable 20 | by default it updates this column on update. If column is not a string field or an association 21 | it will trigger an exception. 22 | 23 | Available configuration options: 24 | 25 | | Annotations | Description | 26 | |--|--| 27 | | **on** |is main option and can be **create, update, change** this tells when it should be updated| 28 | | **field** | only valid if **on="change"** is specified, tracks property or a list of properties for changes | 29 | | **value** | only valid if **on="change"** is specified and the tracked field is a single field (not an array), if the tracked field has this **value** then it updates the blame | 30 | 31 | Column is a string field: 32 | 33 | ``` php 34 | [ 28 | 'carbondate' => DoctrineExtensions\Types\CarbonDateType::class, 29 | 'carbondatetime' => DoctrineExtensions\Types\CarbonDateTimeType::class, 30 | 'carbondatetimetz' => DoctrineExtensions\Types\CarbonDateTimeTzType::class, 31 | 'carbontime' => DoctrineExtensions\Types\CarbonTimeType::class 32 | ], 33 | /* 34 | |-------------------------------------------------------------------------- 35 | | Doctrine custom datetime functions 36 | |-------------------------------------------------------------------------- 37 | */ 38 | 'custom_datetime_functions' => [ 39 | 'DATEADD' => DoctrineExtensions\Query\Mysql\DateAdd::class, 40 | 'DATEDIFF' => DoctrineExtensions\Query\Mysql\DateDiff::class 41 | ], 42 | /* 43 | |-------------------------------------------------------------------------- 44 | | Doctrine custom numeric functions 45 | |-------------------------------------------------------------------------- 46 | */ 47 | 'custom_numeric_functions' => [ 48 | 'ACOS' => DoctrineExtensions\Query\Mysql\Acos::class, 49 | 'ASIN' => DoctrineExtensions\Query\Mysql\Asin::class, 50 | 'ATAN' => DoctrineExtensions\Query\Mysql\Atan::class, 51 | 'ATAN2' => DoctrineExtensions\Query\Mysql\Atan2::class, 52 | 'COS' => DoctrineExtensions\Query\Mysql\Cos::class, 53 | 'COT' => DoctrineExtensions\Query\Mysql\Cot::class, 54 | 'DEGREES' => DoctrineExtensions\Query\Mysql\Degrees::class, 55 | 'RADIANS' => DoctrineExtensions\Query\Mysql\Radians::class, 56 | 'SIN' => DoctrineExtensions\Query\Mysql\Sin::class, 57 | 'TAN' => DoctrineExtensions\Query\Mysql\Ta::class 58 | ], 59 | /* 60 | |-------------------------------------------------------------------------- 61 | | Doctrine custom string functions 62 | |-------------------------------------------------------------------------- 63 | */ 64 | 'custom_string_functions' => [ 65 | 'CHAR_LENGTH' => DoctrineExtensions\Query\Mysql\CharLength::class, 66 | 'CONCAT_WS' => DoctrineExtensions\Query\Mysql\ConcatWs::class, 67 | 'FIELD' => DoctrineExtensions\Query\Mysql\Field::class, 68 | 'FIND_IN_SET' => DoctrineExtensions\Query\Mysql\FindInSet::class, 69 | 'REPLACE' => DoctrineExtensions\Query\Mysql\Replace::class, 70 | 'SOUNDEX' => DoctrineExtensions\Query\Mysql\Soundex::class, 71 | 'STR_TO_DATE' => DoctrineExtensions\Query\Mysql\StrToDate::class 72 | ], 73 | 74 | ]; 75 | -------------------------------------------------------------------------------- /extensions/index.md: -------------------------------------------------------------------------------- 1 | - Prologue 2 | - [Introduction](/docs/{{version}}/extensions/introduction) 3 | - [Upgrade Guide](/docs/{{version}}/extensions/upgrade) 4 | - Setup 5 | - [Laravel](/docs/{{version}}/extensions/installation) 6 | - [Lumen](/docs/{{version}}/extensions/lumen) 7 | - Behavioral extensions 8 | - [Blameable](/docs/{{version}}/extensions/blameable) 9 | - [IpTraceable](/docs/{{version}}/extensions/iptraceable) 10 | - [Loggable](/docs/{{version}}/extensions/loggable) 11 | - [Sluggable](/docs/{{version}}/extensions/sluggable) 12 | - [SoftDeletes](/docs/{{version}}/extensions/softdeletes) 13 | - [Sortable](/docs/{{version}}/extensions/sortable) 14 | - [Timestamps](/docs/{{version}}/extensions/timestamps) 15 | - [Translatable](/docs/{{version}}/extensions/translatable) 16 | - [Tree](/docs/{{version}}/extensions/tree) 17 | - [Uploadable](/docs/{{version}}/extensions/uploadable) 18 | - Query/Type extensions 19 | - [Custom functions](/docs/{{version}}/extensions/custom-functions) 20 | -------------------------------------------------------------------------------- /extensions/installation.md: -------------------------------------------------------------------------------- 1 | # Installation in Laravel 6+ 2 | 3 | Install this package with composer: 4 | 5 | ``` 6 | composer require laravel-doctrine/extensions 7 | ``` 8 | 9 | This package wraps extensions from [Gedmo](https://github.com/Atlantic18/DoctrineExtensions) and [Beberlei](https://github.com/beberlei/DoctrineExtensions). 10 | 11 | To include Gedmo extensions install them: 12 | 13 | ``` 14 | 15 | composer require "gedmo/doctrine-extensions=^3.0" 16 | ``` 17 | 18 | If you are using an **annotation driver**, then add the Gedmo (Behavioral) extensions service provider in `config/app.php`: 19 | 20 | ```php 21 | LaravelDoctrine\Extensions\GedmoExtensionsServiceProvider::class, 22 | ``` 23 | 24 | Also be sure to enable the extensions in the `extensions` section of `config/doctrine.php`. 25 | 26 | To include Beberlei (Query/Type) extensions install them: 27 | 28 | ``` 29 | 30 | composer require "beberlei/DoctrineExtensions=^1.0" 31 | ``` 32 | 33 | And then add the Beberlei extensions service provider in `config/app.php`: 34 | 35 | 36 | ```php 37 | LaravelDoctrine\Extensions\BeberleiExtensionsServiceProvider::class, 38 | ``` 39 | -------------------------------------------------------------------------------- /extensions/introduction.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | This package contains extensions for Doctrine2 that hook into the facilities of Doctrine and offer new functionality 4 | or tools to use Doctrine2 more efficiently. This package contains mostly used behaviors which can be easily attached to your event system 5 | of Doctrine2 and handle the records being flushed in the behavioral way 6 | 7 | ### Behavioral extensions (Gedmo) 8 | 9 | * __Blameable__ - updates string or reference fields on create, update and even property change with a string or object (e.g. user). 10 | * __IpTraceable__ - inherited from Timestampable, sets IP address instead of timestamp 11 | * __Loggable__ - helps tracking changes and history of objects, also supports version management. 12 | * __Sluggable__ - urlizes your specified fields into single unique slug 13 | * __SoftDeleteable__ - allows to implicitly remove records 14 | * __Sortable__ - makes any document or entity sortable 15 | * __Timestampable__ - updates date fields on create, update and even property change. 16 | * __Translatable__ - gives you a very handy solution for translating records into different languages. Easy to setup, easier to use. 17 | * __Tree__ - this extension automates the tree handling process and adds some tree specific functions on repository. (closure, nestedset or materialized path) 18 | * __Uploadable__ - provides file upload handling in entity fields 19 | 20 | ### Query/Type extensions (Beberlei) 21 | 22 | A set of extensions to Doctrine 2 that add support for additional queryfunctions available in MySQL and Oracle. 23 | 24 | | DB | Functions | 25 | |--|---------| 26 | | MySQL | `ACOS, ASCII, ASIN, ATAN, ATAN2, BINARY, CEIL, CHAR_LENGTH, CONCAT_WS, COS, COT, COUNTIF, CRC32, DATE, DATE_FORMAT, DATEADD, DATEDIFF, DATESUB, DAY, DAYNAME, DEGREES, FIELD, FIND_IN_SET, FLOOR, FROM_UNIXTIME, GROUP_CONCAT, HOUR, IFELSE, IFNULL, LAST_DAY, MATCH_AGAINST, MD5, MINUTE, MONTH, MONTHNAME, NULLIF, PI, POWER, QUARTER, RADIANS, RAND, REGEXP, REPLACE, ROUND, SECOND, SHA1, SHA2, SIN, SOUNDEX, STD, STRTODATE, SUBSTRING_INDEX, TAN, TIME, TIMESTAMPADD, TIMESTAMPDIFF, UUID_SHORT, WEEK, WEEKDAY, YEAR` | 27 | | Oracle | `DAY, MONTH, NVL, TODATE, TRUNC, YEAR` | 28 | | Sqlite | `DATE, MINUTE, HOUR, DAY, WEEK, WEEKDAY, MONTH, YEAR, STRFTIME*` | 29 | -------------------------------------------------------------------------------- /extensions/iptraceable.md: -------------------------------------------------------------------------------- 1 | # Ip Traceable 2 | 3 | IpTraceable behavior will automate the update of IP trace on your Entities or Documents. It works through annotations and can update fields on creation, update, property subset update, or even on specific property value change. 4 | 5 | * Automatic predefined ip field update on creation, update, property subset update, and even on record property changes 6 | * Specific annotations for properties, and no interface required 7 | * Can react to specific property or relation changes to specific value 8 | * Can be nested with other behaviors 9 | * Annotation, Yaml and Xml mapping support for extensions 10 | 11 | ### Installation 12 | 13 | Add `LaravelDoctrine\Extensions\IpTraceable\IpTraceableExtension` to `doctrine.extensions` config. 14 | 15 | ### Property annotation 16 | 17 | > @Gedmo\Mapping\Annotation\IpTraceable 18 | 19 | This annotation tells that this column is ipTraceable by default it updates this column on update. If column is not a string field it will trigger an exception. 20 | 21 | Available configuration options: 22 | 23 | | Annotations | Description | 24 | |--|--| 25 | | **on** |is main option and can be **create, update, change** this tells when itshould be updated| 26 | | **field** | only valid if **on="change"** is specified, tracks property or a list of properties for changes | 27 | | **value** | only valid if **on="change"** is specified and the tracked field is a single field (not an array), if the tracked field has this **value**then it updates the trace | 28 | 29 | ``` php 30 | @Gedmo\Mapping\Annotation\Loggable() 17 | 18 | This class annotation will store logs to optionally specified logEntryClass. 19 | 20 | | Annotations | Description | 21 | |--|--| 22 | | **logEntryClass** |optional entity which stores logs| 23 | 24 | ### Property annotation 25 | 26 | >@Gedmo\Mapping\Annotation\Versioned 27 | 28 | This property annotation tracks annotated property for changes 29 | 30 | ``` php 31 | register(LaravelDoctrine\Extensions\GedmoExtensionsServiceProvider::class), 25 | ``` 26 | 27 | To include Beberlei (Query/Type) extensions install them: 28 | 29 | ``` 30 | 31 | composer require "beberlei/DoctrineExtensions=^1.0" 32 | ``` 33 | 34 | And then add the Beberlei extensions service provider in `bootstrap/app.php`: 35 | 36 | 37 | ```php 38 | $app->register(LaravelDoctrine\Extensions\BeberleiExtensionsServiceProvider::class), 39 | -------------------------------------------------------------------------------- /extensions/sluggable.md: -------------------------------------------------------------------------------- 1 | # Sluggable 2 | 3 | Sluggable behavior will build the slug of predefined fields on a given field which should store the slug 4 | 5 | - Automatic predefined field transformation into slug 6 | - Slugs can be unique and styled, even with prefixes and/or suffixes 7 | - Can be nested with other behaviors 8 | - Annotation, Yaml and Xml mapping support for extensions 9 | - Multiple slugs, different slugs can link to same fields 10 | 11 | ### Installation 12 | 13 | Add `LaravelDoctrine\Extensions\Sluggable\SluggableExtension` to `doctrine.extensions` config. 14 | 15 | ### Property annotation 16 | 17 | > @Gedmo\Mapping\Annotation\Slug 18 | 19 | This annotation will use the column to store slug generated fields option must be specified, an array of field names to slug 20 | 21 | | Annotations | Description | 22 | |--|--| 23 | | **fields** | array of fields that should be slugged | 24 | 25 | ``` php 26 | @Gedmo\Mapping\Annotation\SoftDeleteable 18 | 19 | This class annotation tells if a class is SoftDeleteable. It has a mandatory parameter "fieldName", which is the name of the field to be used to hold the known "deletedAt" field. It must be of any of the date types. 20 | 21 | | Annotations | Description | 22 | |--|--| 23 | | **fieldName** | The name of the field that will be used to determine if the object is removed or not (NULL means it's not removed. A date value means it was removed). NOTE: The field MUST be nullable. | 24 | 25 | ``` php 26 | @Gedmo\Mapping\Annotation\SortableGroup 17 | 18 | This annotation will be used for grouping 19 | 20 | > @Gedmo\Mapping\Annotation\SortablePosition 21 | 22 | This annotation will be used to store position index 23 | 24 | ``` php 25 | @Gedmo\Mapping\Annotation\Timestampable 17 | 18 | This annotation tells that this column is timestampable by default it updates this column on update. If column is not date, datetime or time type it will trigger an exception. 19 | 20 | | Annotations | Description | 21 | |--|--| 22 | | **on** | is main option and can be create, update, change this tells when it should be updated | 23 | | **field** | only valid if on="change" is specified, tracks property or a list of properties for changes | 24 | | **value** | only valid if on="change" is specified and the tracked field is a single field (not an array), if the tracked field has this value | 25 | 26 | ```php 27 | @Gedmo\Mapping\Annotation\Translatable 16 | 17 | | Annotations | Description | 18 | |--|--| 19 | | **class** | it will use this class to store translations generated | 20 | 21 | ### Property annotation 22 | 23 | > @Gedmo\Mapping\Annotation\Translatable 24 | 25 | It will translate this field 26 | 27 | > @Gedmo\Mapping\Annotation\Locale or @Gedmo\Mapping\Annotation\Language 28 | 29 | This will identify this column as locale or language used to override the global locale 30 | 31 | ```php 32 | @Gedmo\Mapping\Annotation\Tree 17 | 18 | | Annotations | Description | 19 | |--|--| 20 | | **type** | this class annotation sets the tree strategy by using the type parameter. Currently nested, closure or materializedPath strategies are supported. An additional "activateLocking" parameter is available if you use the "Materialized Path" strategy with MongoDB. It's used to activate the locking mechanism (more on that in the corresponding section). | 21 | 22 | ### Property annotation 23 | 24 | > @Gedmo\Mapping\Annotation\TreeLeft 25 | 26 | This field is used to store the tree left value 27 | 28 | > @Gedmo\Mapping\Annotation\TreeRight 29 | 30 | This field is used to store the tree right value 31 | 32 | > @Gedmo\Mapping\Annotation\TreeParent 33 | 34 | This will identify the column as the relation to parent node 35 | 36 | > @Gedmo\Mapping\Annotation\TreeLevel 37 | 38 | This field is used to store the tree level 39 | 40 | > @Gedmo\Mapping\Annotation\TreeRoot 41 | 42 | This field is used to store the tree root id value 43 | 44 | > @Gedmo\Mapping\Annotation\TreePath 45 | 46 | (Materialized Path only) This field is used to store the path. It has an optional parameter "separator" to define the separator used in the path. 47 | 48 | > @Gedmo\Mapping\Annotation\TreePathSource 49 | 50 | (Materialized Path only) This field is used as the source to construct the "path" 51 | 52 | ```php 53 | @Gedmo\Mapping\Annotation\Uploadable 14 | 15 | This class annotation tells if a class is Uploadable. 16 | 17 | | Annotations | Description | 18 | |--|--| 19 | |**allowOverwrite** | If this option is true, it will overwrite a file if it already exists. If you set "false", an exception will be thrown. Default: false| 20 | |**appendNumber** | If this option is true and "allowOverwrite" is false, in the case that the file already exists, it will append a number to the filename. Example: if you're uploading a file named "test.txt", if the file already exists and this option is true, the extension will modify the name of the uploaded file to "test1.txt", where "1" could be any number. The extension will check if the file exists until it finds a filename with a number as its postfix that is not used. If you use a filename generator and this option is true, it will append a number to the filename anyway if a file with the same name already exists. Default value: false| 21 | |**path** | This option expects a string containing the path where the files represented by this entity will be moved. Default: "". Path can be set in other ways: From the listener or from a method. More details later.| 22 | |**pathMethod** | Similar to option "path", but this time it represents the name of a method on the entity that will return the path to which the files represented by this entity will be moved. This is useful in several cases. For example, you can set specific paths for specific entities, or you can get the path from other sources (like a framework configuration) instead of hardcoding it in the entity. Default: "". As first argument this method takes default path, so you can return path relative to default.| 23 | |**callback** | This option allows you to set a method name. If this option is set, the method will be called after the file is moved. Default value: "". As first argument, this method can receive an array with information about the uploaded file, which includes the following keys: **fileName:**, **fileExtension**, **fileWithoutExt**, **filePath**, **fileMimeType**, **fileSize** .| 24 | |**filenameGenerator**| This option allows you to set a filename generator for the file. There are two already included by the extension: SHA1, which generates a sha1 filename for the file, and ALPHANUMERIC, which "normalizes" the filename, leaving only alphanumeric characters in the filename, and replacing anything else with a "-". You can even create your own FilenameGenerator class (implementing the Gedmo\Uploadable\FilenameGenerator\FilenameGeneratorInterface) and set this option with the fully qualified class name. The other option available is "NONE" which, as you may guess, means no generation for the filename will occur. Default: "NONE".| 25 | |**maxSize**| This option allows you to set a maximum size for the file in bytes. If file size exceeds the value set in this configuration, an exception of type "UploadableMaxSizeException" will be thrown. By default, its value is set to 0, meaning that no size validation will occur.| 26 | |**allowedTypes**| With this option you can set a comma-separated list of allowed mime types for the file. The extension will use a simple mime type guesser to guess the file type, and then it will compare it to the list of allowed types. If the mime type is not valid, then an exception of type "UploadableInvalidMimeTypeException" will be thrown. If you set this option, you can't set the disallowedTypes option described next. By default, no validation of mime type occurs. If you want to use a custom mime type guesser, see this.| 27 | |**disallowedTypes**| Similar to the option allowedTypes, but with this one you configure a "black list" of mime types. If the mime type of the file is on this list, n exception of type "UploadableInvalidMimeTypeException" will be thrown. If you set this option, you can't set the allowedTypes option described next. By default, no validation of mime type occurs. If you want to use a custom mime type guesser, see this.| 28 | 29 | ### Property annotation 30 | 31 | > @Gedmo\Mapping\Annotation\UploadableFilePath 32 | 33 | This annotation is used to set which field will receive the path to the file. The field MUST be of type "string". Either this one or UploadableFileName annotation is REQUIRED to be set. 34 | 35 | > @Gedmo\Mapping\Annotation\UploadableFileName 36 | 37 | This annotation is used to set which field will receive the name of the file. The field MUST be of type "string". Either this one or UploadableFilePath annotation is REQUIRED to be set. 38 | 39 | > @Gedmo\Mapping\Annotation\UploadableFileMimeType 40 | 41 | This is an optional annotation used to set which field will receive the mime type of the file as its value. This field MUST be of type "string". 42 | 43 | > @Gedmo\Mapping\Annotation\UploadableFileSize 44 | 45 | This is an optional annotation used to set which field will receive the size in bytes of the file as its value. This field MUST be of type "decimal". 46 | 47 | 48 | ```php 49 | addEntityFileInto($entity, $fileInfo); 75 | ``` 76 | 77 | Another way would be to also register the `LaravelDoctrine\Extensions\Uploadable\UploadableFacade::class` facade in the `aliases` array in the Laravel's `app.php`. Then you can use the facade to call the listener's methods. 78 | 79 | Example with a facade (named `Uploadable`): 80 | ``` 81 | \Uploadable::addEntityFileInfo($entity, $fileInfo); 82 | ``` 83 | 84 | 85 | For full documentation see [here.](https://github.com/Atlantic18/DoctrineExtensions/blob/master/doc/uploadable.md) 86 | -------------------------------------------------------------------------------- /fluent/embeddables.md: -------------------------------------------------------------------------------- 1 | # Embeddables 2 | 3 | While sometimes scalar types such as strings, integers and booleans are enough to save our entity's state, we may find 4 | ourselves in the need to model objects that hold some part of the state and also contain behavior associated to that 5 | data. This objects are known as **ValueObjects** and are very important when designing a rich domain model. 6 | 7 | Since **Doctrine 2.5**, we can map ValueObjects to our database by declaring them **Embeddables**. 8 | 9 | ## What is an embeddable 10 | 11 | An embeddable is an object that can be mapped to a set of columns in a database table. This object will **not** be 12 | mapped to a table by itself, but will be used **inside an entity**, so its columns will be mapped to the entity's table 13 | instead. 14 | 15 | For example, consider a `Scientist` with a given email address `"a.einstein@example.com"`. 16 | If we were to model this, we could do it as follows: 17 | 18 | ```php 19 | class Scientist 20 | { 21 | /** @var string */ 22 | private $email; 23 | } 24 | ``` 25 | 26 | If we were to protect ourselves against malformed emails on our `Scientist` class, we'd have to do something as follows: 27 | 28 | ```php 29 | class Scientist 30 | { 31 | public function __construct(string $email) 32 | { 33 | if (filter_var($email, FILTER_VALIDATE_EMAIL) === false) { 34 | throw new \InvalidArgumentException("Given email [$email] is not valid."); 35 | } 36 | 37 | $this->email = $email; 38 | } 39 | } 40 | ``` 41 | 42 | As soon as any other object requires an email address, we'll have to duplicate this piece of code to validate it. Unless, 43 | of course, we **model the email address as an object**: 44 | 45 | ```php 46 | class Email 47 | { 48 | /** @var string */ 49 | private $address; 50 | 51 | public function __construct(string $address) 52 | { 53 | if (filter_var($address, FILTER_VALIDATE_EMAIL) === false) { 54 | throw new \InvalidArgumentException("Given email [$address] is not valid."); 55 | } 56 | 57 | $this->address = $address; 58 | } 59 | 60 | public function getAddress(): string 61 | { 62 | return $this->address; 63 | } 64 | } 65 | ``` 66 | 67 | ## Mapping embeddables 68 | 69 | While this helps in reducing duplicated code, we still need a way to map the given email address to the database. To do 70 | so, we'll map the `Email` class as an `Embeddable`: 71 | 72 | ```php 73 | class EmailMapping extends EmbeddableMapping 74 | { 75 | public function mapFor() 76 | { 77 | return Email::class; 78 | } 79 | 80 | public function map(Fluent $builder) 81 | { 82 | $builder->string('address'); 83 | } 84 | } 85 | ``` 86 | 87 | As you can see, embeddable mappings look just as entity mappings, but they extend from a different base class. This will 88 | tell the mapping driver that those classes are not meant to be mapped to a table, but are meant to be used _inside_ 89 | other classes: 90 | 91 | ```php 92 | class ScientistMapping extends EntityMapping 93 | { 94 | public function mapFor() 95 | { 96 | return Scientist::class; 97 | } 98 | 99 | public function map(Fluent $builder) 100 | { 101 | $builder->bigIncrements('id'); 102 | $builder->string('name'); 103 | 104 | $builder->embed(Email::class); 105 | } 106 | } 107 | ``` 108 | 109 | The `Fluent` driver will deduce that you have an `$email` field in your `Scientist` class, and will take care of the 110 | object-columns conversion for you. 111 | 112 | Embeddables are not limited to a single column. They can hold any number of columns, and even hold other embeddables! 113 | 114 | Check [the Doctrine docs](http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/tutorials/embeddables.html) and [our mapping reference](/docs/{{version}}/fluent/reference#embeddables) for more details on embeddables. -------------------------------------------------------------------------------- /fluent/entities.md: -------------------------------------------------------------------------------- 1 | # Entities 2 | 3 | While Laravel maps your `Model` objects to tables using the `ActiveRecord` pattern, Doctrine implements 4 | the `DataMapper` pattern to turn an object's fields into columns in a table. We'll use two patterns to 5 | differentiate objects that can be persisted into a database: Entities and Embeddables. 6 | 7 | ## What is an Entity 8 | 9 | Acording to Eric Evans classification of domain objects, entities are: 10 | 11 | > Objects that have a distinct identity that runs through time and different representations. 12 | > You also hear these called "reference objects". 13 | 14 | With Doctrine, we'll map each `Entity` to a table in our database, and each field we choose to persist 15 | to (at least) one column in it. 16 | 17 | ## Identity 18 | 19 | Entities must have a _distinct identity_, which we usually refer to as ID. IDs can be autogenerated by our 20 | database or generated manually by us, and may be a single incremental integer or any other type of data, as 21 | long as it's unique across the table that holds these Entities. 22 | 23 | ```php 24 | **Internals fun-fact**! 54 | > This mapping driver needs you to implement a single interface: `LaravelDoctrine\Fluent\Mapping`. But one of the methods 55 | > needed in that interface only differs between Entities, MappedSuperClasses and Embeddables, so to simplify its use, 56 | > we made three abstract classes that implement that method and leave it up to you to implement the missing ones. 57 | > 58 | > Those abstract classes are: `LaravelDoctrine\Fluent\EntityMapping`, `LaravelDoctrine\Fluent\EmbeddableMapping` and 59 | > `LaravelDoctrine\Fluent\MappedSuperClassMapping`. 60 | 61 | ## The Mapping class 62 | 63 | We'll need to tell doctrine **which object are we mapping** and **how fields of this object map to columns**. 64 | 65 | ```php 66 | primary()->unsigned()->autoIncrement()` 98 | */ 99 | $builder->increments('id'); 100 | } 101 | } 102 | ``` 103 | 104 | As you can see, we used the `Fluent` builder to map a field to a specific type of column in the database. In our case, 105 | the string 'id' represents the field that doctrine will use inside our entity. The column name will be built from the 106 | field name through a `NamingStrategy`, but we have you covered there! Laravel-doctrine ORM has the `LaravelNamingStrategy` 107 | to keep using snake-cased singular columns and snake-cased plural tables, based on your objects fields and name, 108 | respectively. 109 | 110 | ## Adding the mapping class to the driver 111 | 112 | If you're using Laravel and Doctrine through the `laravel-doctrine/orm` package, then all you need to do here 113 | is add the `ScientistMapping` class reference to your config file: 114 | 115 | ```php 116 | return [ 117 | // ... 118 | 'managers' => [ 119 | 'default' => [ 120 | 'meta' => 'fluent', 121 | 'mappings' => [ 122 | App\Mappings\ScientistMapping::class, 123 | ], 124 | // ... 125 | ]; 126 | ``` 127 | 128 | In standalone mode (and that includes other frameworks by the time of this writing), you should have an instance 129 | of the `FluentDriver` created at boot / kernel time. The `FluentDriver` object has an `addMapping(Mapping $mapping)` method 130 | that will accept an instance of your mapping, or an `addMappings(string[] $mappings)` method that will construct them for 131 | you and add them in bulk. Use any or both at your own convenience! 132 | 133 | ```php 134 | // either... 135 | $driver = new FluentDriver([ 136 | App\Mappings\ScientistMapping::class, 137 | ]); 138 | 139 | // or... 140 | $driver = new FluentDriver; 141 | $driver->addMapping(new ScientistMapping); 142 | 143 | // or... 144 | $driver = new FluentDriver; 145 | $driver->addMappings([ 146 | App\Mappings\ScientistMapping::class, 147 | ]); 148 | 149 | // Then tell Doctrine to use this mapping 150 | $configuration->setMetadataDriverImpl($driver); 151 | ``` 152 | 153 | ## Adding more fields 154 | 155 | We'll make this scientist more interesting: lets give it a name. 156 | 157 | ```php 158 | firstName = $firstName; 179 | $this->lastName = $lastName; 180 | } 181 | } 182 | ``` 183 | 184 | A few things to notice from this example: 185 | 186 | * We added some DocBlocks to indicate the type we expect those fields to have. This is **NOT** mappings or annotations, 187 | it is just a comment. The `Fluent` driver will **NOT** parse it. 188 | * We added a custom `__construct` method. Unlike `Eloquent`, we are in complete control of our objects design, including 189 | its constructor. We'll be calling the constructor on an Entity the moment we create it for the first time, but when 190 | Doctrine fetches an already existing Entity from the database, it won't call its constructor to create it. 191 | 192 | Now, lets map these new fields to the database and see how that looks: 193 | 194 | ```php 195 | increments('id'); 214 | 215 | /** 216 | * Notice how we reference the field here, and not the column. 217 | */ 218 | $builder->string('firstName'); 219 | $builder->string('lastName'); 220 | } 221 | } 222 | ``` 223 | 224 | As you can see, we added two strings to our mapping, one for each field on the Scientist. As in Laravel's migrations, 225 | all fields are `NOT NULL` by default. We've protected ourselves of that scenario with our `__construct`, but maybe we 226 | could add a more strict validation of those fields in the future. 227 | 228 | If we run our schema update command... 229 | ``` 230 | $ php artisan doctrine:schema:update 231 | ``` 232 | 233 | ...and do a quick seed of our first Scientist... 234 | 235 | ```php 236 | We are being intentionally loose on words here. The specific schema will vary between DB engines, but that will be 252 | > taken care of by Doctrine's DBAL layer, so don't worry about it. 253 | 254 | By now you should be able to map your entities to a relational database. In the next chapters you'll learn how to map 255 | relations between them and how to improve your object's design with embedded objects and inheritance mapping. -------------------------------------------------------------------------------- /fluent/extensions.md: -------------------------------------------------------------------------------- 1 | # Extensions 2 | 3 | 4 | ## Gedmo extensions 5 | - [Installation](#installation) 6 | - [Blameable](#blameable) 7 | - [IpTraceable](#iptraceable) 8 | - [Loggable](#loggable) 9 | - [Sluggable](#sluggable) 10 | - [SoftDeletes](#softdeletes) 11 | - [Sortable](#sortable) 12 | - [Timestamps](#timestamps) 13 | - [Translatable](#translatable) 14 | - [Tree](#tree) 15 | - [Uploadable](#uploadable) 16 | 17 | 18 | ### Installation 19 | 20 | To include Gedmo extensions install them: 21 | 22 | ``` 23 | composer require "gedmo/doctrine-extensions=^3.0" 24 | ``` 25 | 26 | #### In Laravel Doctrine 27 | 28 | Require the extensions package in composer: 29 | 30 | ``` 31 | composer require "laravel-doctrine/extensions:1.4.*" 32 | ``` 33 | 34 | Add the Gedmo (Behavioral) extensions service provider in `config/app.php`: 35 | 36 | ```php 37 | LaravelDoctrine\Extensions\GedmoExtensionsServiceProvider::class, 38 | ``` 39 | 40 | #### Standalone usage 41 | 42 | To register all Gedmo extension for Fluent and register all abstract mapping files: 43 | ``` 44 | LaravelDoctrine\Fluent\Extensions\GedmoExtensions::registerAbstract($chain); 45 | ``` 46 | 47 | To register all Gedmo extension for Fluent and register all mapping files: 48 | ``` 49 | LaravelDoctrine\Fluent\Extensions\GedmoExtensions::registerAll($chain); 50 | ``` 51 | 52 | 53 | ### Blameable 54 | 55 | ``` 56 | $builder->manyToOne(User::class, 'createdBy')->blameable()->onCreate(); 57 | $builder->manyToOne(User::class, 'updatedBy')->blameable()->onUpdate(); 58 | $builder->manyToOne(User::class, 'changedBy')->blameable()->onChange(['title', 'body']); 59 | $builder->manyToOne(User::class, 'changedBy')->blameable()->onChange('status', 'Published'); 60 | 61 | $builder->string('createdBy')->blameable()->onCreate(); 62 | $builder->string('updatedBy')->blameable()->onUpdate(); 63 | $builder->string('changedBy')->blameable()->onChange(['title', 'body']); 64 | $builder->string('changedBy')->blameable()->onChange('status', 'Published'); 65 | ``` 66 | 67 | 68 | ### IpTraceable 69 | 70 | ``` 71 | $builder->string('createdFromIp')->ipTraceable()->onCreate(); 72 | $builder->string('updateFromIp')->ipTraceable()->onUpdate(); 73 | $builder->string('changedFromIp')->ipTraceable()->onChange(['title', 'body']); 74 | $builder->string('changedFromIp')->ipTraceable()->onChange('status', 'Published'); 75 | ``` 76 | 77 | 78 | ### Loggable 79 | 80 | ``` 81 | $builder->loggable(); 82 | $builder->loggable(UserLog::class); 83 | 84 | $builder->string('title')->versioned(); 85 | $builder->manyToOne(User::class)->versioned(); 86 | $builder->OneToMany(User::class)->versioned(); 87 | ``` 88 | 89 | 90 | ### Sluggable 91 | 92 | ``` 93 | $builder->string('slug')->sluggable('title'); 94 | $builder->string('slug')->sluggable(['title', 'code']); 95 | 96 | $builder->string('slug')->sluggable('title') 97 | ->style('default') 98 | ->dateFormat('Y-m-d H:i') 99 | ->updatable(true) 100 | ->unique(true) 101 | ->uniqueBase('base') 102 | ->separator('-') 103 | ->prefix('prefix-') 104 | ->suffix('-suffix'); 105 | ``` 106 | 107 | 108 | ### SoftDeletes 109 | 110 | ``` 111 | $builder->softDelete(); 112 | $builder->softDelete('deletedAt')->timeAware(); 113 | $builder->dateTime('deletedAt')->nullable()->softDelete(); 114 | ``` 115 | 116 | 117 | ### Sortable 118 | 119 | ``` 120 | $builder->integer('position')->sortablePosition(); 121 | $builder->string('group')->sortableGroup(); 122 | $builder->oneToMany(Category::class)->sortableGroup(); 123 | $builder->manyToMany(Category::class)->sortableGroup(); 124 | ``` 125 | 126 | 127 | ### Timestamps 128 | 129 | ``` 130 | $builder->timestamps(); // Creates both createdAt and updatedAt 131 | $builder->dateTime('createdAt')->timestampable()->onCreate(); 132 | $builder->dateTime('updatedAt')->timestampable()->onUpdate(); 133 | $builder->dateTime('changedAt')->timestampable()->onChange(['title', 'body']); 134 | $builder->dateTime('changedAt')->timestampable()->onChange('status', 'Published'); 135 | ``` 136 | 137 | 138 | ### Translatable 139 | 140 | ``` 141 | $builder->string('title')->translatable(); 142 | $builder->string('locale')->locale(); 143 | $builder->translationClass(PageTranslation::class); 144 | ``` 145 | 146 | 147 | ### Tree 148 | 149 | ``` 150 | $builder->nestedSet(); // Creates a default left, right, level and root 151 | $builder->nestedSet()->left('lft')->right('rgt'); 152 | 153 | $builder->integer('left')->treeLeft(); 154 | $builder->integer('right')->treeRight(); 155 | $builder->integer('level')->treeLevel(); 156 | $builder->integer('root')->treeRoot(); 157 | ``` 158 | 159 | 160 | ### Uploadable 161 | 162 | ``` 163 | $builder->uploadable(); 164 | $builder->uploadable() 165 | ->allowOverwrite() 166 | ->appendNumber() 167 | ->path('somePath') 168 | ->pathMethod('getPath') 169 | ->callback('afterFileUpload') 170 | ->alphanumericFilename() 171 | ->sha1Filename() 172 | ->customFilename(FileNameGenerator::class) 173 | ->maxSize(10000) 174 | ->allow(['png', 'jgp']) 175 | ->disallow(['exe']); 176 | 177 | $builder->string('filePath')->asFilePath(); 178 | $builder->string('fileName')->asFileName(); 179 | $builder->string('fileSize')->asFileSize(); 180 | $builder->string('mineType')->asFileMimeType(); 181 | ``` 182 | -------------------------------------------------------------------------------- /fluent/first-mapping.md: -------------------------------------------------------------------------------- 1 | # Your first fluent mapping file 2 | 3 | Mapping files in the Fluent driver are PHP classes. Each mapping file will be associated with either an `Entity`, 4 | an `Embeddable` or a `MappedSuperClass`. As each of these mappings behave differently for Doctrine, we have a 5 | specific `Mapping` abstract class to extend from: 6 | 7 | - `LaravelDoctrine\Fluent\EntityMapping` for Entities 8 | - `LaravelDoctrine\Fluent\EmbeddableMapping` for Embeddables 9 | - `LaravelDoctrine\Fluent\MappedSuperClassMapping` for MappedSuperClasses 10 | 11 | ## Mapping an entity 12 | 13 | Let's say we have a `Scientist` entity that we want to persist to a database. 14 | 15 | ```php 16 | increments('id'); 77 | 78 | // Both strings will be varchars 79 | $builder->string('firstName')->nullable(); 80 | $builder->string('lastName')->nullable(); 81 | 82 | // This will map an association with Theory as one-to-many 83 | $builder->hasMany(Theory::class, 'theories'); 84 | } 85 | } 86 | ``` 87 | 88 | As you can see, the syntax used in the `Fluent` builder is similar to what you'd use in 89 | Laravel migrations. The `Builder` object is fully documented in code and with all concrete 90 | methods that will hint on every modern IDE. 91 | -------------------------------------------------------------------------------- /fluent/index.md: -------------------------------------------------------------------------------- 1 | - Prologue 2 | - [Introduction](/docs/{{version}}/fluent/introduction) 3 | - Setup 4 | - [Laravel](/docs/{{version}}/fluent/laravel-installation) 5 | - [Standalone](/docs/{{version}}/fluent/standalone-installation) 6 | - Quick start 7 | - [Your first fluent mapping file](/docs/{{version}}/fluent/first-mapping) 8 | - Mappers 9 | - [Entities](/docs/{{version}}/fluent/entities) 10 | - [Embeddables](/docs/{{version}}/fluent/embeddables) 11 | - [Mapped Super Class](/docs/{{version}}/fluent/mapped-superclass) 12 | - [Mapping Reference](/docs/{{version}}/fluent/reference) 13 | - [Table](/docs/{{version}}/fluent/reference#table) 14 | - [Columns](/docs/{{version}}/fluent/reference#columns) 15 | - [Relations](/docs/{{version}}/fluent/reference#relations) 16 | - [Embeddables](/docs/{{version}}/fluent/reference#embeddables) 17 | - [Inheritance mapping](/docs/{{version}}/fluent/reference#inheritance) 18 | - [Lifecycle callbacks](/docs/{{version}}/fluent/reference#lifecycle-callbacks) 19 | - [Primary keys](/docs/{{version}}/fluent/reference#primary-keys) 20 | - [Indexes](/docs/{{version}}/fluent/reference#indexes) 21 | - [Unique Constraints](/docs/{{version}}/fluent/reference#uniques) 22 | - [Mapping overrides](/docs/{{version}}/fluent/reference#overrides) 23 | - [Extending with macros](/docs/{{version}}/fluent/reference#macros) 24 | - [Advanced Doctrine Entity configuration](/docs/{{version}}/fluent/reference#advanced) 25 | 26 | - [Extensions](/docs/{{version}}/fluent/extensions) 27 | - [Blameable](/docs/{{version}}/fluent/extensions#blameable) 28 | - [IpTraceable](/docs/{{version}}/fluent/extensions#iptraceable) 29 | - [Loggable](/docs/{{version}}/fluent/extensions#loggable) 30 | - [Sluggable](/docs/{{version}}/fluent/extensions#sluggable) 31 | - [SoftDeletes](/docs/{{version}}/fluent/extensions#softdeletes) 32 | - [Sortable](/docs/{{version}}/fluent/extensions#sortable) 33 | - [Timestamps](/docs/{{version}}/fluent/extensions#timestamps) 34 | - [Translatable](/docs/{{version}}/fluent/extensions#translatable) 35 | - [Tree](/docs/{{version}}/fluent/extensions#tree) 36 | - [Uploadable](/docs/{{version}}/fluent/extensions#uploadable) 37 | -------------------------------------------------------------------------------- /fluent/introduction.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | #### A fluent mapping driver for Doctrine2 4 | 5 | This mapping driver allows you to manage your mappings in an Object Oriented approach, separating your entities 6 | from your mapping configuration without the need for configuration files like XML or YAML. 7 | This is done by implementing the `LaravelDoctrine\Fluent\Mapping` interface, or extending the abstract classes 8 | provided with this package for an easier use: 9 | `LaravelDoctrine\Fluent\EntityMapping`, `LaravelDoctrine\Fluent\EmbeddableMapping` or `MappedSuperClassMapping`. 10 | 11 | 12 | This package provides a fluent Builder over Doctrine's `ClassMetadataBuilder`, aimed at easing usage of 13 | Doctrine's mapping concepts in Laravel. The builder adds syntax sugar and implements the same grammar that you 14 | might use in Laravel migrations. 15 | 16 | ``` 17 | class ScientistMapping extends EntityMapping 18 | { 19 | /** 20 | * Returns the fully qualified name of the class that this mapper maps. 21 | * 22 | * @return string 23 | */ 24 | public function mapFor() 25 | { 26 | return Scientist::class; 27 | } 28 | 29 | /** 30 | * Load the object's metadata through the Metadata Builder object. 31 | * 32 | * @param Fluent $builder 33 | */ 34 | public function map(Fluent $builder) 35 | { 36 | $builder->increments('id'); 37 | $builder->embed(Name::class, 'name'); 38 | 39 | $builder->hasMany(Theory::class, 'theories')->ownedBy('scientist'); 40 | } 41 | } 42 | ``` 43 | -------------------------------------------------------------------------------- /fluent/laravel-installation.md: -------------------------------------------------------------------------------- 1 | # Installation in Laravel 6+ 2 | 3 | The Fluent driver can be easily integrated to a Laravel project that already uses Doctrine 4 | through the [laravel-doctrine/orm](https://github.com/laravel-doctrine/orm) package. 5 | 6 | ``` 7 | composer require laravel-doctrine/fluent 8 | ``` 9 | 10 | To start using Fluent, edit your `config/doctrine.php` file and choose the `fluent` MetaData 11 | driver: 12 | 13 | ```php 14 | return [ 15 | // ... 16 | 'managers' => [ 17 | 'default' => [ 18 | 'meta' => 'fluent', 19 | 'mappings' => [ 20 | // Add your mappings here 21 | App\Mappings\UserMapping::class, 22 | App\Mappings\RoleMapping::class, 23 | // etc... 24 | ], 25 | // ... 26 | ]; 27 | ``` 28 | -------------------------------------------------------------------------------- /fluent/mapped-superclass.md: -------------------------------------------------------------------------------- 1 | # Mapped superclasses 2 | 3 | When modeling our entities, we may sometimes find the need to create a hierarchy or family of entities, and do so by 4 | using inheritance in our PHP classes. If we do so, Doctrine offers us several ways to map those classes to our database. 5 | Mapped superclass is one of them. 6 | 7 | ## What is a mapped superclass 8 | 9 | According to [the Doctrine docs](http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/inheritance-mapping.html#mapped-superclasses), 10 | mapped superclasses allow us to share common state between our entities, without it being an entity itself. This means 11 | the parent class will not behave as an entity, and each of our entities will have its own table, containing its state 12 | and, by extension, its parent's state. 13 | 14 | > DISCLAIMER: No animals were hurt while modeling these examples! 15 | 16 | ```php 17 | class TestSubject 18 | { 19 | /** @var int */ 20 | protected $id; 21 | 22 | /** @var Laboratory */ 23 | protected $laboratory; 24 | 25 | /** @var HealthStatus */ 26 | protected $healthStatus; 27 | } 28 | 29 | class LabRat extends TestSubject 30 | { 31 | /** @var string */ 32 | private $codeName; 33 | } 34 | 35 | class Human extends TestSubject 36 | { 37 | /** @var string */ 38 | private $firstName; 39 | 40 | /** @var string */ 41 | private $lastName; 42 | } 43 | ``` 44 | 45 | While both `TestSubjects` share common state, we don't want to mix them up. So, we'll map them as separate entities and 46 | map the common state as a **Mapped Superclass**: 47 | 48 | ```php 49 | class TestSubjectMapping extends MappedSuperClassMapping 50 | { 51 | public function mapFor() 52 | { 53 | return TestSubject::class; 54 | } 55 | 56 | public function map(Fluent $builder) 57 | { 58 | $builder->belongsTo(Laboratory::class); 59 | $builder->embed(HealthStatus::class); 60 | } 61 | } 62 | ``` 63 | 64 | Then, each subclass will have an independent mapping and an independent table: 65 | 66 | ```php 67 | class LabRatMapping extends EntityMapping 68 | { 69 | public function mapFor() 70 | { 71 | return LabRat::class; 72 | } 73 | 74 | public function map(Fluent $builder) 75 | { 76 | $builder->bigIncrements('id'); 77 | 78 | $builder->string('codeName')->unique(); 79 | } 80 | } 81 | 82 | class HumanMapping extends EntityMapping 83 | { 84 | public function mapFor() 85 | { 86 | return Human::class; 87 | } 88 | 89 | public function map(Fluent $builder) 90 | { 91 | $builder->bigIncrements('id'); 92 | $builder->string('firstName'); 93 | $builder->string('lastName'); 94 | } 95 | } 96 | ``` 97 | 98 | The previous mapping configuration would result in the following database schema: 99 | 100 | | Entity | Table | Columns | 101 | |----------|------------|---------------------------------------------------------------------| 102 | | `LabRat` | `lab_rats` | `id`, `laboratory_id`, `health_status_*`, `code_name UNIQUE` | 103 | | `Human` | `humans` | `id`, `laboratory_id`, `health_status_*`, `first_name`, `last_name` | 104 | 105 | Check the [complete mapping reference](/docs/{{version}}/fluent/reference) for more information on inheritance mapping 106 | and other reuse strategies. -------------------------------------------------------------------------------- /fluent/standalone-installation.md: -------------------------------------------------------------------------------- 1 | # Standalone installation 2 | 3 | The fluent driver can be used in any project using Doctrine 2. Simply configure your `EntityManager` with the 4 | `FluentDriver` as the metadata driver: 5 | 6 | ``` 7 | composer require laravel-doctrine/fluent 8 | ``` 9 | 10 | ```php 11 | $fluent = new FluentDriver([ 12 | MyApp\Mappings\ScientistMapping::class, 13 | MyApp\Mappings\TheoryMapping::class, 14 | MyApp\Mappings\UniversityMapping::class, 15 | ]); 16 | 17 | $config = new Doctrine\ORM\Configuration(); 18 | $config->setMetadataDriverImpl($fluent); 19 | 20 | $entityManager = EntityManager::create($db, $config); 21 | ``` 22 | -------------------------------------------------------------------------------- /migrations/builder.md: -------------------------------------------------------------------------------- 1 | # Schema Builder 2 | 3 | The Schema Builder is merely a decorator for the DBAL Schema Builder. It makes the process of building migrations similar to Laravel. 4 | 5 | ### Creating a new table 6 | 7 | ``` 8 | use LaravelDoctrine\Migrations\Schema\Table; 9 | use LaravelDoctrine\Migrations\Schema\Builder; 10 | 11 | (new Builder($schema))->create('users', function(Table $table) { 12 | $table->increments('id'); 13 | $table->timestamps(); 14 | }); 15 | ``` 16 | 17 | ### Editing an existing table 18 | 19 | ``` 20 | use LaravelDoctrine\Migrations\Schema\Table; 21 | use LaravelDoctrine\Migrations\Schema\Builder; 22 | 23 | (new Builder($schema))->table('users', function(Table $table) { 24 | $table->string('name'); 25 | }); 26 | ``` 27 | 28 | ### Available Column Types 29 | 30 | Of course, the schema builder contains a variety of column types that you may use when building your tables: 31 | 32 | Command | Description 33 | ------------- | ------------- 34 | `$table->bigIncrements('id');` | Incrementing ID (primary key) using a "UNSIGNED BIG INTEGER" equivalent. 35 | `$table->bigInteger('votes');` | BIGINT equivalent for the database. 36 | `$table->binary('data');` | BLOB equivalent for the database. 37 | `$table->boolean('confirmed');` | BOOLEAN equivalent for the database. 38 | `$table->date('created_at');` | DATE equivalent for the database. 39 | `$table->dateTime('created_at');` | DATETIME equivalent for the database. 40 | `$table->decimal('amount', 5, 2);` | DECIMAL equivalent with a precision and scale. 41 | `$table->float('amount');` | FLOAT equivalent for the database. 42 | `$table->increments('id');` | Incrementing ID (primary key) using a "UNSIGNED INTEGER" equivalent. 43 | `$table->integer('votes');` | INTEGER equivalent for the database. 44 | `$table->json('options');` | JSON equivalent for the database. 45 | `$table->nullableTimestamps();` | Same as `timestamps()`, except allows NULLs. 46 | `$table->rememberToken();` | Adds `remember_token` as VARCHAR(100) NULL. 47 | `$table->smallInteger('votes');` | SMALLINT equivalent for the database. 48 | `$table->softDeletes();` | Adds `deleted_at` column for soft deletes. 49 | `$table->string('email');` | VARCHAR equivalent column. 50 | `$table->string('name', 100);` | VARCHAR equivalent with a length. 51 | `$table->text('description');` | TEXT equivalent for the database. 52 | `$table->time('sunrise');` | TIME equivalent for the database. 53 | `$table->timestamp('added_on');` | TIMESTAMP equivalent for the database. 54 | `$table->timestamps();` | Adds `created_at` and `updated_at` columns. 55 | 56 | ### Checking For Table / Column Existence 57 | 58 | You may easily check for the existence of a table or column using the `hasTable` and `hasColumn` methods: 59 | 60 | ``` 61 | $builder = (new Builder($schema); 62 | 63 | if ($builder->hasTable('users')) { 64 | // 65 | } 66 | 67 | if ($builder->hasColumn('users', 'email')) { 68 | // 69 | } 70 | ``` 71 | 72 | ### Renaming / Dropping Tables 73 | 74 | To rename an existing database table, use the `rename` method: 75 | 76 | ``` 77 | (new Builder($schema))->rename($from, $to); 78 | ``` 79 | 80 | To drop an existing table, you may use the `drop` or `dropIfExists` methods: 81 | 82 | ``` 83 | (new Builder($schema))->drop('users'); 84 | 85 | (new Builder($schema))->dropIfExists('users'); 86 | ``` 87 | 88 | ### Creating Indexes 89 | 90 | The Schema Builder can create three types of indexes. To create a primary key, you can simply use any one of the 91 | auto-incrementing methods (`bigIncrements` `increments` `smallIncrements`) and it will automatically 92 | create an auto-incrementing unsigned integer column of the specified size and set it as the primary key. 93 | 94 | ``` 95 | $table->bigIncrements('id'); 96 | ``` 97 | 98 | To specify a primary key which does not auto-increment, simply call the `primary` method. For example, consider a weak 99 | entity that represents one of several images of a product and is identified uniquely by the product_id foreign key and the 100 | image ordinal: 101 | 102 | ``` 103 | $table->primary(['product_id', 'position']); 104 | ``` 105 | 106 | To create an index with a unique constraint, call the `unique` 107 | method: 108 | 109 | ``` 110 | $table->unique('email'); 111 | ``` 112 | 113 | You can pass an array of column names to any of these methods: 114 | 115 | ``` 116 | $table->index(['inventory_id', 'image_number']); 117 | ``` 118 | 119 | #### Available Index Types 120 | 121 | Command | Description 122 | ------------- | ------------- 123 | `$table->primary('id'); ` | Add a primary key. 124 | `$table->primary(['last', 'first', 'zip']); ` | Add a composite keys. 125 | `$table->unique('email'); ` | Add a unique (candidate) key. 126 | `$table->index('country'); ` | Add a basic index. 127 | -------------------------------------------------------------------------------- /migrations/configuration.md: -------------------------------------------------------------------------------- 1 | # Configuration 2 | 3 | `config/migrations.php` holds a couple of configuration settings. 4 | 5 | ## Migrations Table 6 | 7 | This database table keeps track of all the migrations that have already run for your application. Using this information, we can determine which of the migrations on disk haven't actually been run in the database. 8 | 9 | __Default__: migrations 10 | 11 | ## Migration Directory 12 | 13 | This directory is where all migrations will be stored 14 | 15 | __Default__: database/migrations 16 | 17 | ## Migration Namespace 18 | 19 | This namespace will be used on all migrations 20 | 21 | __Default__: Database\\Migrations 22 | 23 | ## Migration Schema 24 | 25 | Tables which are filtered by Regular Expression. You optionally exclude or limit to certain tables. The default will allow all tables. 26 | 27 | __Default__: '/^(?).*$/' 28 | 29 | 30 | ## Migration Version Column Length 31 | 32 | The length for the version column in the migrations table. By default migrations have are named like `Version20150914223731`. If you are customizing this name then you will need to expand the column length. 33 | 34 | __Default__: '14' 35 | -------------------------------------------------------------------------------- /migrations/diff.md: -------------------------------------------------------------------------------- 1 | # From metadata to migration 2 | 3 | ```php 4 | $ php artisan doctrine:migrations:diff 5 | ``` 6 | 7 | The command generates a migration by comparing project current database to mapping information. 8 | Doctrine provides this command to generate migration classes by changing entity mappings instead of manually adding modifications to migration class. 9 | 10 | Lets add id and name columns to a User entity. 11 | 12 | ```php 13 | addSql('CREATE TABLE users (id INT AUTO_INCREMENT NOT NULL, name VARCHAR(255) NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB'); 51 | } 52 | 53 | /** 54 | * @param Schema $schema 55 | */ 56 | public function down(Schema $schema): void 57 | { 58 | $this->addSql('DROP TABLE users'); 59 | } 60 | } 61 | ``` 62 | 63 | > Note: If you are using Postgres, there is a known issue with doctrine/dbal which causes the diff tool to always detect a change, and add an extra line to the down function. https://github.com/doctrine/dbal/issues/1110 64 | -------------------------------------------------------------------------------- /migrations/execute.md: -------------------------------------------------------------------------------- 1 | # Execute migration 2 | 3 | ``` 4 | $ php artisan doctrine:migrations:execute [version] [--up] [--down] 5 | ``` 6 | 7 | Executes a single migration version up or down manually. 8 | 9 | ``` 10 | $ php artisan doctrine:migrations:execute 20150914223731 --up 11 | 12 | > Migrated: 20150914223731 13 | ``` 14 | 15 | 16 | ``` 17 | $ php artisan doctrine:migrations:execute 20150914223731 --down 18 | 19 | > Rolled back: 20150914223731 20 | ``` 21 | -------------------------------------------------------------------------------- /migrations/generate.md: -------------------------------------------------------------------------------- 1 | # Generate Migration 2 | 3 | ``` 4 | $ php artisan doctrine:migrations:generate [--create=table_name] [--table=table_name] 5 | ``` 6 | 7 | The new migration will be placed in your database/migrations directory. Each migration file name contains a timestamp as version which allows Doctrine to determine the order of the migrations. 8 | 9 | The `--table` and `--create` options may also be used to indicate the name of the table and whether the migration will be creating a new table. These options simply pre-fill the generated migration stub file with the specified table: 10 | 11 | ```` 12 | php artisan doctrine:migrations:generate --table=users 13 | 14 | php artisan doctrine:migrations:generate --create=users 15 | ``` 16 | 17 | If you would like to specify another output path for the generated migration, you can change the setting in `config/migrations`. 18 | 19 | The command generates blank migration class in `database/migrations` with latest version. 20 | 21 | ```php 22 | addSql('CREATE TABLE addresses (id INT NOT NULL, street VARCHAR(255) NOT NULL, PRIMARY KEY(id)) ENGINE = InnoDB'); 52 | } 53 | ``` 54 | 55 | ### Schema Builder 56 | 57 | Alternatively you can use a Laravel-like Schema Builder. The previous example will now look like this: 58 | 59 | ```php 60 | 61 | use LaravelDoctrine\Migrations\Schema\Table; 62 | use LaravelDoctrine\Migrations\Schema\Builder; 63 | 64 | public function up(Schema $schema): void 65 | { 66 | (new Builder($schema))->create('addresses', function(Table $table) { 67 | $table->increments('id'); 68 | $table->string('street'); 69 | }); 70 | } 71 | ``` 72 | -------------------------------------------------------------------------------- /migrations/index.md: -------------------------------------------------------------------------------- 1 | - Prologue 2 | - [Introduction](/docs/{{version}}/migrations/introduction) 3 | - [Upgrade Guide](/docs/{{version}}/migrations/upgrade) 4 | - Setup 5 | - [Laravel](/docs/{{version}}/migrations/installation) 6 | - [Lumen](/docs/{{version}}/migrations/lumen) 7 | - [Configuration](/docs/{{version}}/migrations/configuration) 8 | - Console 9 | - [Generate migration](/docs/{{version}}/migrations/generate) 10 | - [From metadata to migration](/docs/{{version}}/migrations/diff) 11 | - [Running migrations](/docs/{{version}}/migrations/migrate) 12 | - [Execute a single migration](/docs/{{version}}/migrations/execute) 13 | - [Rollback migration](/docs/{{version}}/migrations/rollback) 14 | - [Get latest version](/docs/{{version}}/migrations/latest) 15 | - [Add/delete version](/docs/{{version}}/migrations/version) 16 | - [Check migration status](/docs/{{version}}/migrations/status) 17 | - [Reset database](/docs/{{version}}/migrations/reset) 18 | - [Re-run migrations](/docs/{{version}}/migrations/refresh) 19 | - Schema 20 | - [Schema builder](/docs/{{version}}/migrations/builder) 21 | -------------------------------------------------------------------------------- /migrations/installation.md: -------------------------------------------------------------------------------- 1 | # Installation in Laravel 6+ 2 | 3 | Install this package with composer: 4 | 5 | ``` 6 | composer require laravel-doctrine/migrations 7 | ``` 8 | 9 | After updating composer, add the ServiceProvider to the providers array in `config/app.php` 10 | 11 | ```php 12 | LaravelDoctrine\Migrations\MigrationsServiceProvider::class, 13 | ``` 14 | 15 | To publish the config use: 16 | 17 | ```php 18 | php artisan vendor:publish --tag="config" --provider="LaravelDoctrine\Migrations\MigrationsServiceProvider" 19 | ``` 20 | -------------------------------------------------------------------------------- /migrations/introduction.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | The Doctrine Migrations offer additional functionality on top of the database abstraction layer (DBAL) for versioning your database schema and easily deploying changes to it. It is a very easy to use and powerful tool. 4 | 5 | This package provides: 6 | 7 | * Generate new migrations from metadata information 8 | * Versioned migrations 9 | * A Laravel-like Schema Builder 10 | -------------------------------------------------------------------------------- /migrations/latest.md: -------------------------------------------------------------------------------- 1 | # Get latest version 2 | 3 | Running `doctrine:migrations:latest` outputs the latest version number: 4 | 5 | ``` 6 | $ php artisan doctrine:migrations:latest 7 | 8 | > Latest version: 20150914223731 9 | ``` 10 | -------------------------------------------------------------------------------- /migrations/lumen.md: -------------------------------------------------------------------------------- 1 | # Installation in Lumen 6+ 2 | 3 | To set up Laravel Doctrine ACL in Lumen, we need some additional steps. 4 | 5 | Install this package with composer: 6 | 7 | ``` 8 | composer require laravel-doctrine/migrations 9 | ``` 10 | 11 | After updating composer, open `bootstrap/app.php` and register the Service Provider after `LaravelDoctrine\ORM\DoctrineServiceProvider::class` 12 | 13 | ```php 14 | $app->register(LaravelDoctrine\Migrations\MigrationsServiceProvider::class); 15 | ``` 16 | -------------------------------------------------------------------------------- /migrations/migrate.md: -------------------------------------------------------------------------------- 1 | # Migrate 2 | 3 | ``` 4 | $ php artisan doctrine:migrations:migrate [version=latest] [--dry-run] [--write-sql] [--query-time] 5 | ``` 6 | 7 | The command executes a migration to a specified version or the latest available version. 8 | 9 | ``` 10 | Migrated: 20150913141214 11 | Migrated: 20150913141215 12 | Migrated: 20150913141216 13 | ``` 14 | -------------------------------------------------------------------------------- /migrations/refresh.md: -------------------------------------------------------------------------------- 1 | # Refresh the database 2 | 3 | The migrate:refresh command will first roll back all of your database migrations, and then run the migrate command. This command effectively re-creates your entire database. 4 | 5 | ``` 6 | $ php artisan doctrine:migrations:refresh 7 | ``` 8 | -------------------------------------------------------------------------------- /migrations/reset.md: -------------------------------------------------------------------------------- 1 | # Reset the database 2 | 3 | The doctrine:migrations:reset command will roll back all of your application's migrations: 4 | 5 | ``` 6 | $ php artisan doctrine:migrations:reset 7 | ``` 8 | -------------------------------------------------------------------------------- /migrations/rollback.md: -------------------------------------------------------------------------------- 1 | # Rollback migration 2 | 3 | ``` 4 | $ php artisan doctrine:migrations:rollback [version?] 5 | ``` 6 | 7 | To rollback the latest migration "operation", you may use the rollback command. 8 | Note that this rolls back the previous "version" or a specific version 9 | 10 | ``` 11 | $ php artisan doctrine:migrations:rollback 12 | 13 | > Rolled back: 20150914223731 14 | ``` 15 | 16 | ``` 17 | $ php artisan doctrine:migrations:rollback 20150914223731 18 | 19 | > Rolled back: 20150914223731 20 | ``` 21 | -------------------------------------------------------------------------------- /migrations/status.md: -------------------------------------------------------------------------------- 1 | # Migration Status 2 | 3 | ``` 4 | $ php artisan doctrine:migrations:status [--show-versions] [--connection] 5 | ``` 6 | 7 | The command allows to View the status of a set of migrations: 8 | 9 | ``` 10 | == Configuration 11 | 12 | >> Database Driver: pdo_mysql 13 | >> Database Name: testdb 14 | >> Configuration Source: ../database/migrations 15 | >> Version Table Name: migrations 16 | >> Migrations Namespace: Database\Migrations 17 | >> Current Version: 2015-09-13 14:12:14 (20150913141214) 18 | >> Latest Version: 2015-09-13 14:12:14 (20150913141214) 19 | >> Executed Migrations: 0 20 | >> Available Migrations: 1 21 | >> New Migrations: 1 22 | 23 | == Migration Versions 24 | 25 | >> 2015-09-13 14:12:14 (20150913141214) not migrated 26 | ``` 27 | -------------------------------------------------------------------------------- /migrations/upgrade.md: -------------------------------------------------------------------------------- 1 | # Upgrade Guide 2 | -------------------------------------------------------------------------------- /migrations/version.md: -------------------------------------------------------------------------------- 1 | # Add or Delete versions 2 | 3 | ```php 4 | $ php artisan doctrine:migrations:version [version] [--add] [--delete] 5 | ``` 6 | 7 | Sometimes you may need to manually change something in the database table which manages the versions for some migrations. For this you can use the version task. You can easily add a version like this: 8 | 9 | ``` 10 | $ php artisan doctrine:migrations:version YYYYMMDDHHMMSS --add 11 | ``` 12 | 13 | Or you can delete that version: 14 | 15 | ``` 16 | $ php artisan doctrine:migrations:version YYYYMMDDHHMMSS --delete 17 | ``` 18 | 19 | The command does not execute any migrations code, it simply adds the specified version to the database. 20 | -------------------------------------------------------------------------------- /orm/auth.md: -------------------------------------------------------------------------------- 1 | # Authentication 2 | 3 | ## Configuration 4 | 5 | ### Implementing Authenticatable 6 | 7 | First you must extend Laravel's authentication contract on the entity you wish to use with authentication. 8 | 9 | ``` 10 | class User implements \Illuminate\Contracts\Auth\Authenticatable 11 | { 12 | 13 | /** 14 | * @ORM\Id 15 | * @ORM\GeneratedValue 16 | * @ORM\Column(type="integer") 17 | */ 18 | protected $id; 19 | 20 | public function getAuthIdentifierName() 21 | { 22 | return 'id'; 23 | } 24 | 25 | public function getAuthIdentifier() 26 | { 27 | return $this->id; 28 | } 29 | 30 | public function getPassword() 31 | { 32 | return $this->password; 33 | } 34 | } 35 | ``` 36 | 37 | You may also use the provided trait `LaravelDoctrine\ORM\Auth\Authenticatable` in your entity and override where necessary. 38 | 39 | 40 | ``` 41 | class User implements \Illuminate\Contracts\Auth\Authenticatable 42 | { 43 | use \LaravelDoctrine\ORM\Auth\Authenticatable; 44 | 45 | /** 46 | * @ORM\Id 47 | * @ORM\GeneratedValue 48 | * @ORM\Column(type="integer") 49 | */ 50 | protected $userId; 51 | 52 | public function getAuthIdentifierName() 53 | { 54 | return 'userId'; 55 | } 56 | } 57 | ``` 58 | 59 | ### Configuring Laravel 60 | 61 | Edit Laravel's Auth configuration (`/config/auth.php`) to set up use with Doctrine. 62 | 63 | ``` 64 | return [ 65 | 66 | /* 67 | |-------------------------------------------------------------------------- 68 | | Default Authentication Driver 69 | |-------------------------------------------------------------------------- 70 | | 71 | | This option controls the authentication driver that will be utilized. 72 | | This driver manages the retrieval and authentication of the users 73 | | attempting to get access to protected areas of your application. 74 | | 75 | | 76 | */ 77 | 78 | 'driver' => 'doctrine', 79 | 80 | /* 81 | |-------------------------------------------------------------------------- 82 | | Authentication Model 83 | |-------------------------------------------------------------------------- 84 | | 85 | | This is the entity that has implemented Authenticatable 86 | | 87 | */ 88 | 89 | 'model' => App\Entities\User::class, 90 | 91 | 92 | /* 93 | |-------------------------------------------------------------------------- 94 | | Password Reset Settings 95 | |-------------------------------------------------------------------------- 96 | | 97 | | Here you may set the options for resetting passwords including the view 98 | | that is your password reset e-mail. You can also set the name of the 99 | | table that maintains all of the reset tokens for your application. 100 | | 101 | | The expire time is the number of minutes that the reset token should be 102 | | considered valid. This security feature keeps tokens short-lived so 103 | | they have less time to be guessed. You may change this as needed. 104 | | 105 | */ 106 | 107 | 'password' => [ 108 | 'email' => 'emails.password', 109 | 'table' => 'password_resets', 110 | 'expire' => 60, 111 | ], 112 | 113 | ]; 114 | ``` 115 | 116 | ## Password hashing 117 | Password hashing must be handled by your application; Laravel's authentication 118 | and LaravelDoctrine will treat passwords as nothing more than strings. We would 119 | recommend decoupling the operation of hashing of the password (and any other 120 | procedures, like validating strength) from its storage by implementing a separate 121 | service to handle any password-related actions. 122 | 123 | ``` 124 | use \Illuminate\Contracts\Hashing\Hasher; 125 | 126 | class PasswordService 127 | { 128 | private $hasher; 129 | private $passwordStrengthValidator; 130 | 131 | /** 132 | * @param Hasher $hasher 133 | * @param MyPasswordStrengthValidator $passwordStrength 134 | */ 135 | public function __construct( 136 | Hasher $hasher, 137 | MyPasswordStrengthValidator $passwordStrength 138 | ) { 139 | $this->hasher = $hasher; 140 | $this->passwordStrengthValidator = $passwordStrength 141 | } 142 | 143 | /** 144 | * Validate and change the given users password 145 | * 146 | * @param User $user 147 | * @param string $password 148 | * @throws PasswordTooWeakException 149 | * @return void 150 | */ 151 | public function changePassword(User $user, $password) 152 | { 153 | if ($this->passwordStrengthValidator->isStrongEnough($password)) { 154 | $user->setPassword($this->hasher->make($password)) 155 | } else { 156 | throw new PasswordTooWeakException(); 157 | } 158 | } 159 | } 160 | ``` 161 | 162 | ## Using Authentication 163 | 164 | Authentication usage is covered by [Laravel's Documentation.](https://laravel.com/docs/authentication) 165 | -------------------------------------------------------------------------------- /orm/caching.md: -------------------------------------------------------------------------------- 1 | # Caching 2 | 3 | This package supports these caching systems out of the box: 4 | 5 | * redis 6 | * memcached 7 | * file 8 | * apc 9 | * array 10 | 11 | ## Extending or Adding Cache Drivers 12 | 13 | Drivers can be replaced or added using `LaravelDoctrine\ORM\Configuration\Cache\CacheManager`. The return should implement `Doctrine\Common\Cache\Cache` or extend `Doctrine\Common\Cache\CacheProvider` 14 | 15 | ```php 16 | public function register() 17 | { 18 | $this->app->resolving(CacheManager::class, function (CacheManager $cache){ 19 | $cache->extend('memcache', function(array $settings, Application $app) { 20 | $memcache = new \Memcache; 21 | return new MemcacheCache($memcache); 22 | }); 23 | }); 24 | } 25 | ``` 26 | -------------------------------------------------------------------------------- /orm/config-file.md: -------------------------------------------------------------------------------- 1 | # Configuration File Overview 2 | 3 | - [Sample Configuration](#sample-configuration) 4 | - [Entity Manager](#entity-manager) 5 | - [Namespace Alias](#entity-manager-namespace-alias) 6 | - [Extensions](#extensions) 7 | - [Custom Types](#custom-types) 8 | - [Custom Functions](#custom-functions) 9 | - [Custom Hydration Modes](#custom-hydration-modes) 10 | - [Logger](#logger) 11 | - [Cache](#cache) 12 | - [Gedmo Extensions](#gedmo) 13 | 14 | This page provides a quick overview of all of the options provided in `doctrine.php`, the configuration file for Laravel Doctrine. 15 | 16 | ### Sample Configuration 17 | 18 | ```php 19 | Warning: Proxy auto generation should only be enabled in dev! 39 | | 40 | */ 41 | 'managers' => [ 42 | 'default' => [ 43 | 'dev' => env('APP_DEBUG'), 44 | 'meta' => env('DOCTRINE_METADATA', 'annotations'), 45 | 'connection' => env('DB_CONNECTION', 'mysql'), 46 | 'namespaces' => [ 47 | 'App' 48 | ], 49 | 'paths' => [ 50 | base_path('app') 51 | ], 52 | 'repository' => Doctrine\ORM\EntityRepository::class, 53 | 'proxies' => [ 54 | 'namespace' => false, 55 | 'path' => storage_path('proxies'), 56 | 'auto_generate' => env('DOCTRINE_PROXY_AUTOGENERATE', false) 57 | ], 58 | /* 59 | |-------------------------------------------------------------------------- 60 | | Doctrine events 61 | |-------------------------------------------------------------------------- 62 | | 63 | | The listener array expects the key to be a Doctrine event 64 | | e.g. Doctrine\ORM\Events::onFlush 65 | | 66 | */ 67 | 'events' => [ 68 | 'listeners' => [], 69 | 'subscribers' => [] 70 | ], 71 | 'filters' => [] 72 | ] 73 | ], 74 | /* 75 | |-------------------------------------------------------------------------- 76 | | Doctrine Extensions 77 | |-------------------------------------------------------------------------- 78 | | 79 | | Enable/disable Doctrine Extensions by adding or removing them from the list 80 | | 81 | | If you want to require custom extensions you will have to require 82 | | laravel-doctrine/extensions in your composer.json 83 | | 84 | */ 85 | 'extensions' => [ 86 | //LaravelDoctrine\ORM\Extensions\TablePrefix\TablePrefixExtension::class, 87 | //LaravelDoctrine\Extensions\Timestamps\TimestampableExtension::class, 88 | //LaravelDoctrine\Extensions\SoftDeletes\SoftDeleteableExtension::class, 89 | //LaravelDoctrine\Extensions\Sluggable\SluggableExtension::class, 90 | //LaravelDoctrine\Extensions\Sortable\SortableExtension::class, 91 | //LaravelDoctrine\Extensions\Tree\TreeExtension::class, 92 | //LaravelDoctrine\Extensions\Loggable\LoggableExtension::class, 93 | //LaravelDoctrine\Extensions\Blameable\BlameableExtension::class, 94 | //LaravelDoctrine\Extensions\IpTraceable\IpTraceableExtension::class, 95 | //LaravelDoctrine\Extensions\Translatable\TranslatableExtension::class 96 | ], 97 | /* 98 | |-------------------------------------------------------------------------- 99 | | Doctrine custom types 100 | |-------------------------------------------------------------------------- 101 | */ 102 | 'custom_types' => [ 103 | 'json' => LaravelDoctrine\ORM\Types\Json::class 104 | ], 105 | /* 106 | |-------------------------------------------------------------------------- 107 | | DQL custom datetime functions 108 | |-------------------------------------------------------------------------- 109 | */ 110 | 'custom_datetime_functions' => [], 111 | /* 112 | |-------------------------------------------------------------------------- 113 | | DQL custom numeric functions 114 | |-------------------------------------------------------------------------- 115 | */ 116 | 'custom_numeric_functions' => [], 117 | /* 118 | |-------------------------------------------------------------------------- 119 | | DQL custom string functions 120 | |-------------------------------------------------------------------------- 121 | */ 122 | 'custom_string_functions' => [], 123 | /* 124 | |-------------------------------------------------------------------------- 125 | | Register custom hydrators 126 | |-------------------------------------------------------------------------- 127 | */ 128 | 'custom_hydration_modes' => [ 129 | // e.g. 'hydrationModeName' => MyHydrator::class, 130 | ], 131 | /* 132 | |-------------------------------------------------------------------------- 133 | | Enable query logging with laravel file logging, 134 | | debugbar, clockwork or an own implementation. 135 | | Setting it to false, will disable logging 136 | | 137 | | Available: 138 | | - LaravelDoctrine\ORM\Loggers\LaravelDebugbarLogger 139 | | - LaravelDoctrine\ORM\Loggers\ClockworkLogger 140 | | - LaravelDoctrine\ORM\Loggers\FileLogger 141 | |-------------------------------------------------------------------------- 142 | */ 143 | 'logger' => env('DOCTRINE_LOGGER', false), 144 | /* 145 | |-------------------------------------------------------------------------- 146 | | Cache 147 | |-------------------------------------------------------------------------- 148 | | 149 | | Configure meta-data, query and result caching here. 150 | | Optionally you can enable second level caching. 151 | | 152 | | Available: acp|array|file|memcached|redis 153 | | 154 | */ 155 | 'cache' => [ 156 | 'second_level' => false, 157 | 'default' => env('DOCTRINE_CACHE', 'array'), 158 | 'namespace' => null, 159 | 'metadata' => [ 160 | 'driver' => env('DOCTRINE_METADATA_CACHE', env('DOCTRINE_CACHE', 'array')), 161 | 'namespace' => null, 162 | ], 163 | 'query' => [ 164 | 'driver' => env('DOCTRINE_QUERY_CACHE', env('DOCTRINE_CACHE', 'array')), 165 | 'namespace' => null, 166 | ], 167 | 'result' => [ 168 | 'driver' => env('DOCTRINE_RESULT_CACHE', env('DOCTRINE_CACHE', 'array')), 169 | 'namespace' => null, 170 | ], 171 | ], 172 | /* 173 | |-------------------------------------------------------------------------- 174 | | Gedmo extensions 175 | |-------------------------------------------------------------------------- 176 | | 177 | | Settings for Gedmo extensions 178 | | If you want to use this you will have to require 179 | | laravel-doctrine/extensions in your composer.json 180 | | 181 | */ 182 | 'gedmo' => [ 183 | 'all_mappings' => false 184 | ] 185 | ]; 186 | ``` 187 | 188 | ### Entity Manager 189 | 190 | An **Entity Manager (EM)** contains all of the information Doctrine needs to understand, retrieve, and manipulate a set of entities (models). 191 | 192 | You must have **at least one** EM in order to use Laravel Doctrine. 193 | 194 | To use more than one EM simply create another entry in the `managers` array. 195 | 196 | | Property | Explanation | 197 | |:-----------|------------| 198 | | **EM Name** | In the sample below the EM we have configured is named `default`. This is the EM that Laravel Doctrine will attempt to use if no argument is provided to `ManagerRegistry`. | 199 | | **dev** | Whether this EM is in development mode. | 200 | | **meta** | The metadata driver to use. Built-in options are `fluent|annotations|yaml|simplified_yaml|xml|simplified_xml|config|static_php|php` | 201 | | **connection** | The connection driver to use. Built-in options are `mysql|oracle|pgsql|sqlite|sqlsrv` | 202 | | **namespaces** | (Optional) If your entities are not located in the configured app namespace you can specify a different one here. | 203 | | **paths** | An paths where the mapping configurations for your entities is located. | 204 | | **repository** | (Optional) The default repository to use for this EM. | 205 | | **decorator** | (Optional) Your custom EM decorator to overwrite the default EM. | 206 | | **proxies.namespace** | Namespace (if different) specified for proxy classes | 207 | | **proxies.path** | The path where proxy classes should be generated. | 208 | | **proxies.auto_generate** | Should proxy classes be generated every time an EM is created? (Turn off production) | 209 | | **events.subscribers** |Subscribers should implement `Doctrine\Common\EventSubscriber` | 210 | | **events.listeners** | Key should be event type. E.g. `Doctrine\ORM\Events::onFlush`. Value should be the listener class | 211 | | **filters** | Filter system that allows the developer to add SQL to the conditional clauses of queries, regardless the place where the SQL is generated | 212 | 213 | 214 | ```php 215 | 'managers' => [ 216 | 'default' => [ 217 | 'dev' => env('APP_DEBUG'), 218 | 'meta' => env('DOCTRINE_METADATA', 'annotations'), 219 | 'connection' => env('DB_CONNECTION', 'mysql'), 220 | 'namespaces' => [ 221 | 'App' 222 | ], 223 | 'paths' => [ 224 | base_path('app') 225 | ], 226 | 'repository' => Doctrine\ORM\EntityRepository::class, 227 | 'proxies' => [ 228 | 'namespace' => false, 229 | 'path' => storage_path('proxies'), 230 | 'auto_generate' => env('DOCTRINE_PROXY_AUTOGENERATE', false) 231 | ], 232 | 'events' => ... 233 | 'filters' => ... 234 | ] 235 | ] 236 | ``` 237 | 238 | #### Namespace Alias 239 | 240 | To use namespace alias, you just have to specify then as key of each namespace. 241 | 242 | Example: 243 | ```php 244 | 'managers' => [ 245 | 'default' => [ 246 | ... 247 | 'connection' => env('DB_CONNECTION', 'mysql'), 248 | 'namespaces' => [ 249 | 'Foo' => 'App\Model\Foo\Entities', 250 | 'Bar' => 'App\Model\Bar\Entities', 251 | ], 252 | 'paths' => [ 253 | base_path('app') 254 | ], 255 | ... 256 | ] 257 | ] 258 | ``` 259 | 260 | Whenever you need to specify entities in these namespaces, you can simple use the alias as follow: 261 | ```php 262 | SELECT f FROM Foo:SomeEntity 263 | or 264 | \EntityManager::getRepository('Bar:SomeEntity'); 265 | ``` 266 | 267 | ### Extensions 268 | 269 | Extensions can be enabled by adding them to this array. They provide additional functionality Entities (Timestamps, Loggable, etc.) 270 | 271 | To use the extensions in this sample you must install the extensions package: 272 | 273 | ``` 274 | require laravel-doctrine/extensions 275 | ``` 276 | 277 | and follow the [installation instructions.](http://www.laraveldoctrine.org/docs/current/extensions/installation) 278 | 279 | ```php 280 | 'extensions' => [ 281 | //LaravelDoctrine\ORM\Extensions\TablePrefix\TablePrefixExtension::class, 282 | //LaravelDoctrine\Extensions\Timestamps\TimestampableExtension::class, 283 | //LaravelDoctrine\Extensions\SoftDeletes\SoftDeleteableExtension::class, 284 | //LaravelDoctrine\Extensions\Sluggable\SluggableExtension::class, 285 | //LaravelDoctrine\Extensions\Sortable\SortableExtension::class, 286 | //LaravelDoctrine\Extensions\Tree\TreeExtension::class, 287 | //LaravelDoctrine\Extensions\Loggable\LoggableExtension::class, 288 | //LaravelDoctrine\Extensions\Blameable\BlameableExtension::class, 289 | //LaravelDoctrine\Extensions\IpTraceable\IpTraceableExtension::class, 290 | //LaravelDoctrine\Extensions\Translatable\TranslatableExtension::class 291 | ], 292 | ``` 293 | 294 | ### Custom Types 295 | 296 | Custom types are classes that allow Doctrine to marshal data to/from the data source in a custom format. 297 | 298 | To register a custom type simple add the class to this list. [For more information on custom types refer to the Doctrine documentation.](https://www.doctrine-project.org/projects/doctrine-orm/en/2.6/cookbook/custom-mapping-types.html) 299 | 300 | ### Custom Functions 301 | 302 | These are classes that extend the functionality of Doctrine's DQL language. More information on what functions are available [visit the repository.](https://github.com/beberlei/DoctrineExtensions) 303 | 304 | To use the extensions in this sample you must install the extensions package: 305 | 306 | ``` 307 | require laravel-doctrine/extensions 308 | ``` 309 | 310 | and follow the [installation instructions.](http://www.laraveldoctrine.org/docs/current/extensions/installation) 311 | 312 | If you include `BeberleiExtensionsServiceProvider` all custom functions will automatically be registered. 313 | 314 | To add a function simply add it to the correct list using this format: 315 | 316 | `'FUNCTION_NAME' => 'Path\To\Class'` 317 | 318 | ```php 319 | /* 320 | |-------------------------------------------------------------------------- 321 | | DQL custom datetime functions 322 | |-------------------------------------------------------------------------- 323 | */ 324 | 'custom_datetime_functions' => [], 325 | /* 326 | |-------------------------------------------------------------------------- 327 | | DQL custom numeric functions 328 | |-------------------------------------------------------------------------- 329 | */ 330 | 'custom_numeric_functions' => [], 331 | /* 332 | |-------------------------------------------------------------------------- 333 | | DQL custom string functions 334 | |-------------------------------------------------------------------------- 335 | */ 336 | 'custom_string_functions' => [], 337 | ``` 338 | 339 | ### Custom Hydration Modes 340 | 341 | This option enables you to register your Hydrator classes to use as custom hydration modes. For more information about custom hydration modes see [doctrine documentation](http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/dql-doctrine-query-language.html#custom-hydration-modes). 342 | 343 | To register custom hydrator, add it to the list in following format: 344 | 345 | `'hydrationModeName' => MyHydrator::class` 346 | 347 | ```php 348 | /* 349 | |-------------------------------------------------------------------------- 350 | | Register custom hydrators 351 | |-------------------------------------------------------------------------- 352 | */ 353 | 'custom_hydration_modes' => [ 354 | // e.g. 'hydrationModeName' => MyHydrator::class, 355 | ], 356 | ``` 357 | 358 | ### Logger 359 | 360 | Enable logging of Laravel Doctrine and Doctrine by using the logger functionality. 361 | 362 | |Available loggers| 363 | |--| 364 | | `LaravelDoctrine\ORM\Loggers\LaravelDebugbarLogger` | 365 | | `LaravelDoctrine\ORM\Loggers\ClockworkLogger` | 366 | | `LaravelDoctrine\ORM\Loggers\FileLogger` | 367 | 368 | ` 'logger' => env('DOCTRINE_LOGGER', false),` 369 | 370 | ### Cache 371 | 372 | Cache will be used to cache metadata, results and queries. 373 | 374 | **Available cache providers:** 375 | 376 | * apc 377 | * array 378 | * file 379 | * memcached 380 | * redis 381 | 382 | ** Config settings:** 383 | 384 | |Property|Explanation | 385 | |--|--| 386 | | **cache.default** | The default cache provider to use. | 387 | | **cache.namespace** | Will add namespace to the cache key. This is useful if you need extra control over handling key names collisions in your Cache solution.| 388 | | **cache.second_level** | The Second Level Cache is designed to reduce the amount of necessary database access. It sits between your application and the database to avoid the number of database hits as much as possible. When turned on, entities will be first searched in cache and if they are not found, a database query will be fired an then the entity result will be stored in a cache provider. When used, READ_ONLY is mostly used. ReadOnly cache can do reads, inserts and deletes, cannot perform updates| 389 | | **cache.metadata** | Your class metadata can be parsed from a few different sources like YAML, XML, Annotations, etc. Instead of parsing this information on each request we should cache it using one of the cache drivers. | 390 | | **cache.query** | Cache transformation of a DQL query to its SQL counterpart. | 391 | | **cache.result** | The result cache can be used to cache the results of your queries so you don't have to query the database or hydrate the data again after the first time. | 392 | 393 | ### Gedmo 394 | 395 | This is an option for use with **Extensions** 396 | 397 | To use this option you must first install the extensions package: 398 | 399 | ``` 400 | require laravel-doctrine/extensions 401 | ``` 402 | and follow the [installation instructions.](http://www.laraveldoctrine.org/docs/current/extensions/installation) 403 | -------------------------------------------------------------------------------- /orm/config-migrator.md: -------------------------------------------------------------------------------- 1 | #Config File Migrator 2 | 3 | Laravel Doctrine provides a command to help migrate the configuration from another Laravel/Doctrine package to Laravel Doctrine's format. 4 | 5 | > This tool is meant to be used AS A STARTING POINT for converting your configuration. In most cases you will still need to inspect and modify the generated configuration to suite your needs. 6 | 7 | ## Supported Packages 8 | 9 | | Package | Version | 10 | |:----:|---| 11 | | [atrauzzi/laravel-doctrine](https://github.com/atrauzzi/laravel-doctrine) | >= [dfef4ad](https://github.com/atrauzzi/laravel-doctrine/commit/dfef4ad87801a746a45d94d944a996498086a137) | 12 | | [mitchellvanw/laravel-doctrine](https://github.com/mitchellvanw/laravel-doctrine) | >= 0.5.0 or [FoxxMD's Fork](https://github.com/FoxxMD/laravel-doctrine) | 13 | 14 | 15 | ## Converting an Existing Configuration 16 | 17 | You must have artisan installed in your project in order to use this command. 18 | 19 | From the commandline usage is the following: 20 | 21 | `php artisan doctrine:config:convert [author] [--source-file] [--dest-path]` 22 | 23 | | Flag |Description| 24 | |:----:|---| 25 | | `author` |The author of the package migrating from. Available authors are: [mitchellvanw](https://github.com/mitchellvanw/laravel-doctrine) & [atrauzzi](https://github.com/atrauzzi/laravel-doctrine) | 26 | | `--source-file` |Path to your existing configuration file from the root dir of your project. If not provided defaults to `config/doctrine.php` | 27 | | `--dest-path` |Path where the migrated configuration should be created. If not provided defaults to `config/` | 28 | 29 | If migration is successful the file `doctrine.generated.php` is created in the `dest-path` specified. 30 | 31 | ## Writing A Template for a Configuration 32 | 33 | To create a new configuration file [blade templates](https://laravel.com/docs/master/blade) are used to create php code that is then rendered to a string and written to a file. Templates take in the original configuration as an array and output sections of the new configuration with the transformed values. 34 | 35 | To create a template follow the following steps: 36 | 37 | ## Implement "ConfigurationMigrator" 38 | 39 | ### Implement the interface 40 | 41 | First, create a new class that implements the interface [`LaravelDoctrine\ORM\ConfigMigrations`](https://github.com/laravel-doctrine/orm/blob/develop/src/Console/ConfigMigrations/ConfigurationMigrator.php) 42 | 43 | ### Write templates for each section of the config 44 | 45 | **This is one way to use templates, but may not be the best for your scenario.** Use your discretion. 46 | 47 | For each section in the configuration write a function that takes in the original configuration (or section of it) and provides it as an argument to a blade template. 48 | 49 | **Example** 50 | 51 | /** 52 | * Convert an entity manager section from mitchellvanw/laravel-doctrine to a string representation of a php array configuration for an entity manager for this project 53 | * 54 | * @param array $sourceArray 55 | * @param boolean $isFork 56 | * @return string 57 | */ 58 | public function convertManager($sourceArray, $isFork) 59 | { 60 | $results = $this->viewFactory->make('mitchell.manager', ['data' => $sourceArray, 'isFork' => $isFork])->render(); 61 | $unescaped = html_entity_decode($results, ENT_QUOTES); 62 | return $unescaped; 63 | } 64 | 65 | Write the new section of the configuration using blade syntax to create patterns to iterate over (IE `foreach` over `entityManagers`). 66 | 67 | **Example** 68 | 69 | [ 70 | 'meta' => '{{{ $isFork ? $data['metadata']['driver'] : 'annotations' }}}', 71 | 'connection' => {{{ $isFork ? '\''.$data['connection'].'\'' : 'config("database.default")' }}}, 72 | 'paths' => {{ var_export(ArrayUtil::get($data['metadata']['paths'], $data['metadata']), true) }}, 73 | 'repository' => '{{{ ArrayUtil::get($data['repository'], \LaravelDoctrine\ORM\EntityRepository::class) }}}', 74 | 'proxies' => [ 75 | 'namespace' => {{{ isset($data['proxy']['namespace']) ? '\'' . $data['proxy']['namespace'] .'\'' : 'false' }}}, 76 | 'path' => '{{{ ArrayUtil::get($data['proxy']['directory'], storage_path('proxies')) }}}', 77 | 'auto_generate' => '{{{ ArrayUtil::get($data['proxy']['auto_generate'], env('DOCTRINE_PROXY_AUTOGENERATE', 'false')) }}}' 78 | ], 79 | 'events' => [ 80 | 'listeners' => [], 81 | 'subscribers' => [] 82 | ], 83 | 'filters' => [] 84 | ] 85 | 86 | 87 | **Use ["MitchellMigrator"](https://github.com/laravel-doctrine/orm/blob/master/src/Console/ConfigMigrations/MitchellMigrator.php) as a reference.** 88 | 89 | ## Add Your Migrator to "ConvertConfigCommand" 90 | 91 | Finally, instantiate your Migrator and add a case for it in ["ConvertConfigCommand"](https://github.com/laravel-doctrine/orm/blob/master/src/Console/ConvertConfigCommand.php). 92 | -------------------------------------------------------------------------------- /orm/connections.md: -------------------------------------------------------------------------------- 1 | # Connections 2 | 3 | Out of the box the database connections configured in `database.php` config are supported: 4 | 5 | * mysql 6 | * sqlite 7 | * pqsql 8 | * sqlsrv 9 | * oci8 10 | 11 | Please note that read/write connections are supported as well. Check out [laravel documentation](https://laravel.com/docs/database#read-and-write-connections) for more details. 12 | 13 | By simply changing the `DB_CONNECTION` env variable you swap the database connection for Doctrine as well. 14 | The additional settings per connection are applied by default. 15 | 16 | ## Extending or Adding Connections Drivers 17 | 18 | You can replace existing connection drivers or add custom drivers using the `LaravelDoctrine\ORM\Configuration\Connections\ConnectionManager`. Should return an array of parameters. 19 | 20 | ```php 21 | public function boot(ConnectionManager $connections) { 22 | $connections->extend('myDriver', function(array $settings, \Illuminate\Contracts\Container\Container $container) { 23 | return [ 24 | 'driver' => 'driver', 25 | 'host' => ... 26 | ]; 27 | }); 28 | } 29 | ``` 30 | 31 | You can find the available connection parameters inside the Doctrine documentation: http://doctrine-dbal.readthedocs.org/en/latest/reference/configuration.html 32 | -------------------------------------------------------------------------------- /orm/console.md: -------------------------------------------------------------------------------- 1 | # Console 2 | 3 | This package offers a bunch of artisan commands to speed up development: 4 | 5 | Artisan command | Description 6 | --- | --- 7 | `doctrine:clear:metadata:cache` | Clear all metadata cache of the various cache drivers. 8 | `doctrine:clear:query:cache`|Clear all query cache of the various cache drivers. 9 | `doctrine:clear:result:cache`|Clear all result cache of the various cache drivers. 10 | `doctrine:ensure:production`|Verify that Doctrine is properly configured for a production environment. 11 | `doctrine:generate:proxies`|Generates proxy classes for entity classes. 12 | `doctrine:info`|Show basic information about all mapped entities. 13 | `doctrine:schema:create`|Processes the schema and either create it directly on EntityManager Storage Connection or generate the SQL output. 14 | `doctrine:schema:drop`|Drop the complete database schema of EntityManager Storage Connection or generate the corresponding SQL output. 15 | `doctrine:schema:update`|Executes (or dumps) the SQL needed to update the database schema to match the current mapping metadata. 16 | `doctrine:schema:validate`|Validate the mapping files. 17 | -------------------------------------------------------------------------------- /orm/contributions.md: -------------------------------------------------------------------------------- 1 | # Contribution Guide 2 | 3 | - [Bug Reports](#bug-reports) 4 | - [Core Development Discussion](#core-development-discussion) 5 | - [Which Branch?](#which-branch) 6 | - [Coding Style](#coding-style) 7 | 8 | 9 | ## Bug Reports 10 | 11 | To encourage active collaboration, we strongly encourages pull requests, not just bug reports. "Bug reports" may also be sent in the form of a pull request containing a failing test. 12 | 13 | However, if you file a bug report, your issue should contain a title and a clear description of the issue. You should also include as much relevant information as possible and a code sample that demonstrates the issue. The goal of a bug report is to make it easy for yourself - and others - to replicate the bug and develop a fix. 14 | 15 | Remember, bug reports are created in the hope that others with the same problem will be able to collaborate with you on solving it. Do not expect that the bug report will automatically see any activity or that others will jump to fix it. Creating a bug report serves to help yourself and others start on the path of fixing the problem. 16 | 17 | The Laravel Doctrine source code is managed on Github, and there are repositories for each of the Laravel Doctrine projects: 18 | 19 | - [Laravel Doctrine ORM](https://github.com/laravel-doctrine/orm) 20 | - [Laravel Doctrine ACL](https://github.com/laravel-doctrine/acl) 21 | - [Laravel Doctrine Extensions](https://github.com/laravel-doctrine/extensions) 22 | - [Laravel Doctrine Migrations](https://github.com/laravel-doctrine/migrations) 23 | - [Laravel Doctrine Documentation](https://github.com/laravel-doctrine/docs) 24 | - [Laravel Doctrine Website](https://github.com/laravel-doctrine/laraveldoctrine.org) 25 | 26 | 27 | ## Core Development Discussion 28 | 29 | Discussion regarding bugs, new features, and implementation of existing features takes place in the channel linked to the package of the [Laravel Doctrine Slack](http://slack.laraveldoctrine.org) Slack team. 30 | 31 | 32 | ## Which Branch? 33 | 34 | **All** bug fixes should be sent to the latest stable branch. Bug fixes should **never** be sent to the `master` branch unless they fix features that exist only in the upcoming release. 35 | 36 | **Minor** features that are **fully backwards compatible** with the current Laravel Doctrine release may be sent to the latest stable branch. 37 | 38 | **Major** new features should always be sent to the `master` branch, which contains the upcoming Laravel Doctrine release. 39 | 40 | If you are unsure if your feature qualifies as a major or minor, please ask help in the `#general` channel of the [Laravel Doctrine Slack](http://slack.laraveldoctrine.org) Slack team. 41 | 42 | It's always a good idea to back your Pull Request with tests, proving your implementation works and gives an idea of what your code does. Always run the tests locally to see if you didn't break any existing code. 43 | 44 | 45 | ## Coding Style 46 | 47 | Laravel Doctrine follows the [PSR-2](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md) coding standard and the [PSR-4](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4-autoloader.md) autoloading standard. 48 | 49 | A config file for [PHP-CS-Fixer](https://github.com/FriendsOfPHP/PHP-CS-Fixer) is included. Every PR will be analyzed for PSR-2 and PSR-4 by [StyleCI](https://styleci.io/). 50 | -------------------------------------------------------------------------------- /orm/default-table-options.md: -------------------------------------------------------------------------------- 1 | # Default Table Options 2 | 3 | You can set default table options for your database connections. 4 | 5 | Modify your `database.php` configuration file to include the `defaultTableOptions` key 6 | 7 | # Example 8 | for a MySQL databse 9 | ```php 10 | ... 11 | 'mysql' => [ 12 | 'driver' => 'mysql', 13 | 'host' => env('DB_HOST', '127.0.0.1'), 14 | 'port' => env('DB_PORT', '3306'), 15 | 'database' => env('DB_DATABASE', 'forge'), 16 | 'username' => env('DB_USERNAME', 'forge'), 17 | 'password' => env('DB_PASSWORD', ''), 18 | 'unix_socket' => env('DB_SOCKET', ''), 19 | 'defaultTableOptions' => [ 20 | 'charset' => 'utf8mb4', 21 | 'collate' => 'utf8mb4_unicode_ci' 22 | ], 23 | 'charset' => 'utf8mb4', // This will be the charset for the connection 24 | 'prefix' => '', 25 | 'strict' => true, 26 | 'engine' => null, 27 | ], 28 | ... 29 | ``` 30 | 31 | Property | Explaination 32 | ---- | ---- 33 | charset | Tables will be created with `CHARACTER SET utf8` by default *Even If* your database is set up with it's own default character set. Setting this property will ensure new tables are created with the given encoding 34 | collate | As above, this must be edited if you with your collation to be anything other than utf8_unicode_ci 35 | -------------------------------------------------------------------------------- /orm/doctrine-manager.md: -------------------------------------------------------------------------------- 1 | # Accessing Entity Managers 2 | 3 | Laravel Doctrine uses `DoctrineManager` to provide an easy method of hooking into the internals of an Entity Manager for more advanced configuration than is possible with just a configuration file. 4 | 5 | It provides access to three facets of Doctrine: 6 | 7 | * [Doctrine\ORM\Configuration](http://www.doctrine-project.org/api/dbal/2.1/class-Doctrine.DBAL.Configuration.html) 8 | * [Doctrine\DBAL\Connection](http://www.doctrine-project.org/api/dbal/2.1/class-Doctrine.DBAL.Connection.html) 9 | * [Doctrine\Common\EventManager](http://www.doctrine-project.org/api/common/2.2/class-Doctrine.Common.EventManager.html) 10 | 11 | These objects are accessed **per Entity Manager** using the name configured for that EM in `doctrine.php` 12 | 13 | ## Using DoctrineManager 14 | 15 | Boilerplate example of `DoctrineManager` using facade `LaravelDoctrine\ORM\Facades\Doctrine` 16 | 17 | ```php 18 | Doctrine::extend('myManager', function(Configuration $configuration, Connection $connection, EventManager $eventManager) { 19 | //modify and access settings as is needed 20 | }); 21 | ``` 22 | 23 | Using dependency injection in `boot()` of a ServiceProvider 24 | 25 | ```php 26 | public function boot(DoctrineManager $manager) { 27 | $manager->extend('myManager', function(Configuration $configuration, Connection $connection, EventManager $eventManager) { 28 | //modify and access settings as is needed 29 | }); 30 | } 31 | ``` 32 | 33 | ## Implementing Your Own Extender 34 | 35 | Additionally, you can write your own custom manager by implementing `LaravelDoctrine\ORM\DoctrineExtender` 36 | 37 | ```php 38 | class MyDoctrineExtender implements DoctrineExtender 39 | { 40 | /** 41 | * @param Configuration $configuration 42 | * @param Connection $connection 43 | * @param EventManager $eventManager 44 | */ 45 | public function extend(Configuration $configuration, Connection $connection, EventManager $eventManager) 46 | { 47 | //your extending code... 48 | } 49 | } 50 | ``` 51 | 52 | ```php 53 | $manager->extend('myManager', MyDoctrineExtender::class); 54 | ``` 55 | -------------------------------------------------------------------------------- /orm/entities.md: -------------------------------------------------------------------------------- 1 | # Entities 2 | 3 | Out of the box this package uses the default Laravel connection from the `.env` file `DB_CONNECTION`, which means that you are ready to start fetching and persisting. 4 | 5 | ```php 6 | addTheory( 14 | new Theory('Theory of relativity') 15 | ); 16 | 17 | EntityManager::persist($scientist); 18 | EntityManager::flush(); 19 | ``` 20 | 21 | Unlike Eloquent, Doctrine is not an Active Record pattern, but a Data Mapper pattern. Every Active Record model extends a base class (with all the database logic), which has a lot of overhead and dramatically slows down your application with thousands or millions of records. 22 | Doctrine entities don't extend any class, they are just regular PHP classes with properties and getters and setters. 23 | Generally the properties are protected or private, so they only can be accessed through getters and setters. 24 | 25 | The domain/business logic is completely separated from the persistence logic. 26 | This means we have to tell Doctrine how it should map the columns from the database to our Entity class. In this example we are using annotations. Other possiblities are YAML, XML or PHP arrays. 27 | 28 | Entities are objects with identity. Their identity has a conceptual meaning inside your domain. In an application each article has a unique id. You can uniquely identify each article by that id. 29 | 30 | Relations are stored in `ArrayCollection`. It's advised to always set this default value in the constructor. `$this->theories = new ArrayCollection`. 31 | You can easily add on new relations with `->add()`, remove them with `->removeElement()` or check if the relation is already defined with `->contains()` 32 | 33 | The `Scientist` entity used in the example above looks like this when using annotations for the meta data. 34 | 35 | ```php 36 | firstname = $firstname; 77 | $this->lastname = $lastname; 78 | 79 | $this->theories = new ArrayCollection; 80 | } 81 | 82 | public function getId() 83 | { 84 | return $this->id; 85 | } 86 | 87 | public function getFirstname() 88 | { 89 | return $this->firstname; 90 | } 91 | 92 | public function getLastname() 93 | { 94 | return $this->lastname; 95 | } 96 | 97 | public function addTheory(Theory $theory) 98 | { 99 | if(!$this->theories->contains($theory)) { 100 | $theory->setScientist($this); 101 | $this->theories->add($theory); 102 | } 103 | } 104 | 105 | public function getTheories() 106 | { 107 | return $this->theories; 108 | } 109 | } 110 | ``` 111 | 112 | The related `Theory` entity would look like this: 113 | 114 | ```php 115 | title = $title; 149 | } 150 | 151 | public function getId() 152 | { 153 | return $this->id; 154 | } 155 | 156 | public function getTitle() 157 | { 158 | return $this->title; 159 | } 160 | 161 | public function setScientist(Scientist $scientist) 162 | { 163 | $this->scientist = $scientist; 164 | } 165 | 166 | public function getScientist() 167 | { 168 | return $this->scientist; 169 | } 170 | } 171 | ``` 172 | -------------------------------------------------------------------------------- /orm/entity-manager.md: -------------------------------------------------------------------------------- 1 | #Entity Manager 2 | 3 | The EntityManager is the central access point to ORM functionality. It can be used to find, persist, flush and remove entities. 4 | 5 | ## Using the EntityManager 6 | 7 | #### Facade 8 | 9 | You can use the facade to access the `EntityManager` methods 10 | 11 | ```php 12 | EntityManager::flush(); 13 | ``` 14 | 15 | #### Container 16 | 17 | ```php 18 | app('em'); 19 | app('Doctrine\ORM\EntityManagerInterface'); 20 | ``` 21 | 22 | #### Dependency injection 23 | 24 | ```php 25 | em = $em; 36 | } 37 | } 38 | ``` 39 | 40 | #### Multiple connections 41 | 42 | If you are using multiple connections `EntityManagerInterface` will return the default connection. If you want to have control over which EnityManager you want, you'll have to inject `Doctrine\Common\Persistence\ManagerRegistry` 43 | 44 | ```php 45 | use Doctrine\Common\Persistence\ManagerRegistry; 46 | 47 | class ExampleController extends Controller 48 | { 49 | protected $em; 50 | 51 | public function __construct(ManagerRegistry $em) 52 | { 53 | $this->em = $em->getManager('otherConnection'); 54 | } 55 | } 56 | ``` 57 | 58 | ## Finding entities 59 | 60 | > Note: for making the examples more expressive, we will use the facade. However I do recommend to leverage dependency injection as much as possible. This makes mocking the EntityManager in your tests a lot easier. 61 | 62 | Entities are objects with identity. Their identity has a conceptual meaning inside your domain. In a CMS application each article has a unique id. You can uniquely identify each article by that id. 63 | 64 | In the example underneath, the Article entity is fetched from the entity manager twice, but was modified after the first find. Doctrine2 keeps track of all those changes. This pattern is called `Identity Map pattern`, which means that Doctrine keeps a map of each entity and ids that have been retrieved per request and keeps return the same instances on every find. 65 | 66 | `$article` and `$article1` will be identical, eventhough we haven't persisted the changes to `$article` to the database yet. 67 | 68 | ```php 69 | $article = EntityManager::find('App\Entities\Article', 1); 70 | $article->setTitle('Different title'); 71 | 72 | $article2 = EntityManager::find('App\Entities\Article', 1); 73 | 74 | if ($article === $article2) { 75 | echo "Yes we are the same!"; 76 | } 77 | ``` 78 | 79 | ### Persisting 80 | 81 | By passing the entity through the `persist` method of the EntityManager, that entity becomes MANAGED, which means that its persistence is from now on managed by an EntityManager. As a result the persistent state of such an entity will subsequently be properly synchronised with the database when `EntityManager::flush()` is invoked. 82 | 83 | > Note: `persist()` doesn't do any `INSERT` queries. 84 | 85 | ```php 86 | $article = new Article; 87 | $article->setTitle('Let\'s learn about persisting'); 88 | 89 | EntityManager::persist($article); 90 | EntityManager::flush(); 91 | ``` 92 | 93 | ### Flushing 94 | 95 | Whenever you have changed the state of an Entity (updated, created, removed, ...) you will have to flush the entity manager to persist these changes to the database. 96 | 97 | ```php 98 | // Flush all changes 99 | EntityManager::flush(); 100 | 101 | // Only flush changes of given entity 102 | EntityManager::flush($article); 103 | ``` 104 | 105 | ### Removing 106 | 107 | An entity can be removed from persistent storage by passing it to the `remove($entity)` method. By applying the remove operation on some entity, that entity becomes REMOVED, which means that its persistent state will be deleted once `flush()` is invoked. 108 | 109 | ```php 110 | EntityManager::remove($article); 111 | EntityManager::flush(); 112 | ``` 113 | 114 | More information about the entity manager: https://www.doctrine-project.org/projects/doctrine-orm/en/2.6/reference/working-with-objects.html 115 | -------------------------------------------------------------------------------- /orm/index.md: -------------------------------------------------------------------------------- 1 | - Prologue 2 | - [Introduction](/docs/{{version}}/orm/introduction) 3 | - [Upgrade Guide](/docs/{{version}}/orm/upgrade) 4 | - [Contribution Guide](/docs/{{version}}/orm/contributions) 5 | - Setup 6 | - [Laravel](/docs/{{version}}/orm/installation) 7 | - [Lumen](/docs/{{version}}/orm/lumen) 8 | - The Basics 9 | - [Entities](/docs/{{version}}/orm/entities) 10 | - [Meta Data](/docs/{{version}}/orm/meta-data) 11 | - [Entity Manager](/docs/{{version}}/orm/entity-manager) 12 | - [Multiple Connections](/docs/{{version}}/orm/multiple-connections) 13 | - [Repositories](/docs/{{version}}/orm/repositories) 14 | - [Console](/docs/{{version}}/orm/console) 15 | - Configuration 16 | - [Configuration File Overview](/docs/{{version}}/orm/config-file) 17 | - [Accessing Entity Managers](/docs/{{version}}/orm/doctrine-manager) 18 | - [Extending Connections](/docs/{{version}}/orm/connections) 19 | - [Extending MetaData](/docs/{{version}}/orm/meta-data-configuration) 20 | - [Extending Caching](/docs/{{version}}/orm/caching) 21 | - [Troubleshooting](/docs/{{version}}/orm/troubleshooting) 22 | - Services 23 | - [Authentication](/docs/{{version}}/orm/auth) 24 | - [Password resets](/docs/{{version}}/orm/passwords) 25 | - [Testing](/docs/{{version}}/orm/testing) 26 | - [Validation](/docs/{{version}}/orm/validation) 27 | - [Notifications](/docs/{{version}}/orm/notifications) 28 | -------------------------------------------------------------------------------- /orm/installation.md: -------------------------------------------------------------------------------- 1 | # Installation in Laravel 6+ 2 | 3 | Laravel | Laravel Doctrine 4 | :---------|:---------- 5 | 6.* | ~1.5 6 | 7.* | ~1.6 7 | 8.* | ~1.7 8 | 9.* | ~1.8 9 | 10 | Install this package with composer: 11 | 12 | ``` 13 | composer require laravel-doctrine/orm 14 | ``` 15 | 16 | Thanks to Laravel auto package discovery feature, the ServiceProvider and Facades are automatically registered. 17 | However they can still be manually registered if required 18 | 19 | ## Manual registration 20 | After updating composer, add the ServiceProvider to the providers array in `config/app.php` 21 | 22 | ```php 23 | LaravelDoctrine\ORM\DoctrineServiceProvider::class, 24 | ``` 25 | 26 | Optionally you can register the EntityManager, Registry and/or Doctrine facade: 27 | 28 | ```php 29 | 'EntityManager' => LaravelDoctrine\ORM\Facades\EntityManager::class, 30 | 'Registry' => LaravelDoctrine\ORM\Facades\Registry::class, 31 | 'Doctrine' => LaravelDoctrine\ORM\Facades\Doctrine::class, 32 | ``` 33 | 34 | ## Config 35 | To publish the config use: 36 | 37 | ```php 38 | php artisan vendor:publish --tag="config" --provider="LaravelDoctrine\ORM\DoctrineServiceProvider" 39 | ``` 40 | 41 | Available environment variables inside the config are: `APP_DEBUG`, `DOCTRINE_METADATA`, `DB_CONNECTION`, `DOCTRINE_PROXY_AUTOGENERATE`, `DOCTRINE_LOGGER` and `DOCTRINE_CACHE` 42 | 43 | > Important: 44 | > By default, Laravel's application skeleton has its `Model` classes in the `app/Models` folder. With Doctrine, you'll need to 45 | > create a dedicated folder for your `Entities` and point your `config/doctrine.php` `paths` array to it. 46 | > If you don't, Doctrine will scan your whole `app/` folder for files, which will have a huge impact on performance! 47 | > 48 | > ``` 49 | > 'paths' => [ 50 | > base_path('app/Entities'), 51 | > ], 52 | > ``` 53 | -------------------------------------------------------------------------------- /orm/introduction.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | #### A drop-in Doctrine ORM 2 implementation for Laravel 6+ 4 | 5 | Doctrine 2 is an object-relational mapper (ORM) for PHP that provides transparent persistence for PHP objects. 6 | It uses the Data Mapper pattern at the heart, aiming for a complete separation of 7 | your domain/business logic from the persistence in a relational database management system. 8 | 9 | The benefit of Doctrine for the programmer is the ability to focus on the object-oriented business 10 | logic and worry about persistence only as a secondary problem. This doesn’t mean persistence is downplayed by Doctrine 2, 11 | however it is our belief that there are considerable benefits for object-oriented programming if persistence and entities are kept separated. 12 | 13 | *Laravel Doctrine offers:* 14 | 15 | * Easy configuration 16 | * Pagination 17 | * Preconfigured metadata, connections and caching 18 | * Extendable: extend or add your own drivers for metadata, connections or cache 19 | * Change metadata, connection or cache settings easy with a resolved hook 20 | * Annotations, yaml, xml, config and static php meta data mappings 21 | * Multiple entity managers and connections 22 | * Laravel naming strategy 23 | * Simple authentication implementation 24 | * Password reminders implementation 25 | * Doctrine console commands 26 | * DoctrineExtensions supported 27 | * Timestamps, Softdeletes and TablePrefix listeners 28 | -------------------------------------------------------------------------------- /orm/lumen.md: -------------------------------------------------------------------------------- 1 | # Installation in Lumen 6+ 2 | 3 | Lumen | Laravel Doctrine 4 | :---------|:---------- 5 | 6.* | ~1.5 6 | 7.* | ~1.6 7 | 8.* | ~1.7 8 | 9 | To set up Laravel Doctrine in Lumen, we need some additional steps. 10 | 11 | Install this package with composer: 12 | 13 | ``` 14 | composer require "laravel-doctrine/orm:1.7.*" 15 | ``` 16 | 17 | After updating composer, open `bootstrap/app.php` and register the Service Provider: 18 | 19 | ```php 20 | $app->register(LaravelDoctrine\ORM\DoctrineServiceProvider::class); 21 | ``` 22 | 23 | Optionally you can register the EntityManager, Registry and/or Doctrine Facade. Don't forget to uncomment `$app->withFacades();` 24 | 25 | ```php 26 | class_alias('LaravelDoctrine\ORM\Facades\EntityManager', 'EntityManager'); 27 | class_alias('LaravelDoctrine\ORM\Facades\Registry', 'Registry'); 28 | class_alias('LaravelDoctrine\ORM\Facades\Doctrine', 'Doctrine'); 29 | ``` 30 | 31 | Uncomment `// Dotenv::load(__DIR__.'/../');`, so environment variables can be loaded 32 | 33 | Next, you will need to create the `config/database.php` and `config/cache.php` config files. 34 | 35 | The database config file should look at least like this (assuming you are using MYSQL), but you can copy it from the Laravel source too: 36 | 37 | ```php 38 | env('DB_CONNECTION', 'mysql'), 52 | /* 53 | |-------------------------------------------------------------------------- 54 | | Database Connections 55 | |-------------------------------------------------------------------------- 56 | | 57 | | Here are each of the database connections setup for your application. 58 | | Of course, examples of configuring each database platform that is 59 | | supported by Laravel is shown below to make development simple. 60 | | 61 | | 62 | | All database work in Laravel is done through the PHP PDO facilities 63 | | so make sure you have the driver for your particular database of 64 | | choice installed on your machine before you begin development. 65 | | 66 | */ 67 | 'connections' => [ 68 | 'mysql' => [ 69 | 'driver' => 'mysql', 70 | 'host' => env('DB_HOST', 'localhost'), 71 | 'database' => env('DB_DATABASE'), 72 | 'username' => env('DB_USERNAME'), 73 | 'password' => env('DB_PASSWORD'), 74 | 'charset' => 'utf8', 75 | 'collation' => 'utf8_unicode_ci', 76 | 'prefix' => '', 77 | 'strict' => false, 78 | ] 79 | ], 80 | ]; 81 | ``` 82 | 83 | If you are using apc, file, memcached or redis cache, the following config should be added: 84 | 85 | ```php 86 | [ 100 | 'apc' => [ 101 | 'driver' => 'apc', 102 | ], 103 | 'file' => [ 104 | 'driver' => 'file', 105 | 'path' => storage_path('framework/cache'), 106 | ], 107 | 'memcached' => [ 108 | 'driver' => 'memcached', 109 | 'servers' => [ 110 | [ 111 | 'host' => '127.0.0.1', 'port' => 11211, 'weight' => 100, 112 | ], 113 | ], 114 | ], 115 | 'redis' => [ 116 | 'driver' => 'redis', 117 | 'connection' => 'default', 118 | ], 119 | ], 120 | ]; 121 | ``` 122 | 123 | ### Config 124 | 125 | If you want to overrule the Doctrine config. You will have to create a `config/doctrine.php` file and copy the contents from the package config. 126 | 127 | Available environment variables inside the config are: `APP_DEBUG`, `DOCTRINE_METADATA`, `DB_CONNECTION`, `DOCTRINE_PROXY_AUTOGENERATE`, `DOCTRINE_LOGGER` and `DOCTRINE_CACHE` 128 | -------------------------------------------------------------------------------- /orm/meta-data-configuration.md: -------------------------------------------------------------------------------- 1 | # Meta Data 2 | 3 | ### Annotations 4 | 5 | This package supports Doctrine annotations meta data and can be enabled inside the config. 6 | 7 | ### XML 8 | 9 | This package supports Doctrine xml meta data and can be enabled inside the config. 10 | 11 | ### SimplifiedXML 12 | 13 | This package supports simplified Doctrine xml meta data and can be enabled inside the config. 14 | 15 | The format of the `paths` config value in `doctrine.php` config differs sligthly from the default. The path should be passed as key, the namespace as value. 16 | 17 | ``` 18 | 'paths' => [ 19 | '/path/to/files1' => 'MyProject\Entities', 20 | '/path/to/files2' => 'OtherProject\Entities' 21 | ], 22 | ``` 23 | 24 | Check the Doctrine documentation for more information: https://www.doctrine-project.org/projects/doctrine-orm/en/2.6/reference/xml-mapping.html#simplified-xml-driver 25 | 26 | ### YAML 27 | 28 | > **NOTE:** The YAML driver is deprecated and will be removed in Doctrine 3.0. 29 | 30 | This package supports Doctrine yml meta data and can be enabled inside the config. 31 | 32 | ### SimplifiedYAML 33 | 34 | > **NOTE:** The YAML driver is deprecated and will be removed in Doctrine 3.0. 35 | 36 | This package supports simplified Doctrine yml meta data and can be enabled inside the config. 37 | 38 | The format of the `paths` config value in `doctrine.php` config differs sligthly from the default. The path should be passed as key, the namespace as value. 39 | 40 | ``` 41 | 'paths' => [ 42 | '/path/to/files1' => 'MyProject\Entities', 43 | '/path/to/files2' => 'OtherProject\Entities' 44 | ], 45 | ``` 46 | 47 | Check the Doctrine documentation for more information: https://www.doctrine-project.org/projects/doctrine-orm/en/2.6/reference/yaml-mapping.html#simplified-yaml-driver 48 | 49 | ### StaticPhp 50 | 51 | This package supports static PHP (`static_php`) meta data and can be enabled inside the config. 52 | 53 | ### Config 54 | 55 | This package supports using config meta data and can be enabled inside the config. 56 | 57 | ## Extending or Adding Metadata Drivers 58 | Drivers can be replaced or added using `LaravelDoctrine\ORM\Configuration\MetaData\MetaDataManager`. The callback should return an instance of `\Doctrine\Common\Persistence\Mapping\Driver\MappingDriver` 59 | 60 | ```php 61 | public function boot(MetaDataManager $metadata) { 62 | $metadata->extend('myDriver', function(Application $app) { 63 | return new FluentDriver(); 64 | }); 65 | } 66 | ``` 67 | -------------------------------------------------------------------------------- /orm/meta-data.md: -------------------------------------------------------------------------------- 1 | # Meta Data 2 | 3 | Because the Entity doesn't extend any smart base class, we will have to tell Doctrine how to map the data from the database into the entity. There're multiple ways of doing this: 4 | 5 | ### Annotations 6 | 7 | The annotation driver is set as default meta driver. It searches the entities in the `app` folder, but you can change this to whatever folder (or multiple folders) you like. Annotations means, that you will use docblocks to indicate the column mappings. 8 | 9 | ```php 10 | id; 35 | } 36 | 37 | public function getTitle() 38 | { 39 | return $this->title; 40 | } 41 | 42 | public function setTitle($title) 43 | { 44 | $this->title = $title; 45 | } 46 | } 47 | ``` 48 | 49 | More about the annotation driver: https://www.doctrine-project.org/projects/doctrine-orm/en/2.6/reference/annotations-reference.html#annotations-reference 50 | 51 | ### Attributes 52 | 53 | The attributes driver requires php 8 or above. It searches the entities in the `app` folder, but you can change this to whatever folder (or multiple folders) you like. Attributes means, that you will use attributes to indicate the column mappings. 54 | 55 | ```php 56 | id; 79 | } 80 | 81 | public function getTitle() 82 | { 83 | return $this->title; 84 | } 85 | 86 | public function setTitle($title) 87 | { 88 | $this->title = $title; 89 | } 90 | } 91 | ``` 92 | 93 | More about the attributes driver: https://www.doctrine-project.org/projects/doctrine-orm/en/2.11/reference/attributes-reference.html 94 | 95 | ### YAML 96 | 97 | > **NOTE:** The YAML driver is deprecated and will be removed in Doctrine 3.0. 98 | 99 | If you prefer Yaml, you can easily switch the meta driver to `yaml`. It's better to change the meta data paths to something like `config_path('mappings')` instead of adding them all to the `app` folder. 100 | 101 | ```yaml 102 | # App.Entities.Article.dcm.yml 103 | App\Entities\Article: 104 | type: entity 105 | table: articles 106 | id: 107 | id: 108 | type: integer 109 | generator: 110 | strategy: AUTO 111 | fields: 112 | title: 113 | type: string 114 | ``` 115 | 116 | More about the YAML driver: https://www.doctrine-project.org/projects/doctrine-orm/en/2.6/reference/yaml-mapping.html 117 | 118 | ### XML 119 | 120 | Another option is to leverage XML mappings. Just like YAML it's better to change the meta data paths to something like `config_path('mappings')`. 121 | 122 | ```xml 123 | // App.Article.dcm.xml 124 | 125 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | ``` 142 | 143 | More information about XML mappings: https://www.doctrine-project.org/projects/doctrine-orm/en/2.6/reference/xml-mapping.html 144 | 145 | ### Config files 146 | 147 | This package adds another option, which leverages Laravel's config system. In addition to setting `meta`, this also requires setting `mapping_file`. You could for example create a `config/mappings.php` file to provide mapping information. Here is an example of setting the `meta` and `mapping_file` config properties inside of `config/doctrine.php` to use config file-based metadata: 148 | 149 | ```php 150 | [ 154 | 'default' => [ 155 | 'meta' => env('DOCTRINE_METADATA', 'config'), 156 | 'mapping_file' => 'mappings', 157 | ``` 158 | 159 | The array structure in `config/mappings.php` is almost identical to the YAML one: 160 | 161 | ```php 162 | [ 165 | 'type' => 'entity', 166 | 'table' => 'articles', 167 | 'id' => [ 168 | 'id' => [ 169 | 'type' => 'integer', 170 | 'generator' => [ 171 | 'strategy' => 'auto' 172 | ] 173 | ], 174 | ], 175 | 'fields' => [ 176 | 'title' => [ 177 | 'type' => 'string' 178 | ] 179 | ] 180 | ] 181 | ]; 182 | ``` 183 | 184 | ### Static PHP 185 | 186 | When you change the meta data driver setting to `static_php`, your entities will expect a `loadMetadata` method. 187 | 188 | ```php 189 | mapField(array( 200 | 'id' => true, 201 | 'fieldName' => 'id', 202 | 'type' => 'integer' 203 | )); 204 | 205 | $metadata->mapField(array( 206 | 'fieldName' => 'title', 207 | 'type' => 'string' 208 | )); 209 | } 210 | } 211 | ``` 212 | 213 | More on the StaticPHP driver: https://www.doctrine-project.org/projects/doctrine-orm/en/2.6/reference/php-mapping.html 214 | -------------------------------------------------------------------------------- /orm/multiple-connections.md: -------------------------------------------------------------------------------- 1 | # Multiple Connections 2 | 3 | You can use multiple Doctrine entity managers or connections. This is necessary if you are using different databases or even vendors with entirely different sets of entities. In other words, one entity manager that connects to one database will handle some entities while another entity manager that connects to another database might handle the rest. 4 | 5 | The default manager is configured in `doctrine.managers`. This one will get used when you use the `EntityManager` directly. You can add more managers to this array. 6 | 7 | In your application you can inject `Doctrine\Common\Persistence\ManagerRegistry`. This holds all entity managers. `ManagerRegistry@getManager()` will return the default manager. By passing through the manager name, you will get the connection you want. Alternatively you can use `getManagerForClass($entityName)` to get a manager which is suitable for that entity. 8 | -------------------------------------------------------------------------------- /orm/notifications.md: -------------------------------------------------------------------------------- 1 | # Notifications 2 | 3 | Laravel 5.3 introduced a brand new notification system with support for custom channels like mail, slack, sms, etc. 4 | Laravel Doctrine offers a doctrine channel so notifications can also be stored in your database. 5 | 6 | ### Notification entity 7 | 8 | First create a `Notification` entity in your project that extends `LaravelDoctrine\ORM\Notifications\Notification`. 9 | Adding `protected $user` is only needed when you are using `annotations`. All other metadata drivers can use the already existing `$user` property. 10 | It might look like this: 11 | 12 | ```php 13 | to($user) 35 | ->success(); 36 | 37 | $n->error(); 38 | 39 | $n->level('info') 40 | ->message('Your notification message') 41 | ->action('Click here', 'http://yoururl.com'); 42 | ``` 43 | 44 | It also has getters to retrieve information about the notification: 45 | 46 | ```php 47 | $n->getId(); 48 | $n->getUser(); 49 | $n->getLevel(); 50 | $n->getMessage(); 51 | $n->getActionText(); 52 | $n->getActionUrl(); 53 | ``` 54 | 55 | ### Publishing notifications on the doctrine channel 56 | 57 | It's recommended you read the Laravel docs: https://laravel.com/docs/notifications 58 | 59 | The Doctrine channel is available as: `LaravelDoctrine\ORM\Notifications\DoctrineChannel::class` 60 | 61 | When adding this channel you need to provide a `toEntity` method. This method should return a new instance of your `Notification` class. 62 | You can use the fluent methods like described above. 63 | 64 | ```php 65 | to($notifiable) 90 | ->success() 91 | ->message('Some message') 92 | ->action('Bla', 'http://test.nl'); 93 | } 94 | } 95 | ``` 96 | 97 | ### Notifiable Entity 98 | 99 | Your Notifiable entity should use the `LaravelDoctrine\ORM\Notifications\Notifiable` trait. 100 | 101 | Now you will be able to do `$user->notify(new InvoicePaid);` 102 | 103 | ```php 104 | class User 105 | { 106 | use LaravelDoctrine\ORM\Notifications\Notifiable; 107 | } 108 | ``` 109 | 110 | ### Custom Entity Manager 111 | 112 | By default the Doctrine Channel will find the first suitable EM to persist the Notification by using the `ManagerRegistry`. 113 | 114 | If you want more control over it, you can specify it inside your notifiable entity (most likely your User entity). Usage of the `LaravelDoctrine\ORM\Notifications\Notifiable` is required. 115 | 116 | ```php 117 | public function routeNotificationForDoctrine() 118 | { 119 | return 'custom'; 120 | } 121 | ``` 122 | -------------------------------------------------------------------------------- /orm/passwords.md: -------------------------------------------------------------------------------- 1 | # Password resets 2 | 3 | Most web applications provide a way for users to reset their forgotten passwords. Rather than forcing you to re-implement this on each application, 4 | Laravel provides convenient methods for sending password reminders and performing password resets. 5 | 6 | First off you have to replace Laravel's `PasswordResetServiceProvider` in `config/app.php` by `LaravelDoctrine\ORM\Auth\Passwords\PasswordResetServiceProvider`. This will make sure the querying is handled by Doctrine. 7 | 8 | To get started, verify that your `User` model implements the `Illuminate\Contracts\Auth\CanResetPassword` contract. You can use the `Illuminate\Auth\Passwords\CanResetPassword` 9 | trait, which provides the methods the interface requires. The trait assumes your `email` property is called `email`. 10 | 11 | Read more about the usage in the [Laravel documentation](https://laravel.com/docs/passwords) 12 | -------------------------------------------------------------------------------- /orm/repositories.md: -------------------------------------------------------------------------------- 1 | # Repositories 2 | 3 | The Repository Design Pattern is one of the most useful and most widely applicable design patterns ever invented. 4 | It works as an abstraction for your persistence layer, giving you a place to write collecting logic, build queries, etc. 5 | 6 | Repositories are usually modeled as collections to abstract away persistence lingo, so it is very common to see methods 7 | like `find($id)`, `findByName("Patrick")`, as if your entities would be in a `Collection` object instead of a database. 8 | 9 | Doctrine comes with a generic `Doctrine\Common\Persistence\ObjectRepository` interface that lets you easily find one, 10 | many or all entities by ID, by an array of filters or by complex `Criteria`, and an implementation of it in 11 | `Doctrine\ORM\EntityRepository`. 12 | 13 | ## Getting a repository instance 14 | 15 | The easiest way to get a repository is to let the EntityManager generate one for the Entity you want: 16 | 17 | ```php 18 | $repository = EntityManager::getRepository(Scientist::class); 19 | ``` 20 | 21 | This will generate an instance of the `Doctrine\ORM\EntityRepository`, a generic implementation ready to be queried for 22 | the class that was given to it. 23 | 24 | ## Injecting repositories 25 | 26 | You can inject generic repositories by using Laravel's [contextual binding](https://laravel.com/docs/container#contextual-binding). 27 | 28 | ```php 29 | scientists = $scientists; 44 | } 45 | } 46 | 47 | // Then, in one of your ServiceProviders 48 | use App\Entities\Research\Laboratory; 49 | use App\Entities\Research\Scientist; 50 | use Doctrine\Common\Persistence\ObjectRepository; 51 | 52 | class AppServiceProvider 53 | { 54 | public function register() 55 | { 56 | $this->app 57 | ->when(Laboratory::class) 58 | ->needs(ObjectRepository::class) 59 | ->give(function(){ 60 | return EntityManager::getRepository(Scientist::class); 61 | }); 62 | } 63 | } 64 | ``` 65 | 66 | ## Extending repositories 67 | 68 | If you want to have more control over these repositories, instead of always calling it on the EntityManager, you can 69 | create your own repository class. When we bind this concrete repository to an interface, it also makes that we can 70 | easily swap the data storage behind them. It also makes testing easier, because we can easily swap the concrete 71 | implementation for a mock. 72 | 73 | Given we have a ScientistRepository: 74 | 75 | ```php 76 | findBy(['name' => $name]); 124 | } 125 | } 126 | 127 | // Then, in one of your ServiceProviders 128 | use App\Entities\Research\Scientist; 129 | 130 | class AppServiceProvider 131 | { 132 | public function register() 133 | { 134 | $this->app->bind(ScientistRepository::class, function($app) { 135 | // This is what Doctrine's EntityRepository needs in its constructor. 136 | return new DoctrineScientistRepository( 137 | $app['em'], 138 | $app['em']->getClassMetaData(Scientist::class) 139 | ); 140 | }); 141 | } 142 | } 143 | ``` 144 | 145 | ### Reusing repositories through composition 146 | 147 | Sometimes inheritance may not be your preferred way of reusing a library. If you'd rather decouple yourself from its 148 | implementation, if you need a different one or if you are writing a library and don't want to force inheritance on your 149 | consumers, you may choose to reuse Doctrine's generic repository implementation through *composition* instead. 150 | 151 | ```php 152 | genericRepository = $genericRepository; 163 | } 164 | 165 | public function find($id) 166 | { 167 | return $this->genericRepository->find($id); 168 | } 169 | 170 | public function findByName($name) 171 | { 172 | return $this->genericRepository->findBy(['name' => $name]); 173 | } 174 | } 175 | 176 | // Then, in one of your ServiceProviders 177 | use App\Entities\Research\Scientist; 178 | 179 | class AppServiceProvider 180 | { 181 | public function register() 182 | { 183 | $this->app->bind(ScientistRepository::class, function(){ 184 | return new DoctrineScientistRepository( 185 | EntityManager::getRepository(Scientist::class) 186 | ); 187 | }); 188 | } 189 | } 190 | ``` 191 | 192 | This method gives you total control over your Repository API. If, for example, you don't want to allow fetching all 193 | Scientist, you simply don't add that method to the interface / implementation, while inheriting the generic Doctrine 194 | repository would force the `findAll()` method on to your `ScientistRepository` API. 195 | 196 | ## Using repositories 197 | 198 | Inside your controller (or any object that will be constructed by Laravel), you can now inject your repository interface: 199 | 200 | ```php 201 | 202 | class ExampleController extends Controller 203 | { 204 | private $scientists; 205 | 206 | public function __construct(ScientistRepository $scientists) 207 | { 208 | $this->scientists = $scientists; 209 | } 210 | 211 | public function index() 212 | { 213 | $articles = $this->scientists->findAll(); 214 | } 215 | 216 | } 217 | ``` 218 | 219 | More about the EntityRepository: http://www.doctrine-project.org/api/orm/2.5/class-Doctrine.ORM.EntityRepository.html 220 | 221 | Learning more about the Repository Pattern: http://shawnmc.cool/the-repository-pattern 222 | 223 | ### Pagination 224 | 225 | If you want to add easy pagination, you can add the `LaravelDoctrine\ORM\Pagination\PaginatesFromRequest` trait to your repositories. It offers two methods: `paginateAll($perPage = 15, $pageName = 'page')` and `paginate($query, $perPage, $pageName = 'page', $fetchJoinCollection = true)`. 226 | 227 | `paginateAll` will work out of the box, and will return all (non-deleted, when soft-deletes are enabled) entities inside Laravel's `LengthAwarePaginator`. 228 | 229 | If you want to add pagination to your custom queries, you will have to pass the query object through `paginate()` 230 | 231 | ```php 232 | public function paginateAllPublishedScientists($perPage = 15, $pageName = 'page') 233 | { 234 | $builder = $this->createQueryBuilder('o'); 235 | $builder->where('o.status = 1'); 236 | 237 | return $this->paginate($builder->getQuery(), $perPage, $pageName); 238 | } 239 | ``` 240 | 241 | The `PaginatesFromRequest` trait uses Laravel's `Request` object to fetch current page, just as `Eloquent` does by default. If this doesn't fit your scenario, you can also take advantage of pagination in Doctrine with the `LaravelDoctrine\ORM\Pagination\PaginatesFromParams` trait: 242 | 243 | ```php 244 | namespace App\Repositories; 245 | 246 | use Illuminate\Contracts\Pagination\LengthAwarePaginator; 247 | use LaravelDoctrine\ORM\Pagination\PaginatesFromParams; 248 | 249 | class DoctrineScientistRepository 250 | { 251 | use PaginatesFromParams; 252 | 253 | /** 254 | * @return Scientist[]|LengthAwarePaginator 255 | */ 256 | public function all(int $limit = 8, int $page = 1): LengthAwarePaginator 257 | { 258 | // paginateAll is already public, you may use it directly as well. 259 | return $this->paginateAll($limit, $page); 260 | } 261 | 262 | /** 263 | * @return Scientist[]|LengthAwarePaginator 264 | */ 265 | public function findByName(string $name, int $limit = 8, int $page = 1): LengthAwarePaginator 266 | { 267 | $query = $this->createQueryBuilder('s') 268 | ->where('s.name LIKE :name') 269 | ->orderBy('s.name', 'asc') 270 | ->setParameter('name', "%$name%") 271 | ->getQuery(); 272 | 273 | return $this->paginate($query, $limit, $page); 274 | } 275 | } 276 | ``` 277 | -------------------------------------------------------------------------------- /orm/testing.md: -------------------------------------------------------------------------------- 1 | # Testing 2 | 3 | - [Entity Factories](#entity-factories) 4 | 5 | 6 | ### Entity Factories 7 | 8 | When testing or demonstrating your application you may need to insert some dummy data into the database. To help with 9 | this Laravel Doctrine provides Entity Factories, which are similar to Laravel's Model Factories. These allow you 10 | to define values for each property of your Entities and quickly generate many of them. 11 | 12 | Place your Factory files in `database/factories`. Each file in this directory will be run with the variable `$factory` 13 | being an instance of `LaravelDoctrine\ORM\Testing\Factory`. 14 | 15 | #### Entity Definitions 16 | 17 | To define an Entity simple pass the factory its classname and a callback which details what its properties should be set 18 | to 19 | 20 | ```php 21 | $factory->define(App\Entities\User::class, function(Faker\Generator $faker) { 22 | return [ 23 | 'name' => $faker->name, 24 | 'emailAddress' => $faker->email 25 | ]; 26 | }); 27 | ``` 28 | 29 | Faker allows you to get Entities with different values each time you generate one. Note that as usual with Doctrine, 30 | we reference class property names, and not database columns! 31 | 32 | The factory allows you to define multiple types of the same Entity using `defineAs` 33 | 34 | ```php 35 | $factory->defineAs(App\Entities\User::class, 'admin', function(Faker\Generator $faker) { 36 | return [ 37 | 'name' => $faker->name, 38 | 'emailAddress' => $faker->email, 39 | 'isAdmin' => true 40 | ]; 41 | }); 42 | ``` 43 | 44 | #### Using Entity Factories in Seeds and Tests 45 | 46 | After you have defined your Entities you can then use the factory to generate them or insert them directly into the 47 | database. 48 | 49 | A helper named `entity()` is defined to aid you in this or you can use the factory directly. 50 | 51 | To make an instance of an Entity (but not persist it to the database), call 52 | 53 | ```php 54 | entity(App\Entities\User::class)->make(); 55 | 56 | // OR 57 | 58 | $factory->of(App\Entities\User::class)->make(); 59 | ``` 60 | 61 | If you need an Entity of a specific type (see the 'admin' example above) 62 | 63 | ```php 64 | entity(App\Entities\User::class, 'admin')->make(); 65 | 66 | // OR 67 | 68 | $factory->of(App\Entities\User::class, 'admin')->make(); 69 | ``` 70 | 71 | If you need multiple Entities 72 | 73 | ```php 74 | entity(App\Entities\User::class, 2)->make(); 75 | entity(App\Entities\User::class, 'admin', 2)->make(); 76 | 77 | // OR 78 | 79 | $factory->of(App\Entities\User::class)->times(2)->make(); 80 | ``` 81 | 82 | These methods will return an instance of `Illuminate\Support\Collection` containing your Entities. 83 | 84 | If you want to instead persist the Entity before being given an instance of it, replace calls to `->make()` with `->create()`, 85 | e.g: 86 | 87 | ```php 88 | entity(App\Entities\User::class)->create(); // The User is now in the database 89 | ``` 90 | 91 | #### Passing Extra Attributes to Factories 92 | 93 | Factory definition callbacks may receive an optional second argument of attributes. 94 | 95 | ```php 96 | $factory->define(App\Entities\User::class, function(Faker\Generator $faker, array $attributes) { 97 | return [ 98 | 'name' => isset($attributes['name']) ? $attributes['name'] : $faker->name, 99 | 'emailAddress' => $faker->email 100 | ]; 101 | }); 102 | 103 | $user = entity(App\Entities\User::class)->make(['name' => 'Taylor']); 104 | 105 | // $user->getName() = 'Taylor' 106 | ``` 107 | -------------------------------------------------------------------------------- /orm/troubleshooting.md: -------------------------------------------------------------------------------- 1 | # Troubleshooting 2 | 3 | Common issues that you may run into when configuring or running Laravel Doctrine. 4 | 5 | ## The DatabaseTransactions trait is not working for tests 6 | 7 | You will need to use a new trait instead of the default Laravel trait. Here is an example of an implementation: 8 | 9 | ``` 10 | beginTransaction(); 21 | } 22 | 23 | public function tearDownDoctrineDatabaseTransactions(): void 24 | { 25 | EntityManager::getConnection()->rollBack(); 26 | } 27 | } 28 | ``` 29 | 30 | If you would like to also use `assertDatabaseHas` in your tests, you need to tell Laravel to use the same connection as Doctrine is using so that it can find rows that have not been committed in a transaction: 31 | 32 | ``` 33 | $pdo = app()->make(\Doctrine\ORM\EntityManagerInterface::class)->getConnection() 34 | ->getWrappedConnection(); 35 | 36 | app()->make(\Illuminate\Database\ConnectionInterface::class)->setPdo($pdo); 37 | ``` 38 | 39 | ## ErrorException: require(.../storage/proxies/__CG__Entity.php): Failed to open stream: No such file or directory 40 | 41 | Proxies need to be generated before they can be used. You can generate the proxies manually using the `php artisan doctrine:generate:proxies` command, or you can enable proxy auto generation in your `doctrine.php` config file. By default, you can set the `DOCTRINE_PROXY_AUTOGENERATE` environment value to true to enable auto generation. 42 | 43 | Note: Proxy auto generation should always be disabled in production for performance reasons. -------------------------------------------------------------------------------- /orm/upgrade.md: -------------------------------------------------------------------------------- 1 | # Upgrade Guide 2 | 3 | - [Upgrading from older packages](#upgrade-older) 4 | - [Upgrading from atrauzzi/laravel-doctrine](#upgrade-atrauzzi) 5 | - [Upgrading from mitchellvanw/laravel-doctrine](#upgrade-mitchellvanw) 6 | 7 | ## Upgrading from older packages 8 | 9 | An artisan command was added to make the upgrade path a bit lighter. 10 | 11 | `php artisan doctrine:config:convert [author] [--source-file] [--dest-path]` 12 | 13 | To learn more about flags and how it works see [Migrating Config Files From Other Packages](/docs/{{version}}/orm/config-migrator). 14 | 15 | > **NOTE:** This tool is meant to be used AS A STARTING POINT for converting your configuration. In most cases you will still need to inspect and modify the generated configuration to suite your needs. 16 | 17 | ## Upgrading from atrauzzi/laravel-doctrine 18 | 19 | If you have used [atrauzzi/laravel-doctrine](https://github.com/atrauzzi/laravel-doctrine) in the past. You can easily update your config file using the following artisan command, a new `doctrine.php` config file will be generated based on your old config file: 20 | 21 | `php artisan doctrine:config:convert atrauzzi [--source-file] [--dest-path]` 22 | 23 | ## Upgrading from mitchellvanw/laravel-doctrine 24 | 25 | If you have used [mitchellvanw/laravel-doctrine](https://github.com/mitchellvanw/laravel-doctrine) in the past. You can easily update your config file using the following artisan command, a new `doctrine.php` config file will be generated based on your old config file: 26 | 27 | `php artisan doctrine:config:convert mitchell [--source-file] [--dest-path]` 28 | -------------------------------------------------------------------------------- /orm/validation.md: -------------------------------------------------------------------------------- 1 | # Validation 2 | 3 | Laravel provides several different approaches to validate your application's incoming data. By default, Laravel's base controller class uses a ValidatesRequests trait which provides a 4 | convenient method to validate incoming HTTP request with a variety of powerful validation rules. 5 | 6 | Both `unique` and `exists` validation rules, require the database to be queried. This packages provides this integration. 7 | 8 | ## Unique 9 | 10 | The field under validation must be unique for a given Entity. If the column option is not specified, the field name will be used. 11 | 12 | |Parameter| Description| 13 | |--|--| 14 | | **entity** | fully qualified namespace of your entity | 15 | | **column** | the column that should be unqiue | 16 | | **exceptId** | the id that should be excluded from the query [optional] | 17 | | **idColumn** | alternative id column (defaults to id) [optional] | 18 | 19 | ```php 20 | /** 21 | * Store a new blog post. 22 | * 23 | * @param Request $request 24 | * @return Response 25 | */ 26 | public function store(Request $request) 27 | { 28 | $this->validate($request, [ 29 | 'username' => 'required|unique:App\Entities\User,username', 30 | ]); 31 | } 32 | ``` 33 | 34 | ### Forcing A Unique Rule To Ignore A Given ID: 35 | 36 | Sometimes, you may wish to ignore a given ID during the unique check. For example, consider an "update profile" screen that includes the user's name, e-mail address, and location. Of course, you will want to verify that the e-mail address is unique. However, if the user only changes the name field and not the e-mail field, you do not want a validation error to be thrown because the user is already the owner of the e-mail address. You only want to throw a validation error if the user provides an e-mail address that is already used by a different user. To tell the unique rule to ignore the user's ID, you may pass the ID as the third parameter: 37 | 38 | ``` 39 | 'email' => 'unique:users,email_address,'.$user->id 40 | ``` 41 | 42 | ### Adding Additional Where Clauses: 43 | 44 | You may also specify more conditions that will be added as "where" clauses to the query: 45 | 46 | ``` 47 | 'email' => 'unique:users,email_address,NULL,id,account_id,1' 48 | ``` 49 | 50 | In the rule above, only rows with an account_id of 1 would be included in the unique check. 51 | 52 | 53 | ## Exists 54 | 55 | The field under validation must exist on a given database table. 56 | 57 | |Parameter| Description| 58 | |--|--| 59 | | **entity** | fully qualified namespace of your entity | 60 | | **column** | the column that should be unqiue | 61 | | **exceptId** | the id that should be excluded from the query [optional] | 62 | | **idColumn** | alternative id column (defaults to id) [optional] | 63 | 64 | ```php 65 | /** 66 | * Store a new blog post. 67 | * 68 | * @param Request $request 69 | * @return Response 70 | */ 71 | public function update($id, Request $request) 72 | { 73 | $this->validate($request, [ 74 | 'username' => 'required|exists:App\Entities\User,username', 75 | ]); 76 | } 77 | ``` 78 | -------------------------------------------------------------------------------- /scout/index.md: -------------------------------------------------------------------------------- 1 | - [Introduction](/docs/{{version}}/scout/introduction) 2 | - [Installation](/docs/{{version}}/scout/installation) 3 | - [Indexing](/docs/{{version}}/scout/indexing) 4 | - [Searching](/docs/{{version}}/scout/searching) 5 | -------------------------------------------------------------------------------- /scout/indexing.md: -------------------------------------------------------------------------------- 1 | # Indexing 2 | 3 | ### Configuration 4 | 5 | Each Doctrine Entity is synced with a given search "index", which contains all of the searchable records for that model. 6 | In other words, you can think of each index like a MySQL table. 7 | By default, each entity will be persisted to an index matching the model's typical "table" name. 8 | Typically, this is the plural form of the model name; however, you are free to customize the model's index by overriding the `searchableAs` method on the model: 9 | 10 | ```php 11 | class PostRepository extends SearchableRepository 12 | { 13 | /** 14 | * @return string 15 | */ 16 | public function searchableAs() 17 | { 18 | return 'posts_index'; 19 | } 20 | } 21 | ``` 22 | 23 | By default, the entire entity will be serialized (based on the available getters) and will be persisted to its search index. 24 | If you would like to customize the data that is synchronized to the search index, 25 | you may override the `toSearchableArray` method on the entity: 26 | 27 | ```php 28 | class Post implements Searchable 29 | { 30 | public $id; 31 | 32 | /** 33 | * @return array 34 | */ 35 | public function toSearchableArray() 36 | { 37 | return [ 38 | 'title' => $this->title, 39 | 'content' => $this->content 40 | ]; 41 | } 42 | } 43 | ``` 44 | 45 | > Please note that currently it is required to have the primary key (`id`) of the entity marked as public to make it possible to index and search them. 46 | 47 | ### Batch indexing 48 | 49 | If you are installing Scout into an existing project, 50 | you may already have database records you need to import into your search driver. 51 | Scout provides an `import` Artisan command that you may use to import all of your existing records into your search indexes: 52 | 53 | ``` 54 | php artisan doctrine:scout:import "App\Entities\Post" 55 | ``` 56 | 57 | ### Adding entities 58 | 59 | Once you have activated the `LaravelDoctrine\Scout\SearchableExtension` extension, 60 | all you need to do is `persist` and `flush` an entity instance and it will automatically be added to your search index. 61 | 62 | ```php 63 | $post = new App\Entities\Post; 64 | 65 | // ... 66 | 67 | $em->persist($post); 68 | $em->flush(); 69 | ``` 70 | 71 | ### Updating entities 72 | 73 | To update a searchable model, you only need to update the entity instance's properties and `flush` the entity to your database. 74 | Scout will automatically persist the changes to your search index: 75 | 76 | ```php 77 | $post = $em->find(Post::class, 1); 78 | 79 | // Update the post 80 | 81 | $em->flush(); 82 | ``` 83 | 84 | ### Removing entities 85 | 86 | To remove a record from your index, simply `remove` and `flush` the entity from the database. 87 | 88 | ```php 89 | $post = $em->find(Post::class, 1); 90 | $em->remove($post); 91 | $em->flush(); 92 | ``` 93 | -------------------------------------------------------------------------------- /scout/installation.md: -------------------------------------------------------------------------------- 1 | # Installation 2 | 3 | First, install the Scout via the Composer package manager: 4 | 5 | ``` 6 | composer require laravel/scout 7 | composer require laravel-doctrine/scout 8 | ``` 9 | 10 | Next, you should add the `ScoutServiceProvider` to the `providers` array of your `config/app.php` configuration file: 11 | 12 | ```php 13 | Laravel\Scout\ScoutServiceProvider::class, 14 | LaravelDoctrine\Scout\ScoutServiceProvider::class, 15 | ``` 16 | 17 | After registering the Scout service providers, you should publish the Scout configuration using the `vendor:publish` Artisan command. This command will publish the `scout.php` configuration file to your `config` directory: 18 | 19 | ``` 20 | php artisan vendor:publish 21 | ``` 22 | 23 | The entities that should be searchable should implement `LaravelDoctrine\Scout\Searchable`. 24 | You can use the `LaravelDoctrine\Scout\Indexable` trait to provide sensible defaults to adhere to the interface. 25 | 26 | ```php 27 | app->bind(PostRepository::class, function($app) { 47 | return new DoctrinePostRepository( 48 | $app['em'], 49 | $app['em']->getClassMetadata(Post::class), 50 | $app->make(Laravel\Scout\EngineManager::class) 51 | ); 52 | }); 53 | ``` 54 | 55 | Enable the `LaravelDoctrine\Scout\SearchableExtension` in the extensions setting in `doctrine.php` config. 56 | 57 | ```php 58 | 'extensions' => [ 59 | LaravelDoctrine\Scout\SearchableExtension::class, 60 | ]; 61 | -------------------------------------------------------------------------------- /scout/introduction.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | Laravel Doctrine Scout provides a simple, driver based solution for adding full-text search to your Doctrine entities. 4 | Using entity subscribers, Scout will automatically keep your search indexes in sync with your Doctrine records. 5 | -------------------------------------------------------------------------------- /scout/searching.md: -------------------------------------------------------------------------------- 1 | # Searching 2 | 3 | You may begin searching an entity using the `search` method. 4 | The search method accepts a single string that will be used to search your models. 5 | You should then chain the `get` method onto the search query to retrieve the hydrated Doctrine Entities that match the given search query: 6 | 7 | ```php 8 | $posts = $repository->search('Star Trek')->get(); 9 | ``` 10 | 11 | You can find the other usages in the Laravel Scout docs: https://laravel.com/docs/scout 12 | --------------------------------------------------------------------------------