Magento 2 Documentation  2.3
Documentation for Magento 2 CMS v2.3 (December 2018)
Filesystem.php
Go to the documentation of this file.
1 <?php
7 
9 
29 {
35  protected $_targetDirs = [];
36 
42  protected $_collectFiles = true;
43 
49  protected $_dirsFirst = true;
50 
56  protected $_collectRecursively = true;
57 
63  protected $_collectDirs = false;
64 
70  protected $_allowedDirsMask = '/^[a-z0-9\.\-\_]+$/i';
71 
77  protected $_allowedFilesMask = '/^[a-z0-9\.\-\_]+\.[a-z0-9]+$/i';
78 
84  protected $_disallowedFilesMask = '';
85 
93  private $_filterIncrement = 0;
94 
102  private $_filterBrackets = [];
103 
111  private $_filterEvalRendered = '';
112 
118  protected $_collectedDirs = [];
119 
125  protected $_collectedFiles = [];
126 
134  public function setDirsFilter($regex)
135  {
136  $this->_allowedDirsMask = (string)$regex;
137  return $this;
138  }
139 
147  public function setFilesFilter($regex)
148  {
149  $this->_allowedFilesMask = (string)$regex;
150  return $this;
151  }
152 
160  public function setDisallowedFilesFilter($regex)
161  {
162  $this->_disallowedFilesMask = (string)$regex;
163  return $this;
164  }
165 
172  public function setCollectDirs($value)
173  {
174  $this->_collectDirs = (bool)$value;
175  return $this;
176  }
177 
184  public function setCollectFiles($value)
185  {
186  $this->_collectFiles = (bool)$value;
187  return $this;
188  }
189 
196  public function setCollectRecursively($value)
197  {
198  $this->_collectRecursively = (bool)$value;
199  return $this;
200  }
201 
209  public function addTargetDir($value)
210  {
211  $value = (string)$value;
212  if (!is_dir($value)) {
213  throw new \Exception('Unable to set target directory.');
214  }
215  $this->_targetDirs[$value] = $value;
216  return $this;
217  }
218 
226  public function setDirsFirst($value)
227  {
228  $this->_dirsFirst = (bool)$value;
229  return $this;
230  }
231 
240  protected function _collectRecursive($dir)
241  {
242  $collectedResult = [];
243  if (!is_array($dir)) {
244  $dir = [$dir];
245  }
246  foreach ($dir as $folder) {
247  if ($nodes = glob($folder . '/*', GLOB_NOSORT)) {
248  foreach ($nodes as $node) {
249  $collectedResult[] = $node;
250  }
251  }
252  }
253  if (empty($collectedResult)) {
254  return;
255  }
256 
257  foreach ($collectedResult as $item) {
258  if (is_dir($item) && (!$this->_allowedDirsMask || preg_match($this->_allowedDirsMask, basename($item)))) {
259  if ($this->_collectDirs) {
260  if ($this->_dirsFirst) {
261  $this->_collectedDirs[] = $item;
262  } else {
263  $this->_collectedFiles[] = $item;
264  }
265  }
266  if ($this->_collectRecursively) {
267  $this->_collectRecursive($item);
268  }
269  } elseif ($this->_collectFiles && is_file(
270  $item
271  ) && (!$this->_allowedFilesMask || preg_match(
272  $this->_allowedFilesMask,
273  basename($item)
274  )) && (!$this->_disallowedFilesMask || !preg_match(
275  $this->_disallowedFilesMask,
276  basename($item)
277  ))
278  ) {
279  $this->_collectedFiles[] = $item;
280  }
281  }
282  }
283 
293  public function loadData($printQuery = false, $logQuery = false)
294  {
295  if ($this->isLoaded()) {
296  return $this;
297  }
298  if (empty($this->_targetDirs)) {
299  throw new \Exception('Please specify at least one target directory.');
300  }
301 
302  $this->_collectedFiles = [];
303  $this->_collectedDirs = [];
304  $this->_collectRecursive($this->_targetDirs);
305  $this->_generateAndFilterAndSort('_collectedFiles');
306  if ($this->_dirsFirst) {
307  $this->_generateAndFilterAndSort('_collectedDirs');
308  $this->_collectedFiles = array_merge($this->_collectedDirs, $this->_collectedFiles);
309  }
310 
311  // calculate totals
312  $this->_totalRecords = count($this->_collectedFiles);
313  $this->_setIsLoaded();
314 
315  // paginate and add items
316  $from = ($this->getCurPage() - 1) * $this->getPageSize();
317  $to = $from + $this->getPageSize() - 1;
318  $isPaginated = $this->getPageSize() > 0;
319 
320  $cnt = 0;
321  foreach ($this->_collectedFiles as $row) {
322  $cnt++;
323  if ($isPaginated && ($cnt < $from || $cnt > $to)) {
324  continue;
325  }
326  $item = new $this->_itemObjectClass();
327  $this->addItem($item->addData($row));
328  if (!$item->hasId()) {
329  $item->setId($cnt);
330  }
331  }
332 
333  return $this;
334  }
335 
345  private function _generateAndFilterAndSort($attributeName)
346  {
347  // generate custom data (as rows with columns) basing on the filenames
348  foreach ($this->{$attributeName} as $key => $filename) {
349  $this->{$attributeName}[$key] = $this->_generateRow($filename);
350  }
351 
352  // apply filters on generated data
353  if (!empty($this->_filters)) {
354  foreach ($this->{$attributeName} as $key => $row) {
355  if (!$this->_filterRow($row)) {
356  unset($this->{$attributeName}[$key]);
357  }
358  }
359  }
360 
361  // sort (keys are lost!)
362  if (!empty($this->_orders)) {
363  usort($this->{$attributeName}, [$this, '_usort']);
364  }
365  }
366 
375  protected function _usort($a, $b)
376  {
377  foreach ($this->_orders as $key => $direction) {
378  $result = $a[$key] > $b[$key] ? 1 : ($a[$key] < $b[$key] ? -1 : 0);
379  return self::SORT_ORDER_ASC === strtoupper($direction) ? $result : -$result;
380  break;
381  }
382  }
383 
392  public function setOrder($field, $direction = self::SORT_ORDER_DESC)
393  {
394  $this->_orders = [$field => $direction];
395  return $this;
396  }
397 
404  protected function _generateRow($filename)
405  {
406  return ['filename' => $filename, 'basename' => basename($filename)];
407  }
408 
423  public function addCallbackFilter($field, $value, $type, $callback, $isInverted = false)
424  {
425  $this->_filters[$this->_filterIncrement] = [
426  'field' => $field,
427  'value' => $value,
428  'is_and' => 'and' === $type,
429  'callback' => $callback,
430  'is_inverted' => $isInverted,
431  ];
432  $this->_filterIncrement++;
433  return $this;
434  }
435 
445  protected function _filterRow($row)
446  {
447  // render filters once
448  if (!$this->_isFiltersRendered) {
449  $eval = '';
450  for ($i = 0; $i < $this->_filterIncrement; $i++) {
451  if (isset($this->_filterBrackets[$i])) {
452  $eval .= $this->_renderConditionBeforeFilterElement(
453  $i,
454  $this->_filterBrackets[$i]['is_and']
455  ) . $this->_filterBrackets[$i]['value'];
456  } else {
457  $f = '$this->_filters[' . $i . ']';
458  $eval .= $this->_renderConditionBeforeFilterElement(
459  $i,
460  $this->_filters[$i]['is_and']
461  ) .
462  ($this->_filters[$i]['is_inverted'] ? '!' : '') .
463  '$this->_invokeFilter(' .
464  "{$f}['callback'], array({$f}['field'], {$f}['value'], " .
465  '$row))';
466  }
467  }
468  $this->_filterEvalRendered = $eval;
469  $this->_isFiltersRendered = true;
470  }
471  $result = false;
472  if ($this->_filterEvalRendered) {
473  eval('$result = ' . $this->_filterEvalRendered . ';');
474  }
475  return $result;
476  }
477 
487  protected function _invokeFilter($callback, $callbackParams)
488  {
489  list($field, $value, $row) = $callbackParams;
490  if (!array_key_exists($field, $row)) {
491  return false;
492  }
493  return call_user_func_array($callback, $callbackParams);
494  }
495 
508  public function addFieldToFilter($field, $cond, $type = 'and')
509  {
510  $inverted = true;
511 
512  // simply check whether equals
513  if (!is_array($cond)) {
514  return $this->addCallbackFilter($field, $cond, $type, [$this, 'filterCallbackEq']);
515  }
516 
517  // versatile filters
518  if (isset($cond['from']) || isset($cond['to'])) {
519  $this->_addFilterBracket('(', 'and' === $type);
520  if (isset($cond['from'])) {
521  $this->addCallbackFilter(
522  $field,
523  $cond['from'],
524  'and',
525  [$this, 'filterCallbackIsLessThan'],
526  $inverted
527  );
528  }
529  if (isset($cond['to'])) {
530  $this->addCallbackFilter(
531  $field,
532  $cond['to'],
533  'and',
534  [$this, 'filterCallbackIsMoreThan'],
535  $inverted
536  );
537  }
538  return $this->_addFilterBracket(')');
539  }
540  if (isset($cond['eq'])) {
541  return $this->addCallbackFilter($field, $cond['eq'], $type, [$this, 'filterCallbackEq']);
542  }
543  if (isset($cond['neq'])) {
544  return $this->addCallbackFilter($field, $cond['neq'], $type, [$this, 'filterCallbackEq'], $inverted);
545  }
546  if (isset($cond['like'])) {
547  return $this->addCallbackFilter($field, $cond['like'], $type, [$this, 'filterCallbackLike']);
548  }
549  if (isset($cond['nlike'])) {
550  return $this->addCallbackFilter(
551  $field,
552  $cond['nlike'],
553  $type,
554  [$this, 'filterCallbackLike'],
555  $inverted
556  );
557  }
558  if (isset($cond['in'])) {
559  return $this->addCallbackFilter($field, $cond['in'], $type, [$this, 'filterCallbackInArray']);
560  }
561  if (isset($cond['nin'])) {
562  return $this->addCallbackFilter(
563  $field,
564  $cond['nin'],
565  $type,
566  [$this, 'filterCallbackInArray'],
567  $inverted
568  );
569  }
570  if (isset($cond['notnull'])) {
571  return $this->addCallbackFilter(
572  $field,
573  $cond['notnull'],
574  $type,
575  [$this, 'filterCallbackIsNull'],
576  $inverted
577  );
578  }
579  if (isset($cond['null'])) {
580  return $this->addCallbackFilter($field, $cond['null'], $type, [$this, 'filterCallbackIsNull']);
581  }
582  if (isset($cond['moreq'])) {
583  return $this->addCallbackFilter(
584  $field,
585  $cond['moreq'],
586  $type,
587  [$this, 'filterCallbackIsLessThan'],
588  $inverted
589  );
590  }
591  if (isset($cond['gt'])) {
592  return $this->addCallbackFilter($field, $cond['gt'], $type, [$this, 'filterCallbackIsMoreThan']);
593  }
594  if (isset($cond['lt'])) {
595  return $this->addCallbackFilter($field, $cond['lt'], $type, [$this, 'filterCallbackIsLessThan']);
596  }
597  if (isset($cond['gteq'])) {
598  return $this->addCallbackFilter(
599  $field,
600  $cond['gteq'],
601  $type,
602  [$this, 'filterCallbackIsLessThan'],
603  $inverted
604  );
605  }
606  if (isset($cond['lteq'])) {
607  return $this->addCallbackFilter(
608  $field,
609  $cond['lteq'],
610  $type,
611  [$this, 'filterCallbackIsMoreThan'],
612  $inverted
613  );
614  }
615  if (isset($cond['finset'])) {
616  $filterValue = $cond['finset'] ? explode(',', $cond['finset']) : [];
617  return $this->addCallbackFilter($field, $filterValue, $type, [$this, 'filterCallbackInArray']);
618  }
619 
620  // add OR recursively
621  foreach ($cond as $orCond) {
622  $this->_addFilterBracket('(', 'and' === $type);
623  $this->addFieldToFilter($field, $orCond, 'or');
624  $this->_addFilterBracket(')');
625  }
626  return $this;
627  }
628 
636  protected function _addFilterBracket($bracket = '(', $isAnd = true)
637  {
638  $this->_filterBrackets[$this->_filterIncrement] = [
639  'value' => $bracket === ')' ? ')' : '(',
640  'is_and' => $isAnd,
641  ];
642  $this->_filterIncrement++;
643  return $this;
644  }
645 
653  protected function _renderConditionBeforeFilterElement($increment, $isAnd)
654  {
655  if (isset($this->_filterBrackets[$increment]) && ')' === $this->_filterBrackets[$increment]['value']) {
656  return '';
657  }
658  $prevIncrement = $increment - 1;
659  $prevBracket = false;
660  if (isset($this->_filterBrackets[$prevIncrement])) {
661  $prevBracket = $this->_filterBrackets[$prevIncrement]['value'];
662  }
663  if ($prevIncrement < 0 || $prevBracket === '(') {
664  return '';
665  }
666  return $isAnd ? ' && ' : ' || ';
667  }
668 
677  public function addFilter($field, $value, $type = 'and')
678  {
679  return $this;
680  }
681 
687  public function getAllIds()
688  {
689  return array_keys($this->_items);
690  }
691 
702  public function filterCallbackLike($field, $filterValue, $row)
703  {
704  $filterValue = trim(stripslashes($filterValue), '\'');
705  $filterValue = trim($filterValue, '%');
706  $filterValueRegex = '(.*?)' . preg_quote($filterValue, '/') . '(.*?)';
707 
708  return (bool)preg_match("/^{$filterValueRegex}\$/i", $row[$field]);
709  }
710 
721  public function filterCallbackEq($field, $filterValue, $row)
722  {
723  return $filterValue == $row[$field];
724  }
725 
736  public function filterCallbackInArray($field, $filterValue, $row)
737  {
738  return in_array($row[$field], $filterValue);
739  }
740 
752  public function filterCallbackIsNull($field, $filterValue, $row)
753  {
754  return null === $row[$field];
755  }
756 
767  public function filterCallbackIsMoreThan($field, $filterValue, $row)
768  {
769  return $row[$field] > $filterValue;
770  }
771 
782  public function filterCallbackIsLessThan($field, $filterValue, $row)
783  {
784  return $row[$field] < $filterValue;
785  }
786 }
filterCallbackInArray($field, $filterValue, $row)
Definition: Filesystem.php:736
elseif(isset( $params[ 'redirect_parent']))
Definition: iframe.phtml:17
loadData($printQuery=false, $logQuery=false)
Definition: Filesystem.php:293
filterCallbackIsNull($field, $filterValue, $row)
Definition: Filesystem.php:752
_addFilterBracket($bracket='(', $isAnd=true)
Definition: Filesystem.php:636
addCallbackFilter($field, $value, $type, $callback, $isInverted=false)
Definition: Filesystem.php:423
_invokeFilter($callback, $callbackParams)
Definition: Filesystem.php:487
$type
Definition: item.phtml:13
addFilter($field, $value, $type='and')
Definition: Filesystem.php:677
setOrder($field, $direction=self::SORT_ORDER_DESC)
Definition: Filesystem.php:392
$value
Definition: gender.phtml:16
filterCallbackIsMoreThan($field, $filterValue, $row)
Definition: Filesystem.php:767
filterCallbackEq($field, $filterValue, $row)
Definition: Filesystem.php:721
_renderConditionBeforeFilterElement($increment, $isAnd)
Definition: Filesystem.php:653
addFieldToFilter($field, $cond, $type='and')
Definition: Filesystem.php:508
filterCallbackLike($field, $filterValue, $row)
Definition: Filesystem.php:702
$i
Definition: gallery.phtml:31
filterCallbackIsLessThan($field, $filterValue, $row)
Definition: Filesystem.php:782
addItem(\Magento\Framework\DataObject $item)
Definition: Collection.php:399