TEntityContainer::setDefaults()   A
last analyzed

Complexity

Conditions 5
Paths 3

Size

Total Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 13
rs 9.5222
c 0
b 0
f 0
cc 5
nc 3
nop 2
1
<?php
2
/**
3
 * TEntityContainer.php
4
 *
5
 * @copyright      More in license.md
6
 * @license        https://www.ipublikuj.eu
7
 * @author         Adam Kadlec <[email protected]>
8
 * @package        iPublikuj:Forms!
9
 * @subpackage     Forms
10
 * @since          1.0.0
11
 *
12
 * @date           10.01.16
13
 */
14
15
declare(strict_types = 1);
16
17
namespace IPub\Forms\Forms;
18
19
use Doctrine\ORM;
20
21
use Nette\Application;
22
use Nette\ComponentModel;
23
use Nette\Forms;
24
25
use IPub\Forms\Exceptions;
26
27
/**
28
 * Form trait for entity binding
29
 *
30
 * @package        iPublikuj:Forms!
31
 * @subpackage     Forms
32
 *
33
 * @author         Adam Kadlec <[email protected]>
34
 *
35
 * @method Application\UI\Form getForm($need = TRUE)
36
 * @method setValues($values, $erase = FALSE)
37
 */
38
trait TEntityContainer
39
{
40
	/**
41
	 * @var mixed
42
	 */
43
	private $entity;
44
45
	/**
46
	 * @param array|\Traversable $values
47
	 * @param bool $erase
48
	 *
49
	 * @return void
50
	 *
51
	 * @throws Exceptions\InvalidArgumentException
52
	 */
53
	public function setDefaults($values, $erase = FALSE) : void
54
	{
55
		$form = $this->getForm(FALSE);
56
57
		if (!$form || !$form->isAnchored() || !$form->isSubmitted()) {
58
			if ($this->isEntity($values)) {
59
				$this->bindEntity($this, $values, $erase);
0 ignored issues
show
Bug introduced by
It seems like $values defined by parameter $values on line 53 can also be of type array; however, IPub\Forms\Forms\TEntityContainer::bindEntity() does only seem to accept object, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
60
61
			} else {
62
				$this->setValues($values, $erase);
63
			}
64
		}
65
	}
66
67
	/**
68
	 * @param mixed $entity
69
	 *
70
	 * @return void
71
	 */
72
	public function setEntity($entity) : void
73
	{
74
		$this->entity = $entity;
75
76
		if (method_exists($entity, 'getId')) {
77
			$this->setId((string) $entity->getId());
0 ignored issues
show
Bug introduced by
It seems like setId() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
78
		}
79
	}
80
81
	/**
82
	 * @return mixed
83
	 */
84
	public function getEntity()
85
	{
86
		return $this->entity;
87
	}
88
89
	/**
90
	 * @param ComponentModel\Component $formElement
91
	 * @param object $entity
92
	 * @param bool $erase
93
	 *
94
	 * @return void
95
	 *
96
	 * @throws Exceptions\InvalidArgumentException
97
	 */
98
	private function bindEntity($formElement, $entity, bool $erase) : void
99
	{
100
		$classMetadata = $this->getMetadata($entity);
101
102
		foreach (self::iterate($formElement) as $name => $component) {
0 ignored issues
show
Documentation introduced by
$formElement is of type object<Nette\ComponentModel\Component>, but the function expects a object<Nette\Forms\ICont...<Nette\Forms\Container>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
103
			if ($component instanceof Forms\IControl) {
104
				if (($classMetadata->hasField($name) || $classMetadata->hasAssociation($name)) && $value = $classMetadata->getFieldValue($entity, $name)) {
105 View Code Duplication
					if (is_object($value) && $this->isEntity($value)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
106
						$UoW = $this->entityManager->getUnitOfWork();
0 ignored issues
show
Bug introduced by
The property entityManager does not seem to exist. Did you mean entity?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
107
						$value = $UoW->getSingleIdentifierValue($value);
108
109
						$component->setValue($value);
110
111
					} else {
112
						$component->setValue($value);
113
					}
114
115
				} else {
116
					$methodName = 'get' . ucfirst($name);
117
118
					if (method_exists($entity, $methodName) && $value = call_user_func([$entity, $methodName])) {
119 View Code Duplication
						if (is_object($value) && $this->isEntity($value)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
120
							$UoW = $this->entityManager->getUnitOfWork();
0 ignored issues
show
Bug introduced by
The property entityManager does not seem to exist. Did you mean entity?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
121
							$value = $UoW->getSingleIdentifierValue($value);
122
123
							$component->setValue($value);
124
125
						} else {
126
							$component->setValue($value);
127
						}
128
129
					} else {
130
						if ($erase) {
131
							$component->setValue(NULL);
132
						}
133
					}
134
				}
135
136
			} elseif ($component instanceof Forms\Container) {
137
				if (($classMetadata->hasField($name) || $classMetadata->hasAssociation($name)) && $value = $classMetadata->getFieldValue($entity, $name)) {
138 View Code Duplication
					if (is_object($value) && $this->isEntity($value)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
139
						$this->bindEntity($component, $value, $erase);
140
141
					} else {
142
						$component->setValues($value, $erase);
143
					}
144
145
				} else {
146
					$methodName = 'get' . ucfirst($name);
147
148
					if (method_exists($entity, $methodName) && $value = call_user_func([$entity, $methodName])) {
149 View Code Duplication
						if (is_object($value) && $this->isEntity($value)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
150
							$this->bindEntity($component, $value, $erase);
151
152
						} else {
153
							$component->setValues($value, $erase);
154
						}
155
156
					} else {
157
						if ($erase) {
158
							$component->setValues([], $erase);
159
						}
160
					}
161
				}
162
			}
163
		}
164
	}
165
166
	/**
167
	 * @param object $entity
168
	 *
169
	 * @return ORM\Mapping\ClassMetadata
170
	 *
171
	 * @throws Exceptions\InvalidArgumentException
172
	 */
173
	private function getMetadata($entity) : ORM\Mapping\ClassMetadata
174
	{
175
		if (!$this->isEntity($entity)) {
176
			throw new Exceptions\InvalidArgumentException(sprintf('Expected object, "%s" given.', gettype($entity)));
177
		}
178
179
		return $this->entityManager->getClassMetadata(get_class($entity));
0 ignored issues
show
Bug introduced by
The property entityManager does not seem to exist. Did you mean entity?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
180
	}
181
182
	/**
183
	 * @param mixed $entity
184
	 *
185
	 * @return bool
186
	 */
187
	private function isEntity($entity) : bool
188
	{
189
		return is_object($entity) && $this->entityManager->getMetadataFactory()->hasMetadataFor(get_class($entity));
0 ignored issues
show
Bug introduced by
The property entityManager does not seem to exist. Did you mean entity?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
190
	}
191
192
	/**
193
	 * @param Forms\IControl|Forms\Container $formElement
194
	 *
195
	 * @return array|\ArrayIterator
196
	 *
197
	 * @throws Exceptions\InvalidArgumentException
198
	 */
199
	private static function iterate($formElement)
200
	{
201
		if ($formElement instanceof Forms\Container) {
202
			return $formElement->getComponents();
203
204
		} elseif ($formElement instanceof Forms\IControl) {
205
			return [$formElement];
206
207
		} else {
208
			throw new Exceptions\InvalidArgumentException(sprintf('Expected Nette\Forms\Container or Nette\Forms\IControl, but "%s" given', get_class($formElement)));
209
		}
210
	}
211
}
212