ILIAS  trunk Revision v11.0_alpha-3011-gc6b235a2e85
Factory.php
Go to the documentation of this file.
1<?php
2
19declare(strict_types=1);
20
21namespace ILIAS\MetaData\Paths;
22
28
29class Factory implements FactoryInterface
30{
32
34 {
35 $this->structure = $structure;
36 }
37
38 public function fromString(string $string): PathInterface
39 {
40 $exploded = explode(Token::SEPARATOR->value, strtolower($string));
41 $builder = $this->setModesFromString($this->custom(), $exploded[0]);
42 $exploded = array_slice($exploded, 1);
43 foreach ($exploded as $step_string) {
44 $builder = $this->addStepFromString($builder, $step_string);
45 }
46 return $builder->get();
47 }
48
49 protected function setModesFromString(
50 BuilderInterface $builder,
51 string $string
53 $pattern = '/^(' . strtolower(Token::LEADS_TO_EXACTLY_ONE->value) .
54 ')?(' . strtolower(Token::START_AT_ROOT->value) . '|' .
55 strtolower(Token::START_AT_CURRENT->value) . ')$/';
56 if (!preg_match($pattern, $string, $matches)) {
57 throw new \ilMDPathException(
58 'Cannot create path, invalid modes in input string: ' . $string
59 );
60 }
61 if (!empty($matches[1])) {
62 $builder = $builder->withLeadsToExactlyOneElement(true);
63 }
64 if ($matches[2] === Token::START_AT_ROOT->value) {
65 $builder = $builder->withRelative(false);
66 } else {
67 $builder = $builder->withRelative(true);
68 }
69 return $builder;
70 }
71
72 protected function addStepFromString(
73 BuilderInterface $builder,
74 string $string
76 $exploded = explode(Token::FILTER_SEPARATOR->value, strtolower($string));
77 $name = StepToken::tryFrom($exploded[0]) ?? $exploded[0];
78 if ($name === StepToken::SUPER) {
79 $builder = $builder->withNextStepToSuperElement(false);
80 } else {
81 $builder = $builder->withNextStep($name, false);
82 }
83 $exploded = array_slice($exploded, 1);
84 foreach ($exploded as $filter_string) {
85 $exploded_filter = explode(
87 strtolower($filter_string)
88 );
89 $type = FilterType::tryFrom($exploded_filter[0]);
90 $exploded_filter = array_slice($exploded_filter, 1);
91 if (!is_null($type)) {
92 $builder = $builder = $builder->withAdditionalFilterAtCurrentStep(
93 $type,
94 ...$exploded_filter
95 );
96 continue;
97 }
98 throw new \ilMDPathException(
99 'Cannot create path, invalid filter type.'
100 );
101 }
102 return $builder;
103 }
104
105 public function toElement(
107 bool $leads_to_exactly_one = false
108 ): PathInterface {
109 $builder = $this
110 ->custom()
111 ->withRelative(false)
112 ->withLeadsToExactlyOneElement($leads_to_exactly_one);
113
114 while (!$to->isRoot()) {
115 $builder = $this->addElementAsStep(
116 $builder,
117 $to,
118 $leads_to_exactly_one,
119 true
120 );
121 $to = $to->getSuperElement();
122 if (!isset($to)) {
123 throw new \ilMDPathException(
124 'Cannot build path from element without root.'
125 );
126 }
127 }
128
129 return $builder->getWithoutValidation();
130 }
131
132 public function betweenElements(
135 bool $leads_to_exactly_one = false
136 ): PathInterface {
137 $to_and_supers = [];
138 while ($to) {
139 array_unshift($to_and_supers, $to);
140 $to = $to->getSuperElement();
141 }
142
143 $builder = $this
144 ->custom()
145 ->withRelative(true)
146 ->withLeadsToExactlyOneElement($leads_to_exactly_one);
147
148 while (!in_array($from, $to_and_supers, true)) {
149 $builder = $builder->withNextStepToSuperElement();
150 $from = $from->getSuperElement();
151 if (!isset($from)) {
152 throw new \ilMDPathException(
153 'Cannot build path between elements from disjunct sets.'
154 );
155 }
156 }
157
158 $to_and_supers = array_slice(
159 $to_and_supers,
160 array_search($from, $to_and_supers, true) + 1
161 );
162 foreach ($to_and_supers as $element) {
163 $builder = $this->addElementAsStep(
164 $builder,
165 $element,
166 $leads_to_exactly_one,
167 false
168 );
169 }
170
171 return $builder->getWithoutValidation();
172 }
173
174 protected function addElementAsStep(
175 BuilderInterface $builder,
176 BaseElementInterface $element,
177 bool $leads_to_exactly_one,
178 bool $add_as_first
180 $builder = $builder->withNextStep(
181 $element->getDefinition()->name(),
182 $add_as_first
183 );
184
185 if ($element instanceof StructureElement) {
186 return $builder;
187 }
188 if ($leads_to_exactly_one) {
189 $id = $element->getMDID();
190 $id = is_int($id) ? (string) $id : $id->value;
191 $builder = $builder->withAdditionalFilterAtCurrentStep(
192 FilterType::MDID,
193 $id
194 );
195 }
196
197 return $builder;
198 }
199
200 public function custom(): BuilderInterface
201 {
202 return new Builder($this->structure);
203 }
204}
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
Definition: plugin.php:23
fromString(string $string)
Definition: Factory.php:38
setModesFromString(BuilderInterface $builder, string $string)
Definition: Factory.php:49
addStepFromString(BuilderInterface $builder, string $string)
Definition: Factory.php:72
StructureSetInterface $structure
Definition: Factory.php:31
betweenElements(BaseElementInterface $from, BaseElementInterface $to, bool $leads_to_exactly_one=false)
Returns relative path between two given elements.
Definition: Factory.php:132
__construct(StructureSetInterface $structure)
Definition: Factory.php:33
toElement(BaseElementInterface $to, bool $leads_to_exactly_one=false)
Returns absolute path from root to the given element.
Definition: Factory.php:105
addElementAsStep(BuilderInterface $builder, BaseElementInterface $element, bool $leads_to_exactly_one, bool $add_as_first)
Definition: Factory.php:174
withNextStepToSuperElement(bool $add_as_first=false)
Add going to the super element as the next step to the path.
withRelative(bool $is_relative)
Relative paths start at some otherwise determined element, absolute paths start at root.
withAdditionalFilterAtCurrentStep(FilterType $type, string ... $values)
Adds a filter to the current step, restricting what elements are included in it:
withNextStep(string $name, bool $add_as_first=false)
Add the next step to the path.
withLeadsToExactlyOneElement(bool $leads_to_one)
Building a path that is flagged to lead to exactly one element, but does not actually do so can throw...
FilterType
Values should always be all lowercase.
Definition: FilterType.php:27
StepToken
The string representation of these tokens must not occur as names of metadata elements.
Definition: StepToken.php:28
Token
The string representation of these tokens must not occur in the names of metadata elements.
Definition: Token.php:28