├── .gitattributes
├── .github
└── workflows
│ └── ci.yml
├── .gitignore
├── .php_cs
├── .scrutinizer.yml
├── LICENSE
├── README.md
├── codeclimate.yml
├── composer.json
├── lib
├── Blameable
│ └── Mapping
│ │ └── Driver
│ │ └── Fluent.php
├── FluentExtension.php
├── IpTraceable
│ └── Mapping
│ │ └── Driver
│ │ └── Fluent.php
├── Loggable
│ └── Mapping
│ │ └── Driver
│ │ └── Fluent.php
├── Sluggable
│ └── Mapping
│ │ └── Driver
│ │ └── Fluent.php
├── SoftDeleteable
│ └── Mapping
│ │ └── Driver
│ │ └── Fluent.php
├── Sortable
│ └── Mapping
│ │ └── Driver
│ │ └── Fluent.php
├── Timestampable
│ └── Mapping
│ │ └── Driver
│ │ └── Fluent.php
├── Translatable
│ └── Mapping
│ │ └── Driver
│ │ └── Fluent.php
├── Tree
│ └── Mapping
│ │ └── Driver
│ │ └── Fluent.php
└── Uploadable
│ └── Mapping
│ └── Driver
│ └── Fluent.php
├── phpunit.xml.dist
└── src
├── Buildable.php
├── Builders
├── AbstractBuilder.php
├── Builder.php
├── Delay.php
├── Embedded.php
├── Entity.php
├── EntityListeners.php
├── Field.php
├── GeneratedValue.php
├── Index.php
├── Inheritance
│ ├── AbstractInheritance.php
│ ├── Inheritance.php
│ ├── InheritanceFactory.php
│ ├── JoinedTableInheritance.php
│ └── SingleTableInheritance.php
├── LifecycleEvents.php
├── Overrides
│ ├── AssociationOverride.php
│ ├── AttributeOverride.php
│ ├── Override.php
│ └── OverrideBuilderFactory.php
├── Primary.php
├── Table.php
├── Traits
│ ├── Aliases.php
│ ├── Constraints.php
│ ├── Dates.php
│ ├── Fields.php
│ ├── Macroable.php
│ ├── Queueable.php
│ ├── QueuesMacros.php
│ └── Relations.php
└── UniqueConstraint.php
├── EmbeddableMapping.php
├── EntityMapping.php
├── Extensions
├── ExtensibleClassMetadata.php
├── ExtensibleClassMetadataFactory.php
├── Extension.php
├── Gedmo
│ ├── AbstractTrackingExtension.php
│ ├── Blameable.php
│ ├── ClosureTable.php
│ ├── GedmoBuilderHints.php
│ ├── GedmoFieldHints.php
│ ├── GedmoManyToManyHints.php
│ ├── GedmoManyToOneHints.php
│ ├── IpTraceable.php
│ ├── Locale.php
│ ├── Loggable.php
│ ├── Mappings
│ │ ├── Loggable
│ │ │ ├── AbstractLogEntryMapping.php
│ │ │ └── LogEntryMapping.php
│ │ ├── Translatable
│ │ │ ├── AbstractPersonalTranslationMapping.php
│ │ │ ├── AbstractTranslationMapping.php
│ │ │ └── TranslationMapping.php
│ │ └── Tree
│ │ │ └── AbstractClosureMapping.php
│ ├── MaterializedPath.php
│ ├── NestedSet.php
│ ├── Sluggable.php
│ ├── SoftDeleteable.php
│ ├── Sortable.php
│ ├── SortableGroup.php
│ ├── SortablePosition.php
│ ├── Timestampable.php
│ ├── Timestamps.php
│ ├── Translatable.php
│ ├── TranslationClass.php
│ ├── Tree.php
│ ├── TreeLeft.php
│ ├── TreeLevel.php
│ ├── TreePath.php
│ ├── TreePathHash.php
│ ├── TreePathSource.php
│ ├── TreeRight.php
│ ├── TreeSelfReference.php
│ ├── TreeStrategy.php
│ ├── Uploadable.php
│ ├── UploadableFile.php
│ └── Versioned.php
└── GedmoExtensions.php
├── Fluent.php
├── FluentDriver.php
├── MappedSuperClassMapping.php
├── Mappers
├── AbstractMapper.php
├── EmbeddableMapper.php
├── EntityMapper.php
├── MappedSuperClassMapper.php
├── Mapper.php
└── MapperSet.php
├── Mapping.php
└── Relations
├── AbstractRelation.php
├── AssociationCache.php
├── JoinColumn.php
├── ManyToMany.php
├── ManyToOne.php
├── OneToMany.php
├── OneToOne.php
├── Relation.php
└── Traits
├── Indexable.php
├── ManyTo.php
├── Orderable.php
├── Ownable.php
├── Owning.php
└── Primary.php
/.gitattributes:
--------------------------------------------------------------------------------
1 | /tests export-ignore
2 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 | on:
3 | schedule:
4 | - cron: '0 0 * * *'
5 | push:
6 | pull_request:
7 | jobs:
8 | tests:
9 | runs-on: 'ubuntu-latest'
10 | name: PHP ${{ matrix.php }} - Doctrine ${{ matrix.doctrine }}
11 | strategy:
12 | matrix:
13 | php: ['8.0', '8.1', '8.2']
14 | doctrine: ['2.11', '2.12', '2.13', '2.14']
15 | steps:
16 | - uses: actions/checkout@v3
17 | - name: Setup PHP
18 | uses: shivammathur/setup-php@v2
19 | with:
20 | php-version: ${{ matrix.php }}
21 | ini-values: error_reporting=E_ALL
22 | tools: phpunit, git
23 |
24 | - name: Install Composer dependencies
25 | run: rm -f composer.lock
26 |
27 | - name: Install doctrine/orm ${{ matrix.doctrine }}
28 | run: composer require --no-progress --no-scripts --no-plugins doctrine/orm "~${{ matrix.doctrine }}.0" -v
29 |
30 | - name: Update dependencies
31 | run: composer update --no-interaction
32 |
33 | - name: PHPUnit
34 | run: vendor/bin/phpunit
35 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /vendor
2 | composer.phar
3 | composer.lock
4 | .php_cs.cache
5 | .phpunit.result.cache
6 |
--------------------------------------------------------------------------------
/.php_cs:
--------------------------------------------------------------------------------
1 | exclude('vendor')
5 | ->exclude('tests')
6 | ->in(__DIR__);
7 |
8 | return Symfony\CS\Config\Config::create()
9 | ->setUsingCache(true)
10 | ->level(Symfony\CS\FixerInterface::PSR2_LEVEL)
11 | ->fixers(array(
12 | 'psr4',
13 | 'encoding',
14 | 'short_tag',
15 | 'blankline_after_open_tag',
16 | 'namespace_no_leading_whitespace',
17 | 'no_blank_lines_after_class_opening',
18 | 'single_array_no_trailing_comma',
19 | 'no_empty_lines_after_phpdocs',
20 | 'concat_with_spaces',
21 | 'eof_ending',
22 | 'ordered_use',
23 | 'extra_empty_lines',
24 | 'single_line_after_imports',
25 | 'trailing_spaces',
26 | 'remove_lines_between_uses',
27 | 'return',
28 | 'indentation',
29 | 'linefeed',
30 | 'braces',
31 | 'visibility',
32 | 'unused_use',
33 | 'whitespacy_lines',
34 | 'php_closing_tag',
35 | 'phpdoc_order',
36 | 'phpdoc_params',
37 | 'phpdoc_trim',
38 | 'phpdoc_scalar',
39 | 'short_array_syntax',
40 | 'align_double_arrow',
41 | 'align_equals',
42 | 'lowercase_constants',
43 | 'lowercase_keywords',
44 | 'multiple_use',
45 | 'line_after_namespace',
46 | ))->finder($finder);
47 |
--------------------------------------------------------------------------------
/.scrutinizer.yml:
--------------------------------------------------------------------------------
1 | tools:
2 | external_code_coverage:
3 | timeout: 600
4 | runs: 4
5 | build:
6 | environment:
7 | variables:
8 | XDEBUG_MODE: 'coverage'
9 | tests:
10 | override:
11 | -
12 | command: 'vendor/bin/phpunit --coverage-clover=phpunit-coverage.xml'
13 | coverage:
14 | file: 'phpunit-coverage.xml'
15 | format: 'php-clover'
16 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Laravel Doctrine
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Fluent Mapping Driver
2 |
3 |
4 |
5 | [](https://packagist.org/packages/laravel-doctrine/fluent)
6 | [](https://packagist.org/packages/laravel-doctrine/fluent)
7 | [](https://packagist.org/packages/laravel-doctrine/fluent)
8 | [](https://github.com/laravel-doctrine/fluent/actions?query=workflow%3ACI+branch%3A1.x)
9 |
10 | *A fluent mapping driver for Doctrine2*
11 |
12 | ```
13 | composer require laravel-doctrine/fluent
14 | ```
15 |
16 | This mapping driver allows you to manage your mappings in an Object Oriented approach, separating your entities
17 | from your mapping configuration without the need for configuration files like XML or YAML.
18 | This is done by implementing the `LaravelDoctrine\Fluent\Mapping` interface, or extending the abstract classes
19 | provided with this package for an easier use:
20 | `LaravelDoctrine\Fluent\EntityMapping`, `LaravelDoctrine\Fluent\EmbeddableMapping` or `MappedSuperClassMapping`.
21 |
22 | This package provides a fluent Builder over Doctrine's `ClassMetadataBuilder`, aimed at easing usage of
23 | Doctrine's mapping concepts in Laravel. The builder adds syntax sugar and implements the same grammar that you
24 | might use in Laravel migrations.
25 |
26 | ```php
27 | class ScientistMapping extends EntityMapping
28 | {
29 | /**
30 | * Returns the fully qualified name of the class that this mapper maps.
31 | *
32 | * @return string
33 | */
34 | public function mapFor()
35 | {
36 | return Scientist::class;
37 | }
38 |
39 | /**
40 | * Load the object's metadata through the Metadata Builder object.
41 | *
42 | * @param Fluent $builder
43 | */
44 | public function map(Fluent $builder)
45 | {
46 | $builder->increments('id');
47 | $builder->embed(Name::class, 'name');
48 |
49 | $builder->hasMany(Theory::class, 'theories')->ownedBy('scientist');
50 | }
51 | }
52 | ```
53 |
54 |
--------------------------------------------------------------------------------
/codeclimate.yml:
--------------------------------------------------------------------------------
1 | languages:
2 | PHP: true
3 | exclude_paths:
4 | - "tests/*"
5 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "laravel-doctrine/fluent",
3 | "description": "A fluent PHP mapping driver for Doctrine2.",
4 | "license": "MIT",
5 | "keywords": [
6 | "doctrine",
7 | "laravel",
8 | "orm",
9 | "data mapper",
10 | "database",
11 | "mappings",
12 | "mapping driver",
13 | "fluent"
14 | ],
15 | "authors": [
16 | {
17 | "name": "Guido Contreras Woda",
18 | "email": "guiwoda@gmail.com"
19 | },
20 | {
21 | "name": "Patrick Brouwers",
22 | "email": "patrick@maatwebsite.nl"
23 | }
24 | ],
25 | "require": {
26 | "php": "^7.2|^8.0",
27 | "doctrine/dbal": "^2.10|^3.3",
28 | "doctrine/orm": "^2.6",
29 | "doctrine/inflector": "^1.4|^2.0",
30 | "doctrine/persistence": "^1.3.5|^2.0|^3.0"
31 | },
32 | "require-dev": {
33 | "phpunit/phpunit": "~8.0|~9.0",
34 | "mockery/mockery": "~1.0",
35 | "beberlei/doctrineextensions": "~1.0",
36 | "zf1/zend-date": "~1.12",
37 | "nesbot/carbon": "*",
38 | "gedmo/doctrine-extensions": "^2.4|^3"
39 | },
40 | "autoload": {
41 | "psr-4": {
42 | "LaravelDoctrine\\Fluent\\": "src/",
43 | "Gedmo\\": "lib/"
44 | }
45 | },
46 | "autoload-dev": {
47 | "psr-4": {
48 | "Tests\\": "tests/"
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/lib/Blameable/Mapping/Driver/Fluent.php:
--------------------------------------------------------------------------------
1 | getExtension(
39 | $this->getExtensionName()
40 | ));
41 | }
42 |
43 | /**
44 | * Make sure the original driver is Fluent.
45 | *
46 | * @param MappingDriver $driver
47 | *
48 | * @return void
49 | */
50 | public function setOriginalDriver($driver)
51 | {
52 | $this->originalDriver = $this->extractFluentDriver($driver);
53 | }
54 |
55 | /**
56 | * @param MappingDriver $driver
57 | *
58 | * @return FluentDriver
59 | */
60 | private function extractFluentDriver(MappingDriver $driver)
61 | {
62 | if ($driver instanceof FluentDriver) {
63 | return $driver;
64 | }
65 |
66 | if ($driver instanceof MappingDriverChain) {
67 | $default = $driver->getDefaultDriver();
68 | if ($default instanceof FluentDriver) {
69 | return $default;
70 | }
71 |
72 | foreach ($driver->getDrivers() as $namespace => $driver) {
73 | if ($driver instanceof FluentDriver) {
74 | return $driver;
75 | }
76 | }
77 | }
78 |
79 | throw new \UnexpectedValueException('Fluent driver not found in the driver chain.');
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/lib/IpTraceable/Mapping/Driver/Fluent.php:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 |
15 | ./tests/
16 |
17 |
18 |
19 |
20 | ./src
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/src/Buildable.php:
--------------------------------------------------------------------------------
1 | builder = $builder;
29 | $this->namingStrategy = $namingStrategy ?: new DefaultNamingStrategy();
30 | }
31 |
32 | /**
33 | * @return ClassMetadataBuilder
34 | */
35 | public function getBuilder()
36 | {
37 | return $this->builder;
38 | }
39 |
40 | /**
41 | * @return ClassMetadata
42 | */
43 | public function getClassMetadata()
44 | {
45 | return $this->builder->getClassMetadata();
46 | }
47 |
48 | /**
49 | * @return NamingStrategy
50 | */
51 | public function getNamingStrategy()
52 | {
53 | return $this->namingStrategy;
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/Builders/Builder.php:
--------------------------------------------------------------------------------
1 | disallowInEmbeddedClasses();
32 |
33 | $table = new Table($this->builder, $name);
34 |
35 | $this->callbackAndQueue($table, $callback);
36 |
37 | return $table;
38 | }
39 |
40 | /**
41 | * {@inheritdoc}
42 | */
43 | public function entity(callable $callback = null)
44 | {
45 | $this->disallowInEmbeddedClasses();
46 |
47 | $entity = new Entity($this->builder, $this->namingStrategy);
48 |
49 | $this->callIfCallable($callback, $entity);
50 |
51 | return $entity;
52 | }
53 |
54 | /**
55 | * {@inheritdoc}
56 | */
57 | public function inheritance($type, callable $callback = null)
58 | {
59 | $inheritance = Inheritance\InheritanceFactory::create($type, $this->builder);
60 |
61 | $this->callIfCallable($callback, $inheritance);
62 |
63 | return $inheritance;
64 | }
65 |
66 | /**
67 | * {@inheritdoc}
68 | */
69 | public function singleTableInheritance(callable $callback = null)
70 | {
71 | return $this->inheritance(Inheritance\Inheritance::SINGLE, $callback);
72 | }
73 |
74 | /**
75 | * {@inheritdoc}
76 | */
77 | public function joinedTableInheritance(callable $callback = null)
78 | {
79 | return $this->inheritance(Inheritance\Inheritance::JOINED, $callback);
80 | }
81 |
82 | /**
83 | * {@inheritdoc}
84 | */
85 | public function embed($embeddable, $field = null, callable $callback = null)
86 | {
87 | $embedded = new Embedded(
88 | $this->builder,
89 | $this->namingStrategy,
90 | $this->guessSingularField($embeddable, $field),
91 | $embeddable
92 | );
93 |
94 | $this->callbackAndQueue($embedded, $callback);
95 |
96 | return $embedded;
97 | }
98 |
99 | /**
100 | * {@inheritdoc}
101 | */
102 | public function override($name, callable $callback)
103 | {
104 | $override = new Overrides\Override(
105 | $this->getBuilder(),
106 | $this->getNamingStrategy(),
107 | $name,
108 | $callback
109 | );
110 |
111 | $this->queue($override);
112 |
113 | return $override;
114 | }
115 |
116 | /**
117 | * {@inheritdoc}
118 | */
119 | public function events(callable $callback = null)
120 | {
121 | $events = new LifecycleEvents($this->builder);
122 |
123 | $this->callbackAndQueue($events, $callback);
124 |
125 | return $events;
126 | }
127 |
128 | /**
129 | * {@inheritdoc}
130 | */
131 | public function listen(callable $callback = null)
132 | {
133 | $events = new EntityListeners($this->builder);
134 |
135 | $this->callbackAndQueue($events, $callback);
136 |
137 | return $events;
138 | }
139 |
140 | /**
141 | * {@inheritdoc}
142 | */
143 | public function isEmbeddedClass()
144 | {
145 | return $this->builder->getClassMetadata()->isEmbeddedClass;
146 | }
147 |
148 | /**
149 | * @param string $name
150 | * @param callable|null $callback
151 | *
152 | * @return Field
153 | */
154 | protected function setArray($name, callable $callback = null)
155 | {
156 | return $this->field(Types::ARRAY, $name, $callback);
157 | }
158 |
159 | /**
160 | * @param string $method
161 | * @param array $params
162 | *
163 | * @return mixed
164 | */
165 | public function __call($method, $params)
166 | {
167 | // Workaround for reserved keywords
168 | if ($method === 'array') {
169 | return call_user_func_array([$this, 'setArray'], $params);
170 | }
171 |
172 | if ($this->hasMacro($method)) {
173 | return $this->queueMacro($method, $params);
174 | }
175 |
176 | throw new InvalidArgumentException('Fluent builder method ['.$method.'] does not exist');
177 | }
178 |
179 | /**
180 | * {@inheritdoc}
181 | */
182 | protected function disallowInEmbeddedClasses($message = '')
183 | {
184 | if ($this->isEmbeddedClass()) {
185 | throw new LogicException($message);
186 | }
187 | }
188 | }
189 |
--------------------------------------------------------------------------------
/src/Builders/Delay.php:
--------------------------------------------------------------------------------
1 | embeddable = $embeddable;
37 | $this->relation = $relation;
38 | }
39 |
40 | /**
41 | * @param string|null $prefix
42 | *
43 | * @return Embedded
44 | */
45 | public function prefix($prefix)
46 | {
47 | $this->columnPrefix = $prefix;
48 |
49 | return $this;
50 | }
51 |
52 | /**
53 | * @return Embedded
54 | */
55 | public function noPrefix()
56 | {
57 | $this->columnPrefix = false;
58 |
59 | return $this;
60 | }
61 |
62 | /**
63 | * Execute the build process.
64 | */
65 | public function build()
66 | {
67 | $this->builder->addEmbedded(
68 | $this->relation,
69 | $this->embeddable,
70 | $this->columnPrefix
71 | );
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/src/Builders/Entity.php:
--------------------------------------------------------------------------------
1 | builder->setCustomRepositoryClass($class);
24 |
25 | return $this;
26 | }
27 |
28 | /**
29 | * @return Entity
30 | */
31 | public function readOnly()
32 | {
33 | $this->builder->setReadOnly();
34 |
35 | return $this;
36 | }
37 |
38 | /**
39 | * Enables second-level cache on this entity.
40 | * If you want to enable second-level cache,
41 | * you must enable it on the EntityManager configuration.
42 | * Depending on the cache mode selected, you may also need to configure
43 | * lock modes.
44 | *
45 | * @param int $usage Cache mode. use ClassMetadataInfo::CACHE_USAGE_* constants.
46 | * Defaults to READ_ONLY mode.
47 | * @param string|null $region The cache region to be used. Doctrine will use a default region
48 | * for each entity, if none is provided.
49 | *
50 | * @return Entity
51 | *
52 | * @see http://doctrine-orm.readthedocs.org/en/latest/reference/second-level-cache.html
53 | */
54 | public function cacheable($usage = ClassMetadataInfo::CACHE_USAGE_READ_ONLY, $region = null)
55 | {
56 | $meta = $this->builder->getClassMetadata();
57 | $meta->enableCache(compact('usage', $region === null ? [] : 'region'));
58 |
59 | return $this;
60 | }
61 |
62 | /**
63 | * @param string $method
64 | * @param array $params
65 | *
66 | * @return mixed
67 | */
68 | public function __call($method, $params)
69 | {
70 | if ($this->hasMacro($method)) {
71 | return $this->queueMacro($method, $params);
72 | }
73 |
74 | throw new \InvalidArgumentException('Fluent builder method ['.$method.'] does not exist');
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/src/Builders/EntityListeners.php:
--------------------------------------------------------------------------------
1 | [],
37 | Events::postRemove => [],
38 | Events::prePersist => [],
39 | Events::postPersist => [],
40 | Events::preUpdate => [],
41 | Events::postUpdate => [],
42 | Events::postLoad => [],
43 | Events::loadClassMetadata => [],
44 | Events::onClassMetadataNotFound => [],
45 | Events::preFlush => [],
46 | Events::onFlush => [],
47 | Events::postFlush => [],
48 | Events::onClear => [],
49 | ];
50 |
51 | /**
52 | * LifecycleEvents constructor.
53 | *
54 | * @param ClassMetadataBuilder $builder
55 | */
56 | public function __construct(ClassMetadataBuilder $builder)
57 | {
58 | $this->builder = $builder;
59 | }
60 |
61 | /**
62 | * Magically call all methods that match an event name.
63 | *
64 | * @param string $event
65 | * @param array $args
66 | *
67 | * @throws InvalidArgumentException
68 | *
69 | * @return LifecycleEvents
70 | */
71 | public function __call($event, $args)
72 | {
73 | if (array_key_exists($event, $this->events)) {
74 | array_unshift($args, $event);
75 |
76 | return call_user_func_array([$this, 'add'], $args);
77 | }
78 |
79 | throw new InvalidArgumentException('Fluent builder method ['.$event.'] does not exist');
80 | }
81 |
82 | /**
83 | * @param string $event
84 | * @param string $class
85 | * @param string|null $method
86 | *
87 | * @return EntityListeners
88 | */
89 | private function add($event, $class, $method = null)
90 | {
91 | $this->events[$event][] = [
92 | 'class' => $class,
93 | 'method' => $method ?: $event,
94 | ];
95 |
96 | return $this;
97 | }
98 |
99 | /**
100 | * Execute the build process.
101 | */
102 | public function build()
103 | {
104 | foreach ($this->events as $event => $listeners) {
105 | foreach ($listeners as $listener) {
106 | $this->builder->getClassMetadata()->addEntityListener($event, $listener['class'], $listener['method']);
107 | }
108 | }
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/src/Builders/GeneratedValue.php:
--------------------------------------------------------------------------------
1 | builder = $builder;
53 | $this->classMetadata = $classMetadata;
54 | }
55 |
56 | /**
57 | * Tells Doctrine to pick the strategy that is preferred by the used database platform. The preferred strategies
58 | * are IDENTITY for MySQL, SQLite, MsSQL and SQL Anywhere and SEQUENCE for Oracle and PostgreSQL. This strategy
59 | * provides full portability.
60 | *
61 | * @param string|null $name
62 | * @param string|null $initial
63 | * @param string|null $size
64 | *
65 | * @return $this
66 | */
67 | public function auto($name = null, $initial = null, $size = null)
68 | {
69 | $this->strategy = 'AUTO';
70 | $this->customize($name, $initial, $size);
71 |
72 | return $this;
73 | }
74 |
75 | /**
76 | * Tells Doctrine to use a database sequence for ID generation. This strategy does currently not provide full
77 | * portability. Sequences are supported by Oracle, PostgreSql and SQL Anywhere.
78 | *
79 | * @param string|null $name
80 | * @param string|null $initial
81 | * @param string|null $size
82 | *
83 | * @return $this
84 | */
85 | public function sequence($name = null, $initial = null, $size = null)
86 | {
87 | $this->strategy = 'SEQUENCE';
88 | $this->customize($name, $initial, $size);
89 |
90 | return $this;
91 | }
92 |
93 | /**
94 | * Tells Doctrine to use special identity columns in the database that generate a value on insertion of a row.
95 | * This strategy does currently not provide full portability and is supported by the following platforms:
96 | * MySQL/SQLite/SQL Anywhere (AUTO_INCREMENT), MSSQL (IDENTITY) and PostgreSQL (SERIAL).
97 | *
98 | * @return $this
99 | */
100 | public function identity()
101 | {
102 | $this->strategy = 'IDENTITY';
103 |
104 | return $this;
105 | }
106 |
107 | /**
108 | * Tells Doctrine to use the built-in Universally Unique Identifier generator.
109 | * This strategy provides full portability.
110 | *
111 | * @return $this
112 | */
113 | public function uuid()
114 | {
115 | $this->strategy = 'UUID';
116 |
117 | return $this;
118 | }
119 |
120 | /**
121 | * Tells Doctrine that the identifiers are assigned (and thus generated) by your code. The assignment must take
122 | * place before a new entity is passed to EntityManager#persist.
123 | * NONE is the same as leaving off the @GeneratedValue entirely.
124 | *
125 | * @return $this
126 | */
127 | public function none()
128 | {
129 | $this->strategy = 'NONE';
130 |
131 | return $this;
132 | }
133 |
134 | /**
135 | * Tells Doctrine to use a custom Generator class to generate identifiers.
136 | * The given class must extend \Doctrine\ORM\Id\AbstractIdGenerator.
137 | *
138 | * @param string $generatorClass
139 | *
140 | * @return $this
141 | */
142 | public function custom($generatorClass)
143 | {
144 | $this->strategy = 'CUSTOM';
145 | $this->generator = $generatorClass;
146 |
147 | return $this;
148 | }
149 |
150 | /**
151 | * @param string|null $name
152 | * @param string|null $initial
153 | * @param string|null $size
154 | */
155 | private function customize($name, $initial, $size)
156 | {
157 | $this->name = $name ?: $this->name;
158 | $this->initial = $initial ?: $this->initial;
159 | $this->size = $size ?: $this->size;
160 | }
161 |
162 | /**
163 | * Execute the build process.
164 | */
165 | public function build()
166 | {
167 | $this->builder->generatedValue($this->strategy);
168 |
169 | if ($this->name) {
170 | $this->builder->setSequenceGenerator($this->name, $this->size, $this->initial);
171 | }
172 |
173 | if ($this->generator) {
174 | $this->classMetadata->setCustomGeneratorDefinition(['class' => $this->generator]);
175 | }
176 | }
177 | }
178 |
--------------------------------------------------------------------------------
/src/Builders/Index.php:
--------------------------------------------------------------------------------
1 | builder = $builder;
44 | $this->columns = $columns;
45 | }
46 |
47 | /**
48 | * Execute the build process.
49 | */
50 | public function build()
51 | {
52 | $this->builder->addIndex(
53 | $this->getColumns(),
54 | $this->getName()
55 | );
56 | }
57 |
58 | /**
59 | * @param string $name
60 | *
61 | * @return $this
62 | */
63 | public function name($name)
64 | {
65 | $this->name = $name;
66 |
67 | return $this;
68 | }
69 |
70 | /**
71 | * @return string[]
72 | */
73 | public function getColumns()
74 | {
75 | return $this->columns;
76 | }
77 |
78 | /**
79 | * @return string
80 | */
81 | public function getName()
82 | {
83 | return $this->name ?: $this->generateIndexName();
84 | }
85 |
86 | /**
87 | * @return string
88 | */
89 | protected function generateIndexName()
90 | {
91 | $table = $this->builder->getClassMetadata()->getTableName();
92 |
93 | return $table.$this->separator.implode($this->separator, $this->getColumns()).$this->separator.$this->suffix;
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/src/Builders/Inheritance/AbstractInheritance.php:
--------------------------------------------------------------------------------
1 | builder = $builder;
24 | $this->setType();
25 | }
26 |
27 | /**
28 | * Set inheritance type.
29 | */
30 | abstract protected function setType();
31 |
32 | /**
33 | * Add the discriminator column.
34 | *
35 | * @param string $column
36 | * @param string $type
37 | * @param int $length
38 | *
39 | * @return Inheritance
40 | */
41 | public function column($column, $type = 'string', $length = 255)
42 | {
43 | $this->builder->setDiscriminatorColumn($column, $type, $length);
44 |
45 | return $this;
46 | }
47 |
48 | /**
49 | * @param string $name
50 | * @param string|null $class
51 | *
52 | * @return Inheritance
53 | */
54 | public function map($name, $class = null)
55 | {
56 | if (is_array($name)) {
57 | foreach ($name as $name => $class) {
58 | $this->map($name, $class);
59 | }
60 |
61 | return $this;
62 | }
63 |
64 | $this->builder->addDiscriminatorMapClass($name, $class);
65 |
66 | return $this;
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/src/Builders/Inheritance/Inheritance.php:
--------------------------------------------------------------------------------
1 | JoinedTableInheritance::class,
15 | 'SINGLE_TABLE' => SingleTableInheritance::class,
16 | Inheritance::SINGLE => SingleTableInheritance::class,
17 | Inheritance::JOINED => JoinedTableInheritance::class,
18 | ];
19 |
20 | /**
21 | * @param string $type
22 | * @param ClassMetadataBuilder $builder
23 | *
24 | * @return Inheritance
25 | */
26 | public static function create($type, ClassMetadataBuilder $builder)
27 | {
28 | if (isset(static::$map[$type])) {
29 | return new static::$map[$type]($builder);
30 | }
31 |
32 | throw new InvalidArgumentException("Inheritance type [{$type}] does not exist. SINGLE_TABLE and JOINED are support");
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/Builders/Inheritance/JoinedTableInheritance.php:
--------------------------------------------------------------------------------
1 | builder->setJoinedTableInheritance();
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/Builders/Inheritance/SingleTableInheritance.php:
--------------------------------------------------------------------------------
1 | builder->setSingleTableInheritance();
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/Builders/LifecycleEvents.php:
--------------------------------------------------------------------------------
1 | [],
32 | Events::postRemove => [],
33 | Events::prePersist => [],
34 | Events::postPersist => [],
35 | Events::preUpdate => [],
36 | Events::postUpdate => [],
37 | Events::postLoad => [],
38 | Events::preFlush => [],
39 | ];
40 |
41 | /**
42 | * LifecycleEvents constructor.
43 | *
44 | * @param ClassMetadataBuilder $builder
45 | */
46 | public function __construct(ClassMetadataBuilder $builder)
47 | {
48 | $this->builder = $builder;
49 | }
50 |
51 | /**
52 | * Magically call all methods that match an event name.
53 | *
54 | * @param string $method
55 | * @param array $args
56 | *
57 | * @throws InvalidArgumentException
58 | *
59 | * @return LifecycleEvents
60 | */
61 | public function __call($method, $args)
62 | {
63 | if (array_key_exists($method, $this->events)) {
64 | array_unshift($args, $method);
65 |
66 | return call_user_func_array([$this, 'add'], $args);
67 | }
68 |
69 | throw new InvalidArgumentException('Fluent builder method ['.$method.'] does not exist');
70 | }
71 |
72 | /**
73 | * @param string $event
74 | * @param string $method
75 | *
76 | * @return LifecycleEvents
77 | */
78 | private function add($event, $method)
79 | {
80 | $this->events[$event][] = $method;
81 |
82 | return $this;
83 | }
84 |
85 | /**
86 | * Execute the build process.
87 | */
88 | public function build()
89 | {
90 | foreach ($this->events as $event => $methods) {
91 | foreach ($methods as $method) {
92 | $this->builder->addLifecycleEvent($method, $event);
93 | }
94 | }
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/src/Builders/Overrides/AssociationOverride.php:
--------------------------------------------------------------------------------
1 | ManyToOne::class,
41 | ClassMetadataInfo::MANY_TO_MANY => ManyToMany::class,
42 | ];
43 |
44 | /**
45 | * @param ClassMetadataBuilder $builder
46 | * @param NamingStrategy $namingStrategy
47 | * @param string $name
48 | * @param callable $callback
49 | */
50 | public function __construct(
51 | ClassMetadataBuilder $builder,
52 | NamingStrategy $namingStrategy,
53 | $name,
54 | callable $callback
55 | ) {
56 | $this->builder = $builder;
57 | $this->callback = $callback;
58 | $this->name = $name;
59 | $this->namingStrategy = $namingStrategy;
60 | }
61 |
62 | /**
63 | * Execute the build process.
64 | */
65 | public function build()
66 | {
67 | $callback = $this->callback;
68 |
69 | // We will create a new class metadata builder instance,
70 | // so we can use it to easily generated a new mapping
71 | // array, without re-declaring the existing association
72 | $builder = $this->newClassMetadataBuilder();
73 | $source = $this->convertToMappingArray($this->builder);
74 |
75 | if (!isset($this->relations[$source['type']])) {
76 | throw new InvalidArgumentException('Only ManyToMany and ManyToOne relations can be overridden');
77 | }
78 |
79 | // Create a new association builder, based on the given type
80 | $associationBuilder = $this->getAssociationBuilder($builder, $source);
81 |
82 | // Give the original join table name, so we won't
83 | // accidentally remove custom join table names
84 | if ($this->hasJoinTable($source)) {
85 | $associationBuilder->setJoinTable($source['joinTable']['name']);
86 | }
87 |
88 | $association = $callback($associationBuilder);
89 |
90 | // When the user forget to return, use the $associationBuilder instance
91 | // which contains the same information
92 | $association = $association ?: $associationBuilder;
93 |
94 | if (!$association instanceof Relation) {
95 | throw new InvalidArgumentException('The callback should return an instance of '.Relation::class);
96 | }
97 |
98 | $association->build();
99 |
100 | $target = $this->convertToMappingArray($builder);
101 |
102 | $overrideMapping = [];
103 |
104 | // ManyToMany mappings
105 | if ($this->hasJoinTable($target)) {
106 | $overrideMapping['joinTable'] = $this->mapJoinTable(
107 | $target['joinTable'],
108 | $source['joinTable']
109 | );
110 | }
111 |
112 | // ManyToOne mappings
113 | if ($this->hasJoinColumns($target)) {
114 | $overrideMapping['joinColumns'] = $this->mapJoinColumns(
115 | $target['joinColumns'],
116 | $source['joinColumns']
117 | );
118 | }
119 |
120 | $this->builder->getClassMetadata()->setAssociationOverride(
121 | $this->name,
122 | $overrideMapping
123 | );
124 | }
125 |
126 | /**
127 | * @param ClassMetadataBuilder $builder
128 | *
129 | * @throws \Doctrine\ORM\Mapping\MappingException
130 | *
131 | * @return array
132 | */
133 | protected function convertToMappingArray(ClassMetadataBuilder $builder)
134 | {
135 | $metadata = $builder->getClassMetadata();
136 |
137 | return $metadata->getAssociationMapping($this->name);
138 | }
139 |
140 | /**
141 | * @return ClassMetadataBuilder
142 | */
143 | protected function newClassMetadataBuilder()
144 | {
145 | return new ClassMetadataBuilder(
146 | new ClassMetadataInfo($this->builder->getClassMetadata()->name)
147 | );
148 | }
149 |
150 | /**
151 | * @param $builder
152 | * @param $source
153 | *
154 | * @return mixed
155 | */
156 | protected function getAssociationBuilder(ClassMetadataBuilder $builder, array $source)
157 | {
158 | return new $this->relations[$source['type']](
159 | $builder,
160 | $this->namingStrategy,
161 | $this->name,
162 | $source['targetEntity']
163 | );
164 | }
165 |
166 | /**
167 | * @param array $target
168 | * @param array $source
169 | *
170 | * @return array
171 | */
172 | protected function mapJoinTable(array $target = [], array $source = [])
173 | {
174 | $joinTable['name'] = $target['name'];
175 |
176 | if ($this->hasJoinColumns($target)) {
177 | $joinTable['joinColumns'] = $this->mapJoinColumns(
178 | $target['joinColumns'],
179 | $source['joinColumns']
180 | );
181 | }
182 |
183 | if ($this->hasInverseJoinColumns($target)) {
184 | $joinTable['inverseJoinColumns'] = $this->mapJoinColumns(
185 | $target['inverseJoinColumns'],
186 | $source['inverseJoinColumns']
187 | );
188 | }
189 |
190 | return $joinTable;
191 | }
192 |
193 | /**
194 | * @param array $target
195 | * @param array $source
196 | *
197 | * @return mixed
198 | *
199 | * @internal param $target
200 | * @internal param $source
201 | * @internal param $overrideMapping
202 | */
203 | protected function mapJoinColumns(array $target = [], array $source = [])
204 | {
205 | $joinColumns = [];
206 | foreach ($target as $index => $joinColumn) {
207 | if (isset($source[$index])) {
208 | $diff = array_diff($joinColumn, $source[$index]);
209 |
210 | if (!empty($diff)) {
211 | $joinColumns[] = $diff;
212 | }
213 | }
214 | }
215 |
216 | return $joinColumns;
217 | }
218 |
219 | /**
220 | * @param array $target
221 | *
222 | * @return bool
223 | */
224 | protected function hasJoinColumns(array $target = [])
225 | {
226 | return isset($target['joinColumns']);
227 | }
228 |
229 | /**
230 | * @param array $target
231 | *
232 | * @return bool
233 | */
234 | protected function hasInverseJoinColumns(array $target = [])
235 | {
236 | return isset($target['inverseJoinColumns']);
237 | }
238 |
239 | /**
240 | * @param array $target
241 | *
242 | * @return bool
243 | */
244 | protected function hasJoinTable(array $target = [])
245 | {
246 | return isset($target['joinTable']);
247 | }
248 | }
249 |
--------------------------------------------------------------------------------
/src/Builders/Overrides/AttributeOverride.php:
--------------------------------------------------------------------------------
1 | builder = $builder;
47 | $this->callback = $callback;
48 | $this->name = $name;
49 | $this->namingStrategy = $namingStrategy;
50 | }
51 |
52 | /**
53 | * Execute the build process.
54 | */
55 | public function build()
56 | {
57 | $callback = $this->callback;
58 |
59 | // We will create a new class metadata builder instance,
60 | // so we can use it to easily generated a new mapping
61 | // array, without re-declaring the existing field
62 | $builder = $this->newClassMetadataBuilder();
63 |
64 | $source = $this->convertToMappingArray($this->builder);
65 |
66 | // Create a new field builder for the new class metadata builder,
67 | // based on the existing (to be overridden) field
68 | $fieldBuilder = $this->getFieldBuilder(
69 | $builder,
70 | $source
71 | );
72 |
73 | $field = $callback($fieldBuilder);
74 |
75 | // When the user forget to return, use the Field instance
76 | // which contains the same information
77 | $field = $field ?: $fieldBuilder;
78 |
79 | if (!$field instanceof Field) {
80 | throw new InvalidArgumentException('The callback should return an instance of '.Field::class);
81 | }
82 |
83 | $field->build();
84 |
85 | $target = $this->convertToMappingArray($builder);
86 |
87 | $this->builder->getClassMetadata()->setAttributeOverride(
88 | $this->name,
89 | $this->mergeRecursively($source, $target)
90 | );
91 | }
92 |
93 | /**
94 | * @param ClassMetadataBuilder $builder
95 | * @param array $mapping
96 | *
97 | * @return Field
98 | */
99 | protected function getFieldBuilder(ClassMetadataBuilder $builder, array $mapping)
100 | {
101 | return Field::make(
102 | $builder,
103 | $mapping['type'],
104 | $this->name
105 | );
106 | }
107 |
108 | /**
109 | * @param ClassMetadataBuilder $builder
110 | *
111 | * @throws \Doctrine\ORM\Mapping\MappingException
112 | *
113 | * @return array
114 | */
115 | protected function convertToMappingArray(ClassMetadataBuilder $builder)
116 | {
117 | $metadata = $builder->getClassMetadata();
118 |
119 | return $metadata->getFieldMapping($this->name);
120 | }
121 |
122 | /**
123 | * @return ClassMetadataBuilder
124 | */
125 | protected function newClassMetadataBuilder()
126 | {
127 | return new ClassMetadataBuilder(
128 | new ClassMetadataInfo($this->builder->getClassMetadata()->name)
129 | );
130 | }
131 |
132 | /**
133 | * Merges the field mappings recursively, by keeping originals
134 | * settings, but replacing and adding new once.
135 | *
136 | * @param array $source
137 | * @param array $target
138 | *
139 | * @return array
140 | */
141 | protected function mergeRecursively(array $source, array $target)
142 | {
143 | foreach ($source as $key => $value) {
144 | if (!isset($target[$key])) {
145 | $target[$key] = $value;
146 | } elseif (is_array($value)) {
147 | $target[$key] = $this->mergeRecursively($value, $target[$key]);
148 | }
149 | }
150 |
151 | return $target;
152 | }
153 | }
154 |
--------------------------------------------------------------------------------
/src/Builders/Overrides/Override.php:
--------------------------------------------------------------------------------
1 | builder = $builder;
41 | $this->callback = $callback;
42 | $this->name = $name;
43 | $this->namingStrategy = $namingStrategy;
44 | }
45 |
46 | /**
47 | * Execute the build process.
48 | */
49 | public function build()
50 | {
51 | $builder = OverrideBuilderFactory::create(
52 | $this->builder,
53 | $this->namingStrategy,
54 | $this->name,
55 | $this->callback
56 | );
57 |
58 | $builder->build();
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/Builders/Overrides/OverrideBuilderFactory.php:
--------------------------------------------------------------------------------
1 | $check) {
23 | if ($check($builder->getClassMetadata(), $name)) {
24 | return new $buildable($builder, $namingStrategy, $name, $callback);
25 | }
26 | }
27 |
28 | throw new InvalidArgumentException('No attribute or association could be found for '.$name);
29 | }
30 |
31 | /**
32 | * @return array
33 | */
34 | protected static function getFactories()
35 | {
36 | return [
37 | AttributeOverride::class => function (ClassMetadata $meta, $name) {
38 | return $meta->hasField($name);
39 | },
40 | AssociationOverride::class => function (ClassMetadata $meta, $name) {
41 | return $meta->hasAssociation($name);
42 | },
43 | ];
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/Builders/Primary.php:
--------------------------------------------------------------------------------
1 | builder = $builder;
27 | $this->fields = $fields;
28 | }
29 |
30 | /**
31 | * Execute the build process.
32 | */
33 | public function build()
34 | {
35 | $this->builder->getClassMetadata()->setIdentifier(
36 | $this->getFields()
37 | );
38 | }
39 |
40 | /**
41 | * @return string[]
42 | */
43 | public function getFields()
44 | {
45 | return $this->fields;
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/Builders/Table.php:
--------------------------------------------------------------------------------
1 | setName($name);
32 | }
33 | }
34 |
35 | /**
36 | * @param string $name
37 | *
38 | * @return $this
39 | */
40 | public function setName($name)
41 | {
42 | $this->builder->setTable($name);
43 |
44 | return $this;
45 | }
46 |
47 | /**
48 | * @param string $schema
49 | *
50 | * @return $this
51 | */
52 | public function schema($schema)
53 | {
54 | $this->primaryTable['schema'] = $schema;
55 |
56 | return $this;
57 | }
58 |
59 | /**
60 | * @param string $charset
61 | *
62 | * @return $this
63 | */
64 | public function charset($charset)
65 | {
66 | $this->option('charset', $charset);
67 |
68 | return $this;
69 | }
70 |
71 | /**
72 | * @param string $collate
73 | *
74 | * @return $this
75 | */
76 | public function collate($collate)
77 | {
78 | $this->option('collate', $collate);
79 |
80 | return $this;
81 | }
82 |
83 | /**
84 | * @param array $options
85 | *
86 | * @return $this
87 | */
88 | public function options(array $options = [])
89 | {
90 | $this->primaryTable['options'] = $options;
91 |
92 | return $this;
93 | }
94 |
95 | /**
96 | * @param string $name
97 | * @param string $value
98 | *
99 | * @return $this
100 | */
101 | public function option($name, $value)
102 | {
103 | $this->primaryTable['options'][$name] = $value;
104 |
105 | return $this;
106 | }
107 |
108 | /**
109 | * Execute the build process.
110 | */
111 | public function build()
112 | {
113 | $this->builder->getClassMetadata()->setPrimaryTable($this->primaryTable);
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/src/Builders/Traits/Aliases.php:
--------------------------------------------------------------------------------
1 | disallowInEmbeddedClasses();
13 |
14 | return $this->integer($name, $callback)->primary()->unsigned()->autoIncrement();
15 | }
16 |
17 | /**
18 | * {@inheritdoc}
19 | */
20 | public function smallIncrements($name, callable $callback = null)
21 | {
22 | $this->disallowInEmbeddedClasses();
23 |
24 | return $this->smallInteger($name, $callback)->primary()->unsigned()->autoIncrement();
25 | }
26 |
27 | /**
28 | * {@inheritdoc}
29 | */
30 | public function bigIncrements($name, callable $callback = null)
31 | {
32 | $this->disallowInEmbeddedClasses();
33 |
34 | return $this->bigInteger($name, $callback)->primary()->unsigned()->autoIncrement();
35 | }
36 |
37 | /**
38 | * {@inheritdoc}
39 | */
40 | public function unsignedSmallInteger($name, callable $callback = null)
41 | {
42 | return $this->smallInteger($name, $callback)->unsigned();
43 | }
44 |
45 | /**
46 | * {@inheritdoc}
47 | */
48 | public function unsignedInteger($name, callable $callback = null)
49 | {
50 | return $this->integer($name, $callback)->unsigned();
51 | }
52 |
53 | /**
54 | * {@inheritdoc}
55 | */
56 | public function unsignedBigInteger($name, callable $callback = null)
57 | {
58 | return $this->bigInteger($name, $callback)->unsigned();
59 | }
60 |
61 | /**
62 | * {@inheritdoc}
63 | */
64 | public function rememberToken($name = 'rememberToken', callable $callback = null)
65 | {
66 | return $this->string($name, $callback)->nullable()->length(100);
67 | }
68 |
69 | /**
70 | * @param string $message
71 | *
72 | * @throws \LogicException
73 | */
74 | abstract protected function disallowInEmbeddedClasses($message = '');
75 |
76 | /**
77 | * @param string $name
78 | * @param callable|null $callback
79 | *
80 | * @return \LaravelDoctrine\Fluent\Builders\Field
81 | */
82 | abstract public function integer($name, callable $callback = null);
83 |
84 | /**
85 | * @param string $name
86 | * @param callable|null $callback
87 | *
88 | * @return \LaravelDoctrine\Fluent\Builders\Field
89 | */
90 | abstract public function smallInteger($name, callable $callback = null);
91 |
92 | /**
93 | * @param string $name
94 | * @param callable|null $callback
95 | *
96 | * @return \LaravelDoctrine\Fluent\Builders\Field
97 | */
98 | abstract public function bigInteger($name, callable $callback = null);
99 |
100 | /**
101 | * @param string $name
102 | * @param callable|null $callback
103 | *
104 | * @return \LaravelDoctrine\Fluent\Builders\Field
105 | */
106 | abstract public function string($name, callable $callback = null);
107 | }
108 |
--------------------------------------------------------------------------------
/src/Builders/Traits/Constraints.php:
--------------------------------------------------------------------------------
1 | constraint(
18 | Index::class,
19 | is_array($columns) ? $columns : func_get_args()
20 | );
21 | }
22 |
23 | /**
24 | * {@inheritdoc}
25 | */
26 | public function primary($fields)
27 | {
28 | return $this->constraint(
29 | Primary::class,
30 | is_array($fields) ? $fields : func_get_args()
31 | );
32 | }
33 |
34 | /**
35 | * {@inheritdoc}
36 | */
37 | public function unique($columns)
38 | {
39 | return $this->constraint(
40 | UniqueConstraint::class,
41 | is_array($columns) ? $columns : func_get_args()
42 | );
43 | }
44 |
45 | /**
46 | * @param string $class
47 | * @param array $columns
48 | *
49 | * @return mixed
50 | */
51 | protected function constraint($class, array $columns)
52 | {
53 | $constraint = new $class($this->getBuilder(), $columns);
54 |
55 | $this->queue($constraint);
56 |
57 | return $constraint;
58 | }
59 |
60 | /**
61 | * @return \Doctrine\ORM\Mapping\Builder\ClassMetadataBuilder
62 | */
63 | abstract public function getBuilder();
64 |
65 | /**
66 | * @param Buildable $buildable
67 | */
68 | abstract protected function queue(Buildable $buildable);
69 | }
70 |
--------------------------------------------------------------------------------
/src/Builders/Traits/Dates.php:
--------------------------------------------------------------------------------
1 | field(Types::DATE_MUTABLE, $name, $callback);
15 | }
16 |
17 | /**
18 | * {@inheritdoc}
19 | */
20 | public function dateTime($name, callable $callback = null)
21 | {
22 | return $this->field(Types::DATETIME_MUTABLE, $name, $callback);
23 | }
24 |
25 | /**
26 | * {@inheritdoc}
27 | */
28 | public function dateTimeTz($name, callable $callback = null)
29 | {
30 | return $this->field(Types::DATETIMETZ_MUTABLE, $name, $callback);
31 | }
32 |
33 | /**
34 | * {@inheritdoc}
35 | */
36 | public function time($name, callable $callback = null)
37 | {
38 | return $this->field(Types::TIME_MUTABLE, $name, $callback);
39 | }
40 |
41 | /**
42 | * {@inheritdoc}
43 | */
44 | public function carbonDateTime($name, callable $callback = null)
45 | {
46 | return $this->field('carbondatetime', $name, $callback);
47 | }
48 |
49 | /**
50 | * {@inheritdoc}
51 | */
52 | public function carbonDateTimeTz($name, callable $callback = null)
53 | {
54 | return $this->field('carbondatetimetz', $name, $callback);
55 | }
56 |
57 | /**
58 | * {@inheritdoc}
59 | */
60 | public function carbonDate($name, callable $callback = null)
61 | {
62 | return $this->field('carbondate', $name, $callback);
63 | }
64 |
65 | /**
66 | * {@inheritdoc}
67 | */
68 | public function carbonTime($name, callable $callback = null)
69 | {
70 | return $this->field('carbontime', $name, $callback);
71 | }
72 |
73 | /**
74 | * {@inheritdoc}
75 | */
76 | public function zendDate($name, callable $callback = null)
77 | {
78 | return $this->field('zenddate', $name, $callback);
79 | }
80 |
81 | /**
82 | * {@inheritdoc}
83 | */
84 | public function timestamp($name, callable $callback = null)
85 | {
86 | return $this->carbonDateTime($name, $callback);
87 | }
88 |
89 | /**
90 | * {@inheritdoc}
91 | */
92 | public function timestampTz($name, callable $callback = null)
93 | {
94 | return $this->carbonDateTimeTz($name, $callback);
95 | }
96 |
97 | /**
98 | * @param string $type
99 | * @param string $name
100 | * @param callable|null $callback
101 | *
102 | * @return \LaravelDoctrine\Fluent\Builders\Field
103 | */
104 | abstract public function field($type, $name, callable $callback = null);
105 | }
106 |
--------------------------------------------------------------------------------
/src/Builders/Traits/Fields.php:
--------------------------------------------------------------------------------
1 | getBuilder(), $type, $name);
17 |
18 | $this->callbackAndQueue($field, $callback);
19 |
20 | return $field;
21 | }
22 |
23 | /**
24 | * {@inheritdoc}
25 | */
26 | public function string($name, callable $callback = null)
27 | {
28 | return $this->field(Types::STRING, $name, $callback);
29 | }
30 |
31 | /**
32 | * {@inheritdoc}
33 | */
34 | public function text($name, callable $callback = null)
35 | {
36 | return $this->field(Types::TEXT, $name, $callback);
37 | }
38 |
39 | /**
40 | * {@inheritdoc}
41 | */
42 | public function integer($name, callable $callback = null)
43 | {
44 | return $this->field(Types::INTEGER, $name, $callback);
45 | }
46 |
47 | /**
48 | * {@inheritdoc}
49 | */
50 | public function smallInteger($name, callable $callback = null)
51 | {
52 | return $this->field(Types::SMALLINT, $name, $callback);
53 | }
54 |
55 | /**
56 | * {@inheritdoc}
57 | */
58 | public function bigInteger($name, callable $callback = null)
59 | {
60 | return $this->field(Types::BIGINT, $name, $callback);
61 | }
62 |
63 | /**
64 | * {@inheritdoc}
65 | */
66 | public function guid($name, callable $callback = null)
67 | {
68 | return $this->field(Types::GUID, $name, $callback);
69 | }
70 |
71 | /**
72 | * {@inheritdoc}
73 | */
74 | public function blob($name, callable $callback = null)
75 | {
76 | return $this->field(Types::BLOB, $name, $callback);
77 | }
78 |
79 | /**
80 | * {@inheritdoc}
81 | */
82 | public function object($name, callable $callback = null)
83 | {
84 | return $this->field(Types::OBJECT, $name, $callback);
85 | }
86 |
87 | /**
88 | * {@inheritdoc}
89 | */
90 | public function float($name, callable $callback = null)
91 | {
92 | return $this->field(Types::FLOAT, $name, $callback)->precision(8)->scale(2);
93 | }
94 |
95 | /**
96 | * {@inheritdoc}
97 | */
98 | public function decimal($name, callable $callback = null)
99 | {
100 | return $this->field(Types::DECIMAL, $name, $callback)->precision(8)->scale(2);
101 | }
102 |
103 | /**
104 | * {@inheritdoc}
105 | */
106 | public function boolean($name, callable $callback = null)
107 | {
108 | return $this->field(Types::BOOLEAN, $name, $callback);
109 | }
110 |
111 | /**
112 | * {@inheritdoc}
113 | */
114 | public function simpleArray($name, callable $callback = null)
115 | {
116 | return $this->field(Types::SIMPLE_ARRAY, $name, $callback);
117 | }
118 |
119 | /**
120 | * {@inheritdoc}
121 | */
122 | public function jsonArray($name, callable $callback = null)
123 | {
124 | return $this->field(Types::JSON, $name, $callback);
125 | }
126 |
127 | /**
128 | * {@inheritdoc}
129 | */
130 | public function binary($name, callable $callback = null)
131 | {
132 | return $this->field(Types::BINARY, $name, $callback)->nullable();
133 | }
134 |
135 | /**
136 | * @return \Doctrine\ORM\Mapping\Builder\ClassMetadataBuilder
137 | */
138 | abstract public function getBuilder();
139 |
140 | /**
141 | * @param Buildable $buildable
142 | * @param callable|null $callback
143 | */
144 | abstract protected function callbackAndQueue(Buildable $buildable, callable $callback = null);
145 | }
146 |
--------------------------------------------------------------------------------
/src/Builders/Traits/Macroable.php:
--------------------------------------------------------------------------------
1 | getMacro($method), $params);
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/Builders/Traits/Queueable.php:
--------------------------------------------------------------------------------
1 | queued[spl_object_hash($buildable)] = $buildable;
21 | }
22 |
23 | /**
24 | * @param Buildable $buildable
25 | * @param callable|null $callback
26 | */
27 | public function callbackAndQueue(Buildable $buildable, callable $callback = null)
28 | {
29 | $this->callIfCallable($callback, $buildable);
30 |
31 | $this->queue($buildable);
32 | }
33 |
34 | /**
35 | * Execute the build process for all queued buildables.
36 | */
37 | public function build()
38 | {
39 | /** @var Buildable[] $delayed */
40 | $delayed = [];
41 |
42 | foreach ($this->getQueued() as $buildable) {
43 | if ($buildable instanceof Delay) {
44 | $delayed[] = $buildable;
45 | } else {
46 | $buildable->build();
47 | }
48 | }
49 |
50 | foreach ($delayed as $buildable) {
51 | $buildable->build();
52 | }
53 | }
54 |
55 | /**
56 | * @return \LaravelDoctrine\Fluent\Buildable[]
57 | */
58 | public function getQueued()
59 | {
60 | return $this->queued;
61 | }
62 |
63 | /**
64 | * Call the callable... only if it is really one.
65 | *
66 | * @param callable|null $callback
67 | * @param mixed $builder
68 | *
69 | * @return void
70 | */
71 | protected function callIfCallable($callback, $builder)
72 | {
73 | if (is_callable($callback)) {
74 | $callback($builder);
75 | }
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/src/Builders/Traits/QueuesMacros.php:
--------------------------------------------------------------------------------
1 | callMacro($method, $args);
33 |
34 | if ($result instanceof Buildable) {
35 | $this->queue($result);
36 | }
37 |
38 | return $result;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/Builders/Traits/Relations.php:
--------------------------------------------------------------------------------
1 | oneToOne($entity, $field, $callback)->ownedBy(
21 | $this->guessSingularField($entity)
22 | );
23 | }
24 |
25 | /**
26 | * {@inheritdoc}
27 | */
28 | public function oneToOne($entity, $field = null, callable $callback = null)
29 | {
30 | return $this->addRelation(
31 | new OneToOne(
32 | $this->getBuilder(),
33 | $this->getNamingStrategy(),
34 | $this->guessSingularField($entity, $field),
35 | $entity
36 | ),
37 | $callback
38 | );
39 | }
40 |
41 | /**
42 | * {@inheritdoc}
43 | */
44 | public function belongsTo($entity, $field = null, callable $callback = null)
45 | {
46 | return $this->manyToOne($entity, $field, $callback);
47 | }
48 |
49 | /**
50 | * {@inheritdoc}
51 | */
52 | public function manyToOne($entity, $field = null, callable $callback = null)
53 | {
54 | return $this->addRelation(
55 | new ManyToOne(
56 | $this->getBuilder(),
57 | $this->getNamingStrategy(),
58 | $this->guessSingularField($entity, $field),
59 | $entity
60 | ),
61 | $callback
62 | );
63 | }
64 |
65 | /**
66 | * {@inheritdoc}
67 | */
68 | public function hasMany($entity, $field = null, callable $callback = null)
69 | {
70 | return $this->oneToMany($entity, $field, $callback);
71 | }
72 |
73 | /**
74 | * {@inheritdoc}
75 | */
76 | public function oneToMany($entity, $field = null, callable $callback = null)
77 | {
78 | return $this->addRelation(
79 | new OneToMany(
80 | $this->getBuilder(),
81 | $this->getNamingStrategy(),
82 | $this->guessPluralField($entity, $field),
83 | $entity
84 | ),
85 | $callback
86 | );
87 | }
88 |
89 | /**
90 | * {@inheritdoc}
91 | */
92 | public function belongsToMany($entity, $field = null, callable $callback = null)
93 | {
94 | return $this->manyToMany($entity, $field, $callback);
95 | }
96 |
97 | /**
98 | * {@inheritdoc}
99 | */
100 | public function manyToMany($entity, $field = null, callable $callback = null)
101 | {
102 | return $this->addRelation(
103 | new ManyToMany(
104 | $this->getBuilder(),
105 | $this->getNamingStrategy(),
106 | $this->guessPluralField($entity, $field),
107 | $entity
108 | ),
109 | $callback
110 | );
111 | }
112 |
113 | /**
114 | * {@inheritdoc}
115 | */
116 | public function addRelation(Relation $relation, callable $callback = null)
117 | {
118 | $this->callbackAndQueue($relation, $callback);
119 |
120 | return $relation;
121 | }
122 |
123 | /**
124 | * @param string $entity
125 | * @param string|null $field
126 | *
127 | * @return string
128 | */
129 | protected function guessSingularField($entity, $field = null)
130 | {
131 | return $field ?: (InflectorFactory::create()->build())->singularize(
132 | lcfirst(basename(str_replace('\\', '/', $entity)))
133 | );
134 | }
135 |
136 | /**
137 | * @param string $entity
138 | * @param string|null $field
139 | *
140 | * @return string
141 | */
142 | protected function guessPluralField($entity, $field = null)
143 | {
144 | return $field ?: (InflectorFactory::create()->build())->pluralize($this->guessSingularField($entity));
145 | }
146 |
147 | /**
148 | * @return \Doctrine\ORM\Mapping\Builder\ClassMetadataBuilder
149 | */
150 | abstract public function getBuilder();
151 |
152 | /**
153 | * @param Buildable $buildable
154 | * @param callable|null $callback
155 | */
156 | abstract protected function callbackAndQueue(Buildable $buildable, callable $callback = null);
157 |
158 | /**
159 | * @return \Doctrine\ORM\Mapping\NamingStrategy
160 | */
161 | abstract public function getNamingStrategy();
162 | }
163 |
--------------------------------------------------------------------------------
/src/Builders/UniqueConstraint.php:
--------------------------------------------------------------------------------
1 | builder->addUniqueConstraint(
22 | $this->getColumns(),
23 | $this->getName()
24 | );
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/EmbeddableMapping.php:
--------------------------------------------------------------------------------
1 | addMapper($this->mapFor(), new EmbeddableMapper($this));
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/EntityMapping.php:
--------------------------------------------------------------------------------
1 | addMapper($this->mapFor(), new EntityMapper($this));
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/Extensions/ExtensibleClassMetadata.php:
--------------------------------------------------------------------------------
1 | extensions[$name] = $config;
27 | }
28 |
29 | /**
30 | * @param string $name
31 | *
32 | * @return array
33 | */
34 | public function getExtension($name)
35 | {
36 | if (isset($this->extensions[$name])) {
37 | return $this->extensions[$name];
38 | }
39 |
40 | return [];
41 | }
42 |
43 | /**
44 | * Merge with current extension configuration, appending new values to old ones.
45 | *
46 | * @param string $name
47 | * @param array $config
48 | */
49 | public function appendExtension($name, array $config = [])
50 | {
51 | $merged = array_merge_recursive(
52 | $this->getExtension($name),
53 | $config
54 | );
55 |
56 | $this->addExtension($name, $merged);
57 | }
58 |
59 | /**
60 | * Merge with current extension configuration, overwriting with new values.
61 | *
62 | * @param string $name
63 | * @param array $config
64 | *
65 | * @return void
66 | */
67 | public function mergeExtension($name, array $config)
68 | {
69 | $this->addExtension($name, array_merge(
70 | $this->getExtension($name),
71 | $config
72 | ));
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/src/Extensions/ExtensibleClassMetadataFactory.php:
--------------------------------------------------------------------------------
1 | entityManager = $em;
25 | }
26 |
27 | /**
28 | * Override to implement our custom ClassMetadata object.
29 | *
30 | * {@inheritdoc}
31 | */
32 | protected function newClassMetadataInstance($className)
33 | {
34 | return new ExtensibleClassMetadata($className, $this->entityManager->getConfiguration()->getNamingStrategy());
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/Extensions/Extension.php:
--------------------------------------------------------------------------------
1 | classMetadata = $classMetadata;
49 | $this->fieldName = $fieldName;
50 | }
51 |
52 | /**
53 | * @return $this
54 | */
55 | public function onCreate()
56 | {
57 | return $this->on('create');
58 | }
59 |
60 | /**
61 | * @return $this
62 | */
63 | public function onUpdate()
64 | {
65 | return $this->on('update');
66 | }
67 |
68 | /**
69 | * @param array|string|null $fields
70 | * @param string|null $value
71 | *
72 | * @return $this
73 | */
74 | public function onChange($fields = null, $value = null)
75 | {
76 | return $this->on('change', $fields, $value);
77 | }
78 |
79 | /**
80 | * Execute the build process.
81 | */
82 | public function build()
83 | {
84 | if ($this->on === null) {
85 | throw new InvalidMappingException(
86 | "Field - [{$this->fieldName}] trigger 'on' is not one of [update, create, change] in class - {$this->classMetadata->name}"
87 | );
88 | }
89 |
90 | if (is_array($this->trackedFields) && $this->value !== null) {
91 | throw new InvalidMappingException('Extension does not support multiple value change-set detection yet.');
92 | }
93 |
94 | $this->classMetadata->appendExtension($this->getExtensionName(), [
95 | $this->on => [
96 | $this->makeConfiguration(),
97 | ],
98 | ]);
99 | }
100 |
101 | /**
102 | * @param string $on
103 | * @param array|string|null $fields
104 | * @param string|null $value
105 | *
106 | * @return $this
107 | */
108 | protected function on($on, $fields = null, $value = null)
109 | {
110 | $this->on = $on;
111 | $this->trackedFields = $fields;
112 | $this->value = $value;
113 |
114 | return $this;
115 | }
116 |
117 | /**
118 | * Returns either the field name on "create" and "update", or the array configuration on "change".
119 | *
120 | * @return array|string
121 | */
122 | protected function makeConfiguration()
123 | {
124 | if ($this->on == 'create' || $this->on == 'update') {
125 | return $this->fieldName;
126 | }
127 |
128 | return [
129 | 'field' => $this->fieldName,
130 | 'trackedField' => $this->trackedFields,
131 | 'value' => $this->value,
132 | ];
133 | }
134 | }
135 |
--------------------------------------------------------------------------------
/src/Extensions/Gedmo/Blameable.php:
--------------------------------------------------------------------------------
1 | getClassMetadata(), $builder->getName());
24 | });
25 |
26 | ManyToOne::macro(self::MACRO_METHOD, function (ManyToOne $builder) {
27 | return new static($builder->getClassMetadata(), $builder->getRelation());
28 | });
29 | }
30 |
31 | /**
32 | * Return the name of the actual extension.
33 | *
34 | * @return string
35 | */
36 | protected function getExtensionName()
37 | {
38 | return Fluent::EXTENSION_NAME;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/Extensions/Gedmo/ClosureTable.php:
--------------------------------------------------------------------------------
1 | closureClass = $class;
28 | }
29 |
30 | /**
31 | * Execute the build process.
32 | */
33 | public function build()
34 | {
35 | $this->builder->entity()->setRepositoryClass(ClosureTreeRepository::class);
36 |
37 | parent::build();
38 | }
39 |
40 | /**
41 | * {@inheritdoc}
42 | */
43 | protected function getValues()
44 | {
45 | return array_merge(parent::getValues(), [
46 | 'strategy' => 'closure',
47 | 'closure' => $this->closureClass,
48 | ]);
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/Extensions/Gedmo/GedmoBuilderHints.php:
--------------------------------------------------------------------------------
1 | getClassMetadata(), $builder->getName());
21 | });
22 | }
23 |
24 | /**
25 | * Return the name of the actual extension.
26 | *
27 | * @return string
28 | */
29 | protected function getExtensionName()
30 | {
31 | return Fluent::EXTENSION_NAME;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/Extensions/Gedmo/Locale.php:
--------------------------------------------------------------------------------
1 | classMetadata = $classMetadata;
36 | $this->fieldName = $fieldName;
37 | }
38 |
39 | /**
40 | * @return void
41 | */
42 | public static function enable()
43 | {
44 | Builder::macro(self::MACRO_METHOD, function (Builder $builder, $fieldName) {
45 | return new static($builder->getClassMetadata(), $fieldName);
46 | });
47 | }
48 |
49 | /**
50 | * Execute the build process.
51 | */
52 | public function build()
53 | {
54 | if ($this->classMetadata->hasField($this->fieldName)) {
55 | throw new InvalidMappingException(
56 | "Locale field [{$this->fieldName}] should not be mapped as column property in entity - {$this->classMetadata->name}, since it makes no sense"
57 | );
58 | }
59 |
60 | $this->classMetadata->appendExtension($this->getExtensionName(), [
61 | 'locale' => $this->fieldName,
62 | ]);
63 | }
64 |
65 | /**
66 | * Return the name of the actual extension.
67 | *
68 | * @return string
69 | */
70 | public function getExtensionName()
71 | {
72 | return FluentDriver::EXTENSION_NAME;
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/src/Extensions/Gedmo/Loggable.php:
--------------------------------------------------------------------------------
1 | classMetadata = $classMetadata;
30 | $this->logEntry = $logEntry;
31 | }
32 |
33 | /**
34 | * @return void
35 | */
36 | public static function enable()
37 | {
38 | Builder::macro('loggable', function (Builder $builder, $logEntry = null) {
39 | $loggable = new static($builder->getClassMetadata(), $logEntry);
40 | $loggable->build();
41 | });
42 |
43 | Versioned::enable();
44 | }
45 |
46 | /**
47 | * Execute the build process.
48 | */
49 | public function build()
50 | {
51 | $config = [
52 | 'loggable' => true,
53 | ];
54 |
55 | if ($this->logEntry !== null) {
56 | $config['logEntryClass'] = $this->logEntry;
57 | }
58 |
59 | $this->classMetadata->addExtension(Fluent::EXTENSION_NAME, array_merge(
60 | $this->classMetadata->getExtension(Fluent::EXTENSION_NAME),
61 | $config
62 | ));
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/Extensions/Gedmo/Mappings/Loggable/AbstractLogEntryMapping.php:
--------------------------------------------------------------------------------
1 | increments('id');
25 | $builder->string('action')->length(8);
26 | $builder->dateTime('loggedAt')->name('logged_at');
27 | $builder->string('objectId')->name('object_id')->length(64)->nullable();
28 | $builder->string('objectClass')->name('object_class');
29 | $builder->integer('version');
30 | $builder->array('data')->nullable();
31 | $builder->string('username')->nullable();
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/Extensions/Gedmo/Mappings/Loggable/LogEntryMapping.php:
--------------------------------------------------------------------------------
1 | table('ext_log_entries');
26 | $builder->entity()->setRepositoryClass(LogEntryRepository::class);
27 |
28 | $builder->index(['object_class'])->name('log_class_lookup_idx');
29 | $builder->index(['logged_at'])->name('log_date_lookup_idx');
30 | $builder->index(['username'])->name('log_user_lookup_idx');
31 | $builder->index(['object_id', 'object_class', 'version'])->name('log_version_lookup_idx');
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/Extensions/Gedmo/Mappings/Translatable/AbstractPersonalTranslationMapping.php:
--------------------------------------------------------------------------------
1 | integer('id')->unsigned()->primary()->generatedValue(function (GeneratedValue $builder) {
26 | $builder->identity();
27 | });
28 | $builder->string('locale')->length(8);
29 | $builder->string('field')->length(32);
30 | $builder->text('content')->nullable();
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/Extensions/Gedmo/Mappings/Translatable/AbstractTranslationMapping.php:
--------------------------------------------------------------------------------
1 | integer('id')->unsigned()->primary()->generatedValue(function (GeneratedValue $builder) {
26 | $builder->identity();
27 | });
28 | $builder->string('locale')->length(8);
29 | $builder->string('objectClass')->name('object_class');
30 | $builder->string('field')->length(32);
31 | $builder->string('foreignKey')->length(64)->name('foreign_key');
32 | $builder->text('content')->nullable();
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/Extensions/Gedmo/Mappings/Translatable/TranslationMapping.php:
--------------------------------------------------------------------------------
1 | table('ext_translations');
26 | $builder->entity()->setRepositoryClass(TranslationRepository::class);
27 |
28 | $builder->index(['locale', 'object_class', 'foreign_key'])->name('translations_lookup_idx');
29 | $builder->unique(['locale', 'object_class', 'field', 'foreign_key'])->name('lookup_unique_idx');
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/Extensions/Gedmo/Mappings/Tree/AbstractClosureMapping.php:
--------------------------------------------------------------------------------
1 | integer('id')->unsigned()->primary()->generatedValue(function (GeneratedValue $builder) {
26 | $builder->identity();
27 | });
28 | $builder->integer('depth');
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/Extensions/Gedmo/MaterializedPath.php:
--------------------------------------------------------------------------------
1 | mapField('string', $field, null, true);
73 |
74 | $this->path = new TreePath($this->getClassMetadata(), $field, $separator);
75 |
76 | $this->callbackAndQueue($this->path, $callback);
77 |
78 | return $this;
79 | }
80 |
81 | /**
82 | * @param string $hash
83 | *
84 | * @return $this
85 | */
86 | public function pathHash($hash = 'pathHash')
87 | {
88 | $this->mapField('string', $hash);
89 |
90 | $this->hash = $hash;
91 |
92 | return $this;
93 | }
94 |
95 | /**
96 | * @param string $field
97 | *
98 | * @return $this
99 | */
100 | public function pathSource($field = 'id')
101 | {
102 | $this->source = $field;
103 |
104 | return $this;
105 | }
106 |
107 | /**
108 | * Execute the build process.
109 | */
110 | public function build()
111 | {
112 | parent::build();
113 |
114 | $this->buildQueue();
115 | }
116 |
117 | /**
118 | * Add default values to all required fields.
119 | *
120 | * @return void
121 | */
122 | protected function defaults()
123 | {
124 | parent::defaults();
125 |
126 | if ($this->isMissingPath()) {
127 | $this->path();
128 | }
129 |
130 | if ($this->isMissingSource()) {
131 | $this->pathSource();
132 | }
133 | }
134 |
135 | /**
136 | * @return array
137 | */
138 | protected function getValues()
139 | {
140 | $values = array_merge(parent::getValues(), [
141 | 'strategy' => 'materializedPath',
142 | 'path_source' => $this->source,
143 | 'path_separator' => $this->separator,
144 | 'path_append_id' => $this->appendIds,
145 | 'path_starts_with_separator' => $this->startsWithSeparator,
146 | 'path_ends_with_separator' => $this->endsWithSeparator,
147 | 'activate_locking' => false,
148 | ]);
149 |
150 | if ($this->hash) {
151 | $values['path_hash'] = $this->hash;
152 | }
153 |
154 | return $values;
155 | }
156 |
157 | /**
158 | * @return bool
159 | */
160 | private function isMissingPath()
161 | {
162 | return !$this->alreadyConfigured('path') && !$this->path;
163 | }
164 |
165 | /**
166 | * @return bool
167 | */
168 | private function isMissingSource()
169 | {
170 | return !$this->alreadyConfigured('path_source') && !$this->source;
171 | }
172 | }
173 |
--------------------------------------------------------------------------------
/src/Extensions/Gedmo/NestedSet.php:
--------------------------------------------------------------------------------
1 | validateNumericField($type, $field);
51 |
52 | $this->mapField($type, $field, $callback);
53 |
54 | $this->left = $field;
55 |
56 | return $this;
57 | }
58 |
59 | /**
60 | * @param string $field
61 | * @param string $type
62 | * @param callable|null $callback
63 | *
64 | * @throws InvalidMappingException
65 | *
66 | * @return $this
67 | */
68 | public function right($field = 'right', $type = 'integer', callable $callback = null)
69 | {
70 | $this->validateNumericField($type, $field);
71 |
72 | $this->mapField($type, $field, $callback);
73 |
74 | $this->right = $field;
75 |
76 | return $this;
77 | }
78 |
79 | /**
80 | * @param string $field
81 | * @param callable|null $callback
82 | *
83 | * @return $this
84 | */
85 | public function root($field = 'root', callable $callback = null)
86 | {
87 | $this->addSelfReferencingRelation($field, $callback);
88 |
89 | $this->root = $field;
90 |
91 | return $this;
92 | }
93 |
94 | /**
95 | * Execute the build process.
96 | */
97 | public function build()
98 | {
99 | $this->builder->entity()->setRepositoryClass(NestedTreeRepository::class);
100 |
101 | parent::build();
102 | }
103 |
104 | /**
105 | * Add default values to all required fields.
106 | *
107 | * @return void
108 | */
109 | protected function defaults()
110 | {
111 | parent::defaults();
112 |
113 | if ($this->isMissingLeft()) {
114 | $this->left();
115 | }
116 |
117 | if ($this->isMissingRight()) {
118 | $this->right();
119 | }
120 | }
121 |
122 | protected function getValues()
123 | {
124 | return array_merge(parent::getValues(), [
125 | 'strategy' => 'nested',
126 | 'left' => $this->left,
127 | 'right' => $this->right,
128 | 'root' => $this->root,
129 | ]);
130 | }
131 |
132 | /**
133 | * @return bool
134 | */
135 | private function isMissingLeft()
136 | {
137 | return !$this->alreadyConfigured('left') && !$this->left;
138 | }
139 |
140 | /**
141 | * @return bool
142 | */
143 | private function isMissingRight()
144 | {
145 | return !$this->alreadyConfigured('right') && !$this->right;
146 | }
147 | }
148 |
--------------------------------------------------------------------------------
/src/Extensions/Gedmo/Sluggable.php:
--------------------------------------------------------------------------------
1 | classMetadata = $classMetadata;
99 | $this->fieldName = $fieldName;
100 | $this->baseOn($fields);
101 | }
102 |
103 | /**
104 | * Return the name of the actual extension.
105 | *
106 | * @return string
107 | */
108 | public function getExtensionName()
109 | {
110 | return FluentDriver::EXTENSION_NAME;
111 | }
112 |
113 | /**
114 | * @return void
115 | */
116 | public static function enable()
117 | {
118 | Field::macro(static::MACRO_METHOD, function (Field $builder, $fields) {
119 | return new static($builder->getClassMetadata(), $builder->getName(), $fields);
120 | });
121 | }
122 |
123 | /**
124 | * Execute the build process.
125 | */
126 | public function build()
127 | {
128 | $this->isValidField($this->classMetadata, $this->fieldName);
129 |
130 | $this->classMetadata->appendExtension($this->getExtensionName(), [
131 | 'slugs' => [
132 | $this->fieldName => $this->makeConfiguration(),
133 | ],
134 | ]);
135 | }
136 |
137 | /**
138 | * @param array|string $fields
139 | *
140 | * @return Sluggable
141 | */
142 | public function baseOn($fields)
143 | {
144 | $this->fields = is_array($fields) ? $fields : [$fields];
145 |
146 | return $this;
147 | }
148 |
149 | /**
150 | * @param array|string $handlers
151 | *
152 | * @return Sluggable
153 | */
154 | public function handlers($handlers)
155 | {
156 | $this->handlers = is_array($handlers) ? $handlers : [$handlers];
157 |
158 | return $this;
159 | }
160 |
161 | /**
162 | * @param string $style
163 | *
164 | * @return Sluggable
165 | */
166 | public function style($style)
167 | {
168 | $this->style = $style;
169 |
170 | return $this;
171 | }
172 |
173 | /**
174 | * @param string $dateFormat
175 | *
176 | * @return Sluggable
177 | */
178 | public function dateFormat($dateFormat)
179 | {
180 | $this->dateFormat = $dateFormat;
181 |
182 | return $this;
183 | }
184 |
185 | /**
186 | * @param bool $updatable
187 | *
188 | * @return Sluggable
189 | */
190 | public function updatable($updatable = true)
191 | {
192 | $this->updatable = $updatable;
193 |
194 | return $this;
195 | }
196 |
197 | /**
198 | * @param bool $unique
199 | *
200 | * @return Sluggable
201 | */
202 | public function unique($unique = true)
203 | {
204 | $this->unique = $unique;
205 |
206 | return $this;
207 | }
208 |
209 | /**
210 | * @param null $unique_base
211 | *
212 | * @return Sluggable
213 | */
214 | public function uniqueBase($unique_base)
215 | {
216 | $this->unique_base = $unique_base;
217 |
218 | return $this;
219 | }
220 |
221 | /**
222 | * @param string $separator
223 | *
224 | * @return Sluggable
225 | */
226 | public function separator($separator)
227 | {
228 | $this->separator = $separator;
229 |
230 | return $this;
231 | }
232 |
233 | /**
234 | * @param string $prefix
235 | *
236 | * @return Sluggable
237 | */
238 | public function prefix($prefix)
239 | {
240 | $this->prefix = $prefix;
241 |
242 | return $this;
243 | }
244 |
245 | /**
246 | * @param string $suffix
247 | *
248 | * @return Sluggable
249 | */
250 | public function suffix($suffix)
251 | {
252 | $this->suffix = $suffix;
253 |
254 | return $this;
255 | }
256 |
257 | /**
258 | * Checks if $field type is valid as Sluggable field.
259 | *
260 | * @param ClassMetadataInfo $meta
261 | * @param string $field
262 | *
263 | * @throws InvalidArgumentException
264 | *
265 | * @return bool
266 | */
267 | protected function isValidField(ClassMetadataInfo $meta, $field)
268 | {
269 | $mapping = $meta->getFieldMapping($field);
270 |
271 | if (!$mapping || !in_array($mapping['type'], $this->validTypes)) {
272 | throw new InvalidArgumentException('Sluggable field is not a valid field type');
273 | }
274 |
275 | return true;
276 | }
277 |
278 | /**
279 | * @return array
280 | */
281 | private function makeConfiguration()
282 | {
283 | return [
284 | 'fields' => $this->fields,
285 | 'handlers' => $this->handlers,
286 | 'slug' => $this->fieldName,
287 | 'style' => $this->style,
288 | 'dateFormat' => $this->dateFormat,
289 | 'updatable' => $this->updatable,
290 | 'unique' => $this->unique,
291 | 'unique_base' => $this->unique_base,
292 | 'separator' => $this->separator,
293 | 'prefix' => $this->prefix,
294 | 'suffix' => $this->suffix,
295 | ];
296 | }
297 | }
298 |
--------------------------------------------------------------------------------
/src/Extensions/Gedmo/SoftDeleteable.php:
--------------------------------------------------------------------------------
1 | classMetadata = $classMetadata;
43 | $this->fieldName = $fieldName;
44 | }
45 |
46 | /**
47 | * Return the name of the actual extension.
48 | *
49 | * @return string
50 | */
51 | public function getExtensionName()
52 | {
53 | return FluentDriver::EXTENSION_NAME;
54 | }
55 |
56 | /**
57 | * @param bool $value
58 | *
59 | * @return $this
60 | */
61 | public function timeAware($value = true)
62 | {
63 | $this->timeAware = $value;
64 |
65 | return $this;
66 | }
67 |
68 | /**
69 | * @return void
70 | */
71 | public static function enable()
72 | {
73 | Builder::macro(static::MACRO_METHOD, function (Builder $builder, $fieldName = 'deletedAt', $type = 'dateTime') {
74 | $builder->{$type}($fieldName)->nullable();
75 |
76 | return new static($builder->getClassMetadata(), $fieldName);
77 | });
78 |
79 | Field::macro(static::MACRO_METHOD, function (Field $builder) {
80 | return new static($builder->getClassMetadata(), $builder->getName());
81 | });
82 | }
83 |
84 | /**
85 | * Execute the build process.
86 | */
87 | public function build()
88 | {
89 | $this->classMetadata->addExtension($this->getExtensionName(), [
90 | 'softDeleteable' => true,
91 | 'fieldName' => $this->fieldName,
92 | 'timeAware' => $this->timeAware,
93 | ]);
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/src/Extensions/Gedmo/Sortable.php:
--------------------------------------------------------------------------------
1 | classMetadata = $classMetadata;
33 | $this->fieldName = $fieldName;
34 | }
35 |
36 | /**
37 | * Return the name of the actual extension.
38 | *
39 | * @return string
40 | */
41 | public function getExtensionName()
42 | {
43 | return FluentDriver::EXTENSION_NAME;
44 | }
45 |
46 | /**
47 | * @return void
48 | */
49 | public static function enable()
50 | {
51 | Field::macro(self::MACRO_METHOD, function (Field $builder) {
52 | return new static($builder->getClassMetadata(), $builder->getName());
53 | });
54 |
55 | ManyToOne::macro(self::MACRO_METHOD, function (ManyToOne $builder) {
56 | return new static($builder->getClassMetadata(), $builder->getRelation());
57 | });
58 |
59 | ManyToMany::macro(self::MACRO_METHOD, function (ManyToMany $builder) {
60 | return new static($builder->getClassMetadata(), $builder->getRelation());
61 | });
62 | }
63 |
64 | /**
65 | * Execute the build process.
66 | */
67 | public function build()
68 | {
69 | $this->classMetadata->appendExtension($this->getExtensionName(), [
70 | 'groups' => [
71 | $this->fieldName,
72 | ],
73 | ]);
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/src/Extensions/Gedmo/SortablePosition.php:
--------------------------------------------------------------------------------
1 | classMetadata = $classMetadata;
31 | $this->fieldName = $fieldName;
32 | }
33 |
34 | /**
35 | * Return the name of the actual extension.
36 | *
37 | * @return string
38 | */
39 | public function getExtensionName()
40 | {
41 | return FluentDriver::EXTENSION_NAME;
42 | }
43 |
44 | /**
45 | * @return void
46 | */
47 | public static function enable()
48 | {
49 | Field::macro(self::MACRO_METHOD, function (Field $builder) {
50 | return new static($builder->getClassMetadata(), $builder->getName());
51 | });
52 | }
53 |
54 | /**
55 | * Execute the build process.
56 | */
57 | public function build()
58 | {
59 | $this->classMetadata->appendExtension($this->getExtensionName(), [
60 | 'position' => $this->fieldName,
61 | ]);
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/Extensions/Gedmo/Timestampable.php:
--------------------------------------------------------------------------------
1 | getClassMetadata(), $builder->getName());
23 | });
24 |
25 | Timestamps::enable();
26 | }
27 |
28 | /**
29 | * Return the name of the actual extension.
30 | *
31 | * @return string
32 | */
33 | protected function getExtensionName()
34 | {
35 | return FluentDriver::EXTENSION_NAME;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/Extensions/Gedmo/Timestamps.php:
--------------------------------------------------------------------------------
1 | {$type}($createdAt)->timestampable()->onCreate();
21 | $builder->{$type}($updatedAt)->timestampable()->onUpdate();
22 | });
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/Extensions/Gedmo/Translatable.php:
--------------------------------------------------------------------------------
1 | classMetadata = $classMetadata;
32 | $this->fieldName = $fieldName;
33 | }
34 |
35 | /**
36 | * Return the name of the actual extension.
37 | *
38 | * @return string
39 | */
40 | public function getExtensionName()
41 | {
42 | return FluentDriver::EXTENSION_NAME;
43 | }
44 |
45 | /**
46 | * @return void
47 | */
48 | public static function enable()
49 | {
50 | Field::macro(static::MACRO_METHOD, function (Field $builder) {
51 | return new static($builder->getClassMetadata(), $builder->getName());
52 | });
53 |
54 | Locale::enable();
55 | TranslationClass::enable();
56 | }
57 |
58 | /**
59 | * Execute the build process.
60 | */
61 | public function build()
62 | {
63 | $this->classMetadata->appendExtension($this->getExtensionName(), [
64 | 'fields' => [
65 | $this->fieldName,
66 | ],
67 | ]);
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/src/Extensions/Gedmo/TranslationClass.php:
--------------------------------------------------------------------------------
1 | classMetadata = $classMetadata;
33 | $this->class = $class;
34 | }
35 |
36 | /**
37 | * @return void
38 | */
39 | public static function enable()
40 | {
41 | Builder::macro(self::MACRO_METHOD, function (Builder $builder, $class) {
42 | return new static($builder->getClassMetadata(), $class);
43 | });
44 | }
45 |
46 | /**
47 | * Execute the build process.
48 | */
49 | public function build()
50 | {
51 | $this->classMetadata->appendExtension($this->getExtensionName(), [
52 | 'translationClass' => $this->class,
53 | ]);
54 | }
55 |
56 | /**
57 | * Return the name of the actual extension.
58 | *
59 | * @return string
60 | */
61 | public function getExtensionName()
62 | {
63 | return FluentDriver::EXTENSION_NAME;
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/src/Extensions/Gedmo/Tree.php:
--------------------------------------------------------------------------------
1 | builder = $builder;
30 | }
31 |
32 | /**
33 | * Enable extension.
34 | */
35 | public static function enable()
36 | {
37 | Builder::macro(self::MACRO_METHOD, function (Fluent $builder, callable $callback = null) {
38 | $tree = new static($builder);
39 |
40 | if (is_callable($callback)) {
41 | call_user_func($callback, $tree);
42 | }
43 |
44 | return $tree;
45 | });
46 |
47 | NestedSet::enable();
48 | MaterializedPath::enable();
49 | ClosureTable::enable();
50 | }
51 |
52 | /**
53 | * Sets the tree strategy to NestedSet, returning it for further customization.
54 | * See {@link https://en.wikipedia.org/wiki/Nested_set_model} for more information on nested set trees.
55 | *
56 | * @return NestedSet
57 | */
58 | public function asNestedSet()
59 | {
60 | return $this->strategy(new NestedSet($this->builder));
61 | }
62 |
63 | /**
64 | * Sets the tree strategy to MaterializedPath, returning it for further customization.
65 | * See {@link https://bojanz.wordpress.com/2014/04/25/storing-hierarchical-data-materialized-path/} for
66 | * more information on materialized path trees.
67 | *
68 | * @return MaterializedPath
69 | */
70 | public function asMaterializedPath()
71 | {
72 | return $this->strategy(new MaterializedPath($this->builder));
73 | }
74 |
75 | /**
76 | * Sets the tree strategy to ClosureTable, returning it for further customization.
77 | * See {@link https://coderwall.com/p/lixing/closure-tables-for-browsing-trees-in-sql} for more
78 | * information on closure table trees.
79 | *
80 | * @param string $class The class that represents the ClosureTable. You may extend Gedmo's mapped superclass
81 | * for easier usage. {@see Gedmo\Tree\Entity\MappedSuperclass\AbstractClosure}
82 | *
83 | * @return ClosureTable
84 | */
85 | public function asClosureTable($class)
86 | {
87 | return $this->strategy(new ClosureTable($this->builder, $class));
88 | }
89 |
90 | /**
91 | * Execute the build process.
92 | */
93 | public function build()
94 | {
95 | $this->strategy->build();
96 | }
97 |
98 | /**
99 | * @param Buildable $strategy
100 | *
101 | * @return Buildable
102 | */
103 | protected function strategy(Buildable $strategy)
104 | {
105 | return $this->strategy = $strategy;
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/src/Extensions/Gedmo/TreeLeft.php:
--------------------------------------------------------------------------------
1 | classMetadata = $classMetadata;
33 | $this->fieldName = $fieldName;
34 | }
35 |
36 | /**
37 | * Enable TreeLeft.
38 | */
39 | public static function enable()
40 | {
41 | Field::macro(self::MACRO_METHOD, function (Field $field) {
42 | return new static($field->getClassMetadata(), $field->getName());
43 | });
44 | }
45 |
46 | /**
47 | * Execute the build process.
48 | */
49 | public function build()
50 | {
51 | if (!(new Validator())->isValidField($this->classMetadata, $this->fieldName)) {
52 | throw new InvalidMappingException("Tree left field must be 'integer' in class - {$this->classMetadata->name}");
53 | }
54 |
55 | $this->classMetadata->mergeExtension($this->getExtensionName(), [
56 | 'left' => $this->fieldName,
57 | ]);
58 | }
59 |
60 | /**
61 | * Return the name of the actual extension.
62 | *
63 | * @return string
64 | */
65 | public function getExtensionName()
66 | {
67 | return FluentDriver::EXTENSION_NAME;
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/src/Extensions/Gedmo/TreeLevel.php:
--------------------------------------------------------------------------------
1 | classMetadata = $classMetadata;
33 | $this->fieldName = $fieldName;
34 | }
35 |
36 | /**
37 | * Enable TreeLevel.
38 | */
39 | public static function enable()
40 | {
41 | Field::macro(self::MACRO_METHOD, function (Field $field) {
42 | return new static($field->getClassMetadata(), $field->getName());
43 | });
44 | }
45 |
46 | /**
47 | * Execute the build process.
48 | */
49 | public function build()
50 | {
51 | if (!(new Validator())->isValidField($this->classMetadata, $this->fieldName)) {
52 | throw new InvalidMappingException("Tree level field must be 'integer' in class - {$this->classMetadata->name}");
53 | }
54 |
55 | $this->classMetadata->mergeExtension($this->getExtensionName(), [
56 | 'level' => $this->fieldName,
57 | ]);
58 | }
59 |
60 | /**
61 | * Return the name of the actual extension.
62 | *
63 | * @return string
64 | */
65 | public function getExtensionName()
66 | {
67 | return FluentDriver::EXTENSION_NAME;
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/src/Extensions/Gedmo/TreePath.php:
--------------------------------------------------------------------------------
1 | classMetadata = $classMetadata;
55 | $this->fieldName = $fieldName;
56 | $this->separator = $separator;
57 | }
58 |
59 | /**
60 | * Enable TreePath.
61 | */
62 | public static function enable()
63 | {
64 | Field::macro(self::MACRO_METHOD, function (Field $field, $separator = '|') {
65 | return new static($field->getClassMetadata(), $field->getName(), $separator);
66 | });
67 | }
68 |
69 | /**
70 | * @param string $separator
71 | *
72 | * @return TreePath
73 | */
74 | public function separator($separator)
75 | {
76 | $this->separator = $separator;
77 |
78 | return $this;
79 | }
80 |
81 | /**
82 | * @param bool $shouldIt
83 | *
84 | * @return TreePath
85 | */
86 | public function appendId($shouldIt = true)
87 | {
88 | $this->appendId = $shouldIt;
89 |
90 | return $this;
91 | }
92 |
93 | /**
94 | * @param bool $doesIt
95 | *
96 | * @return TreePath
97 | */
98 | public function startsWithSeparator($doesIt = true)
99 | {
100 | $this->startsWithSeparator = $doesIt;
101 |
102 | return $this;
103 | }
104 |
105 | /**
106 | * @param bool $doesIt
107 | *
108 | * @return TreePath
109 | */
110 | public function endsWithSeparator($doesIt = true)
111 | {
112 | $this->endsWithSeparator = $doesIt;
113 |
114 | return $this;
115 | }
116 |
117 | /**
118 | * Execute the build process.
119 | */
120 | public function build()
121 | {
122 | if (strlen($this->separator) > 1) {
123 | throw new InvalidMappingException("Tree Path field - [{$this->fieldName}] Separator {$this->separator} is invalid. It must be only one character long.");
124 | }
125 |
126 | $this->classMetadata->mergeExtension($this->getExtensionName(), [
127 | 'path' => $this->fieldName,
128 | 'path_separator' => $this->separator,
129 | 'path_append_id' => $this->appendId,
130 | 'path_starts_with_separator' => $this->startsWithSeparator,
131 | 'path_ends_with_separator' => $this->endsWithSeparator,
132 | ]);
133 | }
134 |
135 | /**
136 | * Return the name of the actual extension.
137 | *
138 | * @return string
139 | */
140 | protected function getExtensionName()
141 | {
142 | return FluentDriver::EXTENSION_NAME;
143 | }
144 | }
145 |
--------------------------------------------------------------------------------
/src/Extensions/Gedmo/TreePathHash.php:
--------------------------------------------------------------------------------
1 | classMetadata = $classMetadata;
31 | $this->fieldName = $fieldName;
32 | }
33 |
34 | /**
35 | * Enable TreePathHash.
36 | */
37 | public static function enable()
38 | {
39 | Field::macro(self::MACRO_METHOD, function (Field $field) {
40 | return new static($field->getClassMetadata(), $field->getName());
41 | });
42 | }
43 |
44 | /**
45 | * Execute the build process.
46 | */
47 | public function build()
48 | {
49 | $this->classMetadata->mergeExtension($this->getExtensionName(), [
50 | 'path_hash' => $this->fieldName,
51 | ]);
52 | }
53 |
54 | /**
55 | * Return the name of the actual extension.
56 | *
57 | * @return string
58 | */
59 | public function getExtensionName()
60 | {
61 | return FluentDriver::EXTENSION_NAME;
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/Extensions/Gedmo/TreePathSource.php:
--------------------------------------------------------------------------------
1 | classMetadata = $classMetadata;
33 | $this->fieldName = $fieldName;
34 | }
35 |
36 | /**
37 | * Enable TreePathSource.
38 | */
39 | public static function enable()
40 | {
41 | Field::macro(self::MACRO_METHOD, function (Field $field) {
42 | return new static($field->getClassMetadata(), $field->getName());
43 | });
44 | }
45 |
46 | /**
47 | * Execute the build process.
48 | */
49 | public function build()
50 | {
51 | if (!(new Validator())->isValidFieldForPathSource($this->classMetadata, $this->fieldName)) {
52 | throw new InvalidMappingException(
53 | "Tree PathSource field - [{$this->fieldName}] type is not valid. It can be any of the integer variants, double, float or string in class - {$this->classMetadata->name}"
54 | );
55 | }
56 |
57 | $this->classMetadata->mergeExtension($this->getExtensionName(), [
58 | 'path_source' => $this->fieldName,
59 | ]);
60 | }
61 |
62 | /**
63 | * Return the name of the actual extension.
64 | *
65 | * @return string
66 | */
67 | public function getExtensionName()
68 | {
69 | return FluentDriver::EXTENSION_NAME;
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/src/Extensions/Gedmo/TreeRight.php:
--------------------------------------------------------------------------------
1 | classMetadata = $classMetadata;
33 | $this->fieldName = $fieldName;
34 | }
35 |
36 | /**
37 | * Enable TreeRight.
38 | */
39 | public static function enable()
40 | {
41 | Field::macro(self::MACRO_METHOD, function (Field $field) {
42 | return new static($field->getClassMetadata(), $field->getName());
43 | });
44 | }
45 |
46 | /**
47 | * Execute the build process.
48 | */
49 | public function build()
50 | {
51 | if (!(new Validator())->isValidField($this->classMetadata, $this->fieldName)) {
52 | throw new InvalidMappingException("Tree right field must be 'integer' in class - {$this->classMetadata->name}");
53 | }
54 |
55 | $this->classMetadata->mergeExtension($this->getExtensionName(), [
56 | 'right' => $this->fieldName,
57 | ]);
58 | }
59 |
60 | /**
61 | * Return the name of the actual extension.
62 | *
63 | * @return string
64 | */
65 | public function getExtensionName()
66 | {
67 | return FluentDriver::EXTENSION_NAME;
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/src/Extensions/Gedmo/TreeSelfReference.php:
--------------------------------------------------------------------------------
1 | classMetadata = $classMetadata;
36 | $this->fieldName = $fieldName;
37 | $this->key = $key;
38 | }
39 |
40 | /**
41 | * Enable TreeRoot and TreeParent macros.
42 | *
43 | * @return void
44 | */
45 | public static function enable()
46 | {
47 | static::enableRoot();
48 | static::enableParent();
49 | }
50 |
51 | /**
52 | * Enable only the TreeRoot macro.
53 | *
54 | * @return void
55 | */
56 | public static function enableRoot()
57 | {
58 | static::addMacro('treeRoot', 'root');
59 | }
60 |
61 | /**
62 | * Enable only the TreeParent macro.
63 | *
64 | * @return void
65 | */
66 | public static function enableParent()
67 | {
68 | static::addMacro('treeParent', 'parent');
69 | }
70 |
71 | /**
72 | * @param string $method
73 | * @param string $key
74 | *
75 | * @return void
76 | */
77 | protected static function addMacro($method, $key)
78 | {
79 | Field::macro($method, function (Field $field) use ($key) {
80 | $field->nullable();
81 |
82 | return new static($field->getClassMetadata(), $field->getName(), $key);
83 | });
84 |
85 | ManyToOne::macro($method, function (ManyToOne $relation) use ($key) {
86 | $relation->nullable();
87 |
88 | return new static($relation->getClassMetadata(), $relation->getRelation(), $key);
89 | });
90 | }
91 |
92 | /**
93 | * Execute the build process.
94 | */
95 | public function build()
96 | {
97 | $this->classMetadata->mergeExtension($this->getExtensionName(), [
98 | $this->key => $this->fieldName,
99 | ]);
100 | }
101 |
102 | /**
103 | * Return the name of the actual extension.
104 | *
105 | * @return string
106 | */
107 | public function getExtensionName()
108 | {
109 | return FluentDriver::EXTENSION_NAME;
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/src/Extensions/Gedmo/TreeStrategy.php:
--------------------------------------------------------------------------------
1 | builder = $builder;
35 | }
36 |
37 | /**
38 | * Enable extension.
39 | */
40 | public static function enable()
41 | {
42 | TreeLevel::enable();
43 | TreeSelfReference::enableParent();
44 | }
45 |
46 | /**
47 | * @param string $field
48 | * @param string $type
49 | * @param callable|null $callback
50 | *
51 | * @throws InvalidMappingException
52 | *
53 | * @return $this
54 | */
55 | public function level($field = 'level', $type = 'integer', callable $callback = null)
56 | {
57 | $this->validateNumericField($type, $field);
58 |
59 | $this->mapField($type, $field, $callback);
60 |
61 | $this->level = $field;
62 |
63 | return $this;
64 | }
65 |
66 | /**
67 | * @param string $field
68 | * @param callable|null $callback
69 | *
70 | * @return $this
71 | */
72 | public function parent($field = 'parent', callable $callback = null)
73 | {
74 | $this->addSelfReferencingRelation($field, $callback);
75 |
76 | $this->parent = $field;
77 |
78 | return $this;
79 | }
80 |
81 | /**
82 | * {@inheritdoc}
83 | */
84 | public function build()
85 | {
86 | $this->defaults();
87 |
88 | $this->getClassMetadata()->mergeExtension($this->getExtensionName(), $this->getValues());
89 | }
90 |
91 | /**
92 | * Return the name of the actual extension.
93 | *
94 | * @return string
95 | */
96 | protected function getExtensionName()
97 | {
98 | return FluentDriver::EXTENSION_NAME;
99 | }
100 |
101 | /**
102 | * @param string $type
103 | * @param string $field
104 | * @param callable|null $callback
105 | * @param bool|false $nullable
106 | */
107 | protected function mapField($type, $field, callable $callback = null, $nullable = false)
108 | {
109 | $this->builder->field($type, $field, $callback)->nullable($nullable);
110 | }
111 |
112 | /**
113 | * @param string $type
114 | * @param string $field
115 | *
116 | * @throws InvalidMappingException
117 | */
118 | protected function validateNumericField($type, $field)
119 | {
120 | if (!in_array($type, ['integer', 'bigint', 'smallint'])) {
121 | throw new InvalidMappingException("Invalid type [$type] for the [$field] field. Must be a (small, big) integer type.");
122 | }
123 | }
124 |
125 | /**
126 | * Returns the name of the mapped class.
127 | *
128 | * @return string
129 | */
130 | protected function myself()
131 | {
132 | return $this->getClassMetadata()->name;
133 | }
134 |
135 | /**
136 | * @param string $field
137 | * @param callable|null $callback
138 | */
139 | protected function addSelfReferencingRelation($field, callable $callback = null)
140 | {
141 | $this->builder->belongsTo($this->myself(), $field, $callback)->nullable();
142 | }
143 |
144 | /**
145 | * @return ExtensibleClassMetadata
146 | */
147 | protected function getClassMetadata()
148 | {
149 | return $this->builder->getBuilder()->getClassMetadata();
150 | }
151 |
152 | /**
153 | * @return array
154 | */
155 | protected function getValues()
156 | {
157 | $values = [];
158 |
159 | if ($this->parent) {
160 | $values['parent'] = $this->parent;
161 | }
162 |
163 | if ($this->level) {
164 | $values['level'] = $this->level;
165 | }
166 |
167 | return $values;
168 | }
169 |
170 | /**
171 | * Check if a given key is already configured for this extension.
172 | *
173 | * @param string $key
174 | *
175 | * @return bool
176 | */
177 | protected function alreadyConfigured($key)
178 | {
179 | $config = $this->getClassMetadata()->getExtension($this->getExtensionName());
180 |
181 | return isset($config[$key]);
182 | }
183 |
184 | /**
185 | * Check if parent is missing from both configuration and the current tree strategy builder.
186 | *
187 | * @return bool
188 | */
189 | protected function isMissingParent()
190 | {
191 | return !$this->alreadyConfigured('parent') && !$this->parent;
192 | }
193 |
194 | /**
195 | * Set the default fields to fill if they were not configured.
196 | * All Tree strategies share one common required field: the parent reference.
197 | *
198 | * @return void
199 | */
200 | protected function defaults()
201 | {
202 | if ($this->isMissingParent()) {
203 | $this->parent();
204 | }
205 | }
206 | }
207 |
--------------------------------------------------------------------------------
/src/Extensions/Gedmo/UploadableFile.php:
--------------------------------------------------------------------------------
1 | validateType($type);
43 |
44 | $this->classMetadata = $classMetadata;
45 | $this->fieldName = $fieldName;
46 | $this->type = "file{$type}Field";
47 | }
48 |
49 | /**
50 | * Enable the UploadableFile extension.
51 | *
52 | * @return void
53 | */
54 | public static function enable()
55 | {
56 | foreach (self::$validTypes as $type) {
57 | Field::macro("asFile$type", function (Field $builder) use ($type) {
58 | return new static($builder->getClassMetadata(), $builder->getName(), $type);
59 | });
60 | }
61 | }
62 |
63 | /**
64 | * Execute the build process.
65 | */
66 | public function build()
67 | {
68 | $this->classMetadata->appendExtension(UploadableDriver::EXTENSION_NAME, [
69 | $this->type => $this->fieldName,
70 | ]);
71 | }
72 |
73 | /**
74 | * Validate the given type of file field.
75 | *
76 | * @param string $type
77 | *
78 | * @return void
79 | */
80 | private function validateType($type)
81 | {
82 | if (!in_array($type, self::$validTypes)) {
83 | throw new InvalidMappingException(
84 | 'Invalid uploadable field type reference. Must be one of: '.implode(', ', self::$validTypes)
85 | );
86 | }
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/src/Extensions/Gedmo/Versioned.php:
--------------------------------------------------------------------------------
1 | classMetadata = $classMetadata;
35 | $this->fieldName = $fieldName;
36 | }
37 |
38 | public static function enable()
39 | {
40 | Field::macro(self::MACRO_METHOD, function (Field $builder) {
41 | return new static($builder->getClassMetadata(), $builder->getName());
42 | });
43 |
44 | ManyToOne::macro(self::MACRO_METHOD, function (ManyToOne $builder) {
45 | return new static($builder->getClassMetadata(), $builder->getRelation());
46 | });
47 |
48 | OneToOne::macro(self::MACRO_METHOD, function (OneToOne $builder) {
49 | return new static($builder->getClassMetadata(), $builder->getRelation());
50 | });
51 | }
52 |
53 | /**
54 | * Execute the build process.
55 | */
56 | public function build()
57 | {
58 | $config = $this->classMetadata->getExtension(Fluent::EXTENSION_NAME);
59 |
60 | $config['loggable'] = true;
61 | $config['versioned'] = array_unique(array_merge(
62 | isset($config['versioned']) ? $config['versioned'] : [],
63 | [
64 | $this->fieldName,
65 | ]
66 | ));
67 |
68 | $this->classMetadata->addExtension(Fluent::EXTENSION_NAME, $config);
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/src/Extensions/GedmoExtensions.php:
--------------------------------------------------------------------------------
1 | addDriver(
88 | new FluentDriver($mappings),
89 | 'Gedmo'
90 | );
91 |
92 | foreach (self::$extensions as $extension) {
93 | $extension::enable();
94 | }
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/src/FluentDriver.php:
--------------------------------------------------------------------------------
1 | fluentFactory = function (ClassMetadata $metadata) use ($namingStrategy) {
38 | return new Builder(new ClassMetadataBuilder($metadata), $namingStrategy);
39 | };
40 |
41 | $this->mappers = new MapperSet();
42 | $this->addMappings($mappings);
43 | }
44 |
45 | /**
46 | * Loads the metadata for the specified class into the provided container.
47 | *
48 | * @param string $className
49 | * @param ClassMetadata $metadata
50 | */
51 | public function loadMetadataForClass($className, ClassMetadata $metadata)
52 | {
53 | $this->mappers->getMapperFor($className)->map(
54 | $this->getFluent($metadata)
55 | );
56 | }
57 |
58 | /**
59 | * Gets the names of all mapped classes known to this driver.
60 | *
61 | * @throws MappingException
62 | *
63 | * @return string[] The names of all mapped classes known to this driver.
64 | */
65 | public function getAllClassNames()
66 | {
67 | return $this->mappers->getClassNames();
68 | }
69 |
70 | /**
71 | * Returns whether the class with the specified name should have its metadata loaded.
72 | * This is only the case if it is either mapped as an Entity or a MappedSuperclass.
73 | *
74 | * @param string $className
75 | *
76 | * @return bool
77 | */
78 | public function isTransient($className)
79 | {
80 | return
81 | !$this->mappers->hasMapperFor($className) ||
82 | $this->mappers->getMapperFor($className)->isTransient();
83 | }
84 |
85 | /**
86 | * @param string[] $mappings
87 | */
88 | public function addMappings(array $mappings = [])
89 | {
90 | foreach ($mappings as $class) {
91 | if (!class_exists($class)) {
92 | throw new InvalidArgumentException("Mapping class [{$class}] does not exist");
93 | }
94 |
95 | $mapping = new $class();
96 |
97 | if (!$mapping instanceof Mapping) {
98 | throw new InvalidArgumentException("Mapping class [{$class}] should implement ".Mapping::class);
99 | }
100 |
101 | $this->addMapping($mapping);
102 | }
103 | }
104 |
105 | /**
106 | * @param Mapping $mapping
107 | *
108 | * @throws MappingException
109 | *
110 | * @return void
111 | */
112 | public function addMapping(Mapping $mapping)
113 | {
114 | $this->mappers->add($mapping);
115 | }
116 |
117 | /**
118 | * @return MapperSet
119 | */
120 | public function getMappers()
121 | {
122 | return $this->mappers;
123 | }
124 |
125 | /**
126 | * Override the default Fluent factory method with a custom one.
127 | * Use this to implement your own Fluent builder.
128 | * The method will receive a ClassMetadata object as its only argument.
129 | *
130 | * @param callable $factory
131 | */
132 | public function setFluentFactory(callable $factory)
133 | {
134 | $this->fluentFactory = $factory;
135 | }
136 |
137 | /**
138 | * @param ClassMetadata $metadata
139 | *
140 | * @return Fluent
141 | */
142 | protected function getFluent(ClassMetadata $metadata)
143 | {
144 | return call_user_func($this->fluentFactory, $metadata);
145 | }
146 | }
147 |
--------------------------------------------------------------------------------
/src/MappedSuperClassMapping.php:
--------------------------------------------------------------------------------
1 | addMapper($this->mapFor(), new MappedSuperClassMapper($this));
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/Mappers/AbstractMapper.php:
--------------------------------------------------------------------------------
1 | mapping = $mapping;
22 | }
23 |
24 | /**
25 | * @param Fluent $builder
26 | */
27 | public function map(Fluent $builder)
28 | {
29 | $this->setType($builder->getBuilder());
30 |
31 | $this->mapping->map($builder);
32 |
33 | $builder->build();
34 | }
35 |
36 | /**
37 | * @param ClassMetadataBuilder $metadata
38 | */
39 | protected function setType(ClassMetadataBuilder $metadata)
40 | {
41 | // By default nothing has to be done
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/Mappers/EmbeddableMapper.php:
--------------------------------------------------------------------------------
1 | setEmbeddable();
15 | }
16 |
17 | /**
18 | * Returns whether the class with the specified name should have its metadata loaded.
19 | * This is only the case if it is either mapped as an Entity or a MappedSuperclass.
20 | *
21 | * @return bool
22 | */
23 | public function isTransient()
24 | {
25 | return true;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/Mappers/EntityMapper.php:
--------------------------------------------------------------------------------
1 | setMappedSuperClass();
15 | }
16 |
17 | /**
18 | * Returns whether the class with the specified name should have its metadata loaded.
19 | * This is only the case if it is either mapped as an Entity or a MappedSuperclass.
20 | *
21 | * @return bool
22 | */
23 | public function isTransient()
24 | {
25 | return false;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/Mappers/Mapper.php:
--------------------------------------------------------------------------------
1 | addMapperTo($this);
26 | }
27 |
28 | /**
29 | * @param string $className
30 | *
31 | * @throws MappingException
32 | *
33 | * @return Mapper
34 | */
35 | public function getMapperFor($className)
36 | {
37 | if (!$this->hasMapperFor($className)) {
38 | throw new MappingException(sprintf(
39 | 'Class [%s] does not have a mapping configuration. '.
40 | 'Make sure you create a Mapping class that extends either %s, %s or %s. '.
41 | 'If you are using inheritance mapping, remember to create mappings '.
42 | 'for every child of the inheritance tree.',
43 | $className,
44 | EntityMapping::class,
45 | EmbeddableMapping::class,
46 | MappedSuperClassMapping::class
47 | ));
48 | }
49 |
50 | return $this->mappers[$className];
51 | }
52 |
53 | /**
54 | * @param string $className
55 | *
56 | * @return bool
57 | */
58 | public function hasMapperFor($className)
59 | {
60 | return isset($this->mappers[$className]);
61 | }
62 |
63 | /**
64 | * @return bool
65 | */
66 | public function hasMappers()
67 | {
68 | return count($this->mappers) > 0;
69 | }
70 |
71 | /**
72 | * @return Mapper[]
73 | */
74 | public function getMappers()
75 | {
76 | return $this->mappers;
77 | }
78 |
79 | /**
80 | * @return string[]
81 | */
82 | public function getClassNames()
83 | {
84 | return array_keys($this->mappers);
85 | }
86 |
87 | /**
88 | * Add a mapper to the given class.
89 | *
90 | * @param string $class
91 | * @param Mapper $mapper
92 | */
93 | public function addMapper($class, Mapper $mapper)
94 | {
95 | $this->mappers[$class] = $mapper;
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/src/Mapping.php:
--------------------------------------------------------------------------------
1 | entity = $entity;
66 | $this->builder = $builder;
67 | $this->relation = $relation;
68 | $this->namingStrategy = $namingStrategy;
69 | $this->association = $this->createAssociation($builder, $relation, $entity);
70 | }
71 |
72 | /**
73 | * @param ClassMetadataBuilder $builder
74 | * @param string $relation
75 | * @param string $entity
76 | *
77 | * @return AssociationBuilder
78 | */
79 | abstract protected function createAssociation(ClassMetadataBuilder $builder, $relation, $entity);
80 |
81 | /**
82 | * @param string[] $cascade one of "persist", "remove", "merge", "detach", "refresh" or "ALL"
83 | *
84 | * @return $this
85 | */
86 | public function cascade(array $cascade)
87 | {
88 | foreach ($cascade as $name) {
89 | $method = 'cascade'.(InflectorFactory::create()->build())->classify(strtolower($name));
90 |
91 | if (!method_exists($this->association, $method)) {
92 | throw new InvalidArgumentException('Cascade ['.$name.'] does not exist');
93 | }
94 |
95 | $this->{$method}();
96 | }
97 |
98 | return $this;
99 | }
100 |
101 | /**
102 | * @param string $strategy one of "LAZY", "EAGER", "EXTRA_LAZY"
103 | *
104 | * @return $this
105 | */
106 | public function fetch($strategy)
107 | {
108 | $method = 'fetch'.(InflectorFactory::create()->build())->classify(strtolower($strategy));
109 |
110 | if (!method_exists($this->association, $method)) {
111 | throw new InvalidArgumentException('Fetch ['.$strategy.'] does not exist');
112 | }
113 |
114 | $this->{$method}();
115 |
116 | return $this;
117 | }
118 |
119 | /**
120 | * @return ClassMetadataBuilder
121 | */
122 | public function getBuilder()
123 | {
124 | return $this->builder;
125 | }
126 |
127 | /**
128 | * @return \Doctrine\ORM\Mapping\ClassMetadata|ExtensibleClassMetadata
129 | */
130 | public function getClassMetadata()
131 | {
132 | return $this->builder->getClassMetadata();
133 | }
134 |
135 | /**
136 | * @return AssociationBuilder
137 | */
138 | public function getAssociation()
139 | {
140 | return $this->association;
141 | }
142 |
143 | /**
144 | * @param string $usage
145 | * @param string|null $region
146 | *
147 | * @return $this
148 | */
149 | public function cache($usage = 'READ_ONLY', $region = null)
150 | {
151 | $cache = new AssociationCache(
152 | $this->builder->getClassMetadata(),
153 | $this->relation,
154 | $usage,
155 | $region
156 | );
157 |
158 | $this->queue($cache);
159 |
160 | return $this;
161 | }
162 |
163 | /**
164 | * Execute the build process for all queued buildables.
165 | */
166 | public function build()
167 | {
168 | $this->getAssociation()->build();
169 |
170 | $this->buildQueued();
171 | }
172 |
173 | /**
174 | * Magic call method works as a proxy for the Doctrine associationBuilder.
175 | *
176 | * @param string $method
177 | * @param array $args
178 | *
179 | * @throws BadMethodCallException
180 | *
181 | * @return $this
182 | */
183 | public function __call($method, $args)
184 | {
185 | if (method_exists($this->getAssociation(), $method)) {
186 | call_user_func_array([$this->getAssociation(), $method], $args);
187 |
188 | return $this;
189 | }
190 |
191 | throw new BadMethodCallException("Relation method [{$method}] does not exist.");
192 | }
193 |
194 | /**
195 | * @return NamingStrategy
196 | */
197 | public function getNamingStrategy()
198 | {
199 | return $this->namingStrategy;
200 | }
201 |
202 | /**
203 | * @return string
204 | */
205 | public function getRelation()
206 | {
207 | return $this->relation;
208 | }
209 | }
210 |
--------------------------------------------------------------------------------
/src/Relations/AssociationCache.php:
--------------------------------------------------------------------------------
1 | ClassMetadataInfo::CACHE_USAGE_READ_ONLY,
27 | 'NONSTRICT_READ_WRITE' => ClassMetadataInfo::CACHE_USAGE_NONSTRICT_READ_WRITE,
28 | 'READ_WRITE' => ClassMetadataInfo::CACHE_USAGE_READ_WRITE,
29 | ];
30 |
31 | /**
32 | * @var string
33 | */
34 | protected $field;
35 |
36 | /**
37 | * @var ClassMetadata
38 | */
39 | protected $metadata;
40 |
41 | /**
42 | * @param ClassMetadata $metadata
43 | * @param string $field
44 | * @param string|int $usage
45 | * @param string|null $region
46 | */
47 | public function __construct(ClassMetadata $metadata, $field, $usage = 'READ_ONLY', $region = null)
48 | {
49 | $this->field = $field;
50 | $this->metadata = $metadata;
51 | $this->setRegion($region);
52 | $this->setUsage($usage);
53 | }
54 |
55 | /**
56 | * @return string
57 | */
58 | public function getUsage()
59 | {
60 | return $this->usage;
61 | }
62 |
63 | /**
64 | * @param string $usage
65 | *
66 | * @throws InvalidArgumentException
67 | *
68 | * @return AssociationCache
69 | */
70 | public function setUsage($usage)
71 | {
72 | if (is_int($usage)) {
73 | $this->validate($usage, $this->usages);
74 | } else {
75 | $this->validate($usage, array_keys($this->usages));
76 | $usage = $this->usages[$usage];
77 | }
78 |
79 | $this->usage = $usage;
80 |
81 | return $this;
82 | }
83 |
84 | /**
85 | * @return string
86 | */
87 | public function getRegion()
88 | {
89 | return $this->region;
90 | }
91 |
92 | /**
93 | * @param string $region
94 | *
95 | * @return AssociationCache
96 | */
97 | public function setRegion($region)
98 | {
99 | $this->region = $region;
100 |
101 | return $this;
102 | }
103 |
104 | /**
105 | * Execute the build process.
106 | */
107 | public function build()
108 | {
109 | $this->metadata->enableAssociationCache($this->field, [
110 | 'usage' => $this->getUsage(),
111 | 'region' => $this->getRegion(),
112 | ]);
113 | }
114 |
115 | /**
116 | * @param string|int $usage
117 | * @param array $usages
118 | *
119 | * @return mixed
120 | */
121 | protected function validate($usage, array $usages)
122 | {
123 | if (!in_array($usage, $usages)) {
124 | throw new InvalidArgumentException(
125 | '['.$usage.'] is not a valid cache usage. Available: '.implode(', ', array_keys($this->usages))
126 | );
127 | }
128 |
129 | return $usage;
130 | }
131 | }
132 |
--------------------------------------------------------------------------------
/src/Relations/JoinColumn.php:
--------------------------------------------------------------------------------
1 | namingStrategy = $namingStrategy;
70 | $this->relation = $relation;
71 | $this->joinColumn = $joinColumn;
72 | $this->referenceColumn = $referenceColumn;
73 | $this->nullable = $nullable;
74 | $this->unique = $unique;
75 | $this->onDelete = $onDelete;
76 | $this->columnDefinition = $columnDefinition;
77 | }
78 |
79 | /**
80 | * @param string $foreignKey
81 | *
82 | * @return $this
83 | */
84 | public function foreignKey($foreignKey)
85 | {
86 | $this->joinColumn = $foreignKey;
87 |
88 | return $this;
89 | }
90 |
91 | /**
92 | * @param string $foreignKey
93 | *
94 | * @return $this
95 | */
96 | public function target($foreignKey)
97 | {
98 | return $this->foreignKey($foreignKey);
99 | }
100 |
101 | /**
102 | * @param string $localKey
103 | *
104 | * @return $this
105 | */
106 | public function localKey($localKey)
107 | {
108 | $this->referenceColumn = $localKey;
109 |
110 | return $this;
111 | }
112 |
113 | /**
114 | * @param string $localKey
115 | *
116 | * @return $this
117 | */
118 | public function source($localKey)
119 | {
120 | return $this->localKey($localKey);
121 | }
122 |
123 | /**
124 | * @return string
125 | */
126 | public function getJoinColumn()
127 | {
128 | return $this->joinColumn ?: $this->namingStrategy->joinColumnName($this->relation);
129 | }
130 |
131 | /**
132 | * @param string $joinColumn
133 | *
134 | * @return $this
135 | */
136 | public function setJoinColumn($joinColumn)
137 | {
138 | $this->joinColumn = $joinColumn;
139 |
140 | return $this;
141 | }
142 |
143 | /**
144 | * @return string
145 | */
146 | public function getReferenceColumn()
147 | {
148 | return $this->referenceColumn ?: $this->namingStrategy->referenceColumnName();
149 | }
150 |
151 | /**
152 | * @param string $referenceColumn
153 | *
154 | * @return $this
155 | */
156 | public function setReferenceColumn($referenceColumn)
157 | {
158 | $this->referenceColumn = $referenceColumn;
159 |
160 | return $this;
161 | }
162 |
163 | /**
164 | * @return $this
165 | */
166 | public function nullable()
167 | {
168 | $this->nullable = true;
169 |
170 | return $this;
171 | }
172 |
173 | /**
174 | * @return bool
175 | */
176 | public function isNullable()
177 | {
178 | return $this->nullable;
179 | }
180 |
181 | /**
182 | * @return bool
183 | */
184 | public function isUnique()
185 | {
186 | return $this->unique;
187 | }
188 |
189 | /**
190 | * @return $this
191 | */
192 | public function unique()
193 | {
194 | $this->unique = true;
195 |
196 | return $this;
197 | }
198 |
199 | /**
200 | * @return string|null
201 | */
202 | public function getOnDelete()
203 | {
204 | return $this->onDelete;
205 | }
206 |
207 | /**
208 | * @param string|null $onDelete
209 | *
210 | * @return $this
211 | */
212 | public function onDelete($onDelete = null)
213 | {
214 | $this->onDelete = $onDelete;
215 |
216 | return $this;
217 | }
218 |
219 | /**
220 | * @return string|null
221 | */
222 | public function getColumnDefinition()
223 | {
224 | return $this->columnDefinition;
225 | }
226 | }
227 |
--------------------------------------------------------------------------------
/src/Relations/ManyToMany.php:
--------------------------------------------------------------------------------
1 | builder->createManyToMany($relation, $entity);
48 | }
49 |
50 | /**
51 | * @param string $table
52 | *
53 | * @return $this
54 | */
55 | public function joinTable($table)
56 | {
57 | $this->association->setJoinTable($table);
58 |
59 | return $this;
60 | }
61 |
62 | /**
63 | * @param string $joinColumn
64 | * @param string $references
65 | * @param bool $unique
66 | *
67 | * @return $this
68 | */
69 | public function joinColumn($joinColumn, $references = 'id', $unique = false)
70 | {
71 | $this->addJoinColumn(null, $joinColumn, $references, false, $unique);
72 |
73 | return $this;
74 | }
75 |
76 | /**
77 | * @param string $foreignKey
78 | * @param string $references
79 | * @param bool $unique
80 | *
81 | * @return $this
82 | */
83 | public function foreignKey($foreignKey, $references = 'id', $unique = false)
84 | {
85 | return $this->joinColumn($foreignKey, $references, $unique);
86 | }
87 |
88 | /**
89 | * @param string $foreignKey
90 | * @param string $references
91 | * @param bool $unique
92 | *
93 | * @return $this
94 | */
95 | public function source($foreignKey, $references = 'id', $unique = false)
96 | {
97 | return $this->joinColumn($foreignKey, $references, $unique);
98 | }
99 |
100 | /**
101 | * @param string $inverseKey
102 | * @param string $references
103 | * @param bool $unique
104 | *
105 | * @return $this
106 | */
107 | public function inverseKey($inverseKey, $references = 'id', $unique = false)
108 | {
109 | $this->association->addInverseJoinColumn($inverseKey, $references, false, $unique);
110 |
111 | return $this;
112 | }
113 |
114 | /**
115 | * @param string $inverseKey
116 | * @param string $references
117 | * @param bool $unique
118 | *
119 | * @return $this
120 | */
121 | public function target($inverseKey, $references = 'id', $unique = false)
122 | {
123 | return $this->inverseKey($inverseKey, $references, $unique);
124 | }
125 |
126 | /**
127 | * Magic call method works as a proxy for the Doctrine associationBuilder.
128 | *
129 | * @param string $method
130 | * @param array $args
131 | *
132 | * @throws \BadMethodCallException
133 | *
134 | * @return $this
135 | */
136 | public function __call($method, $args)
137 | {
138 | if ($this->hasMacro($method)) {
139 | return $this->queueMacro($method, $args);
140 | }
141 |
142 | return parent::__call($method, $args);
143 | }
144 | }
145 |
--------------------------------------------------------------------------------
/src/Relations/ManyToOne.php:
--------------------------------------------------------------------------------
1 | addJoinColumn($relation);
47 | }
48 |
49 | /**
50 | * @param ClassMetadataBuilder $builder
51 | * @param string $relation
52 | * @param string $entity
53 | *
54 | * @return AssociationBuilder
55 | */
56 | protected function createAssociation(ClassMetadataBuilder $builder, $relation, $entity)
57 | {
58 | return $this->builder->createManyToOne(
59 | $relation,
60 | $entity
61 | );
62 | }
63 |
64 | /**
65 | * @param callable|null $callback
66 | *
67 | * @return JoinColumn|false
68 | */
69 | public function getJoinColumn(callable $callback = null)
70 | {
71 | $joinColumn = reset($this->joinColumns);
72 |
73 | if (is_callable($callback)) {
74 | $callback($joinColumn);
75 | }
76 |
77 | return $joinColumn;
78 | }
79 |
80 | /**
81 | * Magic call method works as a proxy for the Doctrine associationBuilder.
82 | *
83 | * @param string $method
84 | * @param array $args
85 | *
86 | * @throws \BadMethodCallException
87 | *
88 | * @return $this
89 | */
90 | public function __call($method, $args)
91 | {
92 | if ($this->hasMacro($method)) {
93 | return $this->queueMacro($method, $args);
94 | }
95 |
96 | if (method_exists($this->getJoinColumn(), $method)) {
97 | call_user_func_array([$this->getJoinColumn(), $method], $args);
98 |
99 | return $this;
100 | }
101 |
102 | return parent::__call($method, $args);
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/src/Relations/OneToMany.php:
--------------------------------------------------------------------------------
1 | builder->createOneToMany($relation, $entity);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/Relations/OneToOne.php:
--------------------------------------------------------------------------------
1 | builder->createOneToOne(
35 | $relation,
36 | $entity
37 | );
38 | }
39 |
40 | /**
41 | * @param string $method
42 | * @param array $args
43 | *
44 | * @throws \BadMethodCallException
45 | *
46 | * @return $this
47 | */
48 | public function __call($method, $args)
49 | {
50 | if ($this->hasMacro($method)) {
51 | return $this->queueMacro($method, $args);
52 | }
53 |
54 | return parent::__call($method, $args);
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/Relations/Relation.php:
--------------------------------------------------------------------------------
1 | getAssociation()->setIndexBy($index);
15 |
16 | return $this;
17 | }
18 |
19 | /**
20 | * @return \Doctrine\ORM\Mapping\Builder\OneToManyAssociationBuilder
21 | */
22 | abstract public function getAssociation();
23 | }
24 |
--------------------------------------------------------------------------------
/src/Relations/Traits/ManyTo.php:
--------------------------------------------------------------------------------
1 | getJoinColumns() as $column) {
20 | $this->getAssociation()->addJoinColumn(
21 | $column->getJoinColumn(),
22 | $column->getReferenceColumn(),
23 | $column->isNullable(),
24 | $column->isUnique(),
25 | $column->getOnDelete(),
26 | $column->getColumnDefinition()
27 | );
28 | }
29 |
30 | parent::build();
31 | }
32 |
33 | /**
34 | * @param string $relation
35 | * @param string|null $joinColumn
36 | * @param string|null $referenceColumn
37 | * @param bool|false $nullable
38 | * @param bool|false $unique
39 | * @param string|null $onDelete
40 | * @param string|null $columnDefinition
41 | *
42 | * @return $this
43 | */
44 | public function addJoinColumn(
45 | $relation,
46 | $joinColumn = null,
47 | $referenceColumn = null,
48 | $nullable = false,
49 | $unique = false,
50 | $onDelete = null,
51 | $columnDefinition = null
52 | ) {
53 | $joinColumn = new JoinColumn(
54 | $this->getNamingStrategy(),
55 | $relation,
56 | $joinColumn,
57 | $referenceColumn,
58 | $nullable,
59 | $unique,
60 | $onDelete,
61 | $columnDefinition
62 | );
63 |
64 | $this->pushJoinColumn($joinColumn);
65 |
66 | return $this;
67 | }
68 |
69 | /**
70 | * @param JoinColumn $column
71 | */
72 | protected function pushJoinColumn(JoinColumn $column)
73 | {
74 | $this->joinColumns[] = $column;
75 | }
76 |
77 | /**
78 | * @return JoinColumn[]
79 | */
80 | public function getJoinColumns()
81 | {
82 | return $this->joinColumns;
83 | }
84 |
85 | /**
86 | * @return \Doctrine\ORM\Mapping\Builder\AssociationBuilder
87 | */
88 | abstract public function getAssociation();
89 |
90 | /**
91 | * @return \Doctrine\ORM\Mapping\NamingStrategy
92 | */
93 | abstract public function getNamingStrategy();
94 | }
95 |
--------------------------------------------------------------------------------
/src/Relations/Traits/Orderable.php:
--------------------------------------------------------------------------------
1 | getAssociation()->setOrderBy([
16 | $name => $order,
17 | ]);
18 |
19 | return $this;
20 | }
21 |
22 | /**
23 | * @return \Doctrine\ORM\Mapping\Builder\OneToManyAssociationBuilder
24 | */
25 | abstract public function getAssociation();
26 | }
27 |
--------------------------------------------------------------------------------
/src/Relations/Traits/Ownable.php:
--------------------------------------------------------------------------------
1 | getAssociation()->mappedBy($relation);
15 |
16 | return $this;
17 | }
18 |
19 | /**
20 | * @return \Doctrine\ORM\Mapping\Builder\AssociationBuilder
21 | */
22 | abstract public function getAssociation();
23 | }
24 |
--------------------------------------------------------------------------------
/src/Relations/Traits/Owning.php:
--------------------------------------------------------------------------------
1 | getAssociation()->inversedBy($relation);
15 |
16 | return $this;
17 | }
18 |
19 | /**
20 | * @return \Doctrine\ORM\Mapping\Builder\AssociationBuilder
21 | */
22 | abstract public function getAssociation();
23 | }
24 |
--------------------------------------------------------------------------------
/src/Relations/Traits/Primary.php:
--------------------------------------------------------------------------------
1 | getAssociation()->makePrimaryKey();
16 |
17 | return $this;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------