ILIAS  trunk Revision v11.0_alpha-1715-g7fc467680fb
All Data Structures Namespaces Files Functions Variables Enumerations Enumerator Modules Pages
Factory.php
Go to the documentation of this file.
1 <?php
2 
19 declare(strict_types=1);
20 
21 namespace ILIAS\MetaData\Paths;
22 
28 
29 class Factory implements FactoryInterface
30 {
32 
33  public function __construct(StructureSetInterface $structure)
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
52  ): BuilderInterface {
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
75  ): BuilderInterface {
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->get();
130  }
131 
132  public function betweenElements(
133  BaseElementInterface $from,
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->get();
172  }
173 
174  protected function addElementAsStep(
175  BuilderInterface $builder,
176  BaseElementInterface $element,
177  bool $leads_to_exactly_one,
178  bool $add_as_first
179  ): BuilderInterface {
180  $builder = $builder->withNextStep(
181  $element->getDefinition()->name(),
182  $add_as_first
183  );
184 
185  $id = $element->getMDID();
186  if ($element instanceof StructureElement) {
187  return $builder;
188  }
189  $id = is_int($id) ? (string) $id : $id->value;
190  if ($leads_to_exactly_one) {
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 }
addStepFromString(BuilderInterface $builder, string $string)
Definition: Factory.php:72
FilterType
Values should always be all lowercase.
Definition: FilterType.php:26
fromString(string $string)
Definition: Factory.php:38
if(!file_exists('../ilias.ini.php'))
StructureSetInterface $structure
Definition: Factory.php:31
withNextStep(string $name, bool $add_as_first=false)
Add the next step to the path.
withAdditionalFilterAtCurrentStep(FilterType $type, string ... $values)
Adds a filter to the current step, restricting what elements are included in it:
StepToken
The string representation of these tokens must not occur as names of metadata elements.
Definition: StepToken.php:27
setModesFromString(BuilderInterface $builder, string $string)
Definition: Factory.php:49
__construct(StructureSetInterface $structure)
Definition: Factory.php:33
getDefinition()
Defining properties of the metadata element.
betweenElements(BaseElementInterface $from, BaseElementInterface $to, bool $leads_to_exactly_one=false)
Returns relative path between two given elements.
Definition: Factory.php:132
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
Definition: plugin.php:23
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...
withNextStepToSuperElement(bool $add_as_first=false)
Add going to the super element as the next step to the path.
addElementAsStep(BuilderInterface $builder, BaseElementInterface $element, bool $leads_to_exactly_one, bool $add_as_first)
Definition: Factory.php:174
toElement(BaseElementInterface $to, bool $leads_to_exactly_one=false)
Returns absolute path from root to the given element.
Definition: Factory.php:105
withRelative(bool $is_relative)
Relative paths start at some otherwise determined element, absolute paths start at root...