From 3094c54084a305de471e7a530468a5a3b3b34dc7 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 13 Apr 2024 13:30:22 +0200 Subject: Merging upstream version 0.13.2. Signed-off-by: Daniel Baumann --- vendor/ipl/i18n/src/GettextTranslator.php | 2 + vendor/ipl/orm/src/Behavior/Binary.php | 5 +- vendor/ipl/orm/src/Compat/FilterProcessor.php | 13 +++++ vendor/ipl/orm/src/Hydrator.php | 64 ++++++++++++++++++---- vendor/ipl/web/phpstan-baseline-by-php-version.php | 12 ++++ vendor/ipl/web/src/Compat/StyleWithNonce.php | 8 ++- vendor/ipl/web/src/Compat/ViewRenderer.php | 12 +++- vendor/ipl/web/src/Control/LimitControl.php | 6 ++ vendor/ipl/web/src/Control/PaginationControl.php | 9 +-- vendor/ipl/web/src/FormElement/TermInput.php | 6 +- 10 files changed, 113 insertions(+), 24 deletions(-) create mode 100644 vendor/ipl/web/phpstan-baseline-by-php-version.php (limited to 'vendor/ipl') diff --git a/vendor/ipl/i18n/src/GettextTranslator.php b/vendor/ipl/i18n/src/GettextTranslator.php index 288a489..ee0cee4 100644 --- a/vendor/ipl/i18n/src/GettextTranslator.php +++ b/vendor/ipl/i18n/src/GettextTranslator.php @@ -2,6 +2,7 @@ namespace ipl\I18n; +use Locale; use FilesystemIterator; use ipl\Stdlib\Contract\Translator; use SplFileInfo; @@ -195,6 +196,7 @@ class GettextTranslator implements Translator { putenv("LANGUAGE=$locale.UTF-8"); setlocale(LC_ALL, $locale . '.UTF-8'); + Locale::setDefault($locale . '.UTF-8'); $this->loadTranslations(); diff --git a/vendor/ipl/orm/src/Behavior/Binary.php b/vendor/ipl/orm/src/Behavior/Binary.php index c43082a..602c9c7 100644 --- a/vendor/ipl/orm/src/Behavior/Binary.php +++ b/vendor/ipl/orm/src/Behavior/Binary.php @@ -29,7 +29,10 @@ class Binary extends PropertyBehavior implements QueryAwareBehavior, RewriteFilt if ($value !== null) { if (is_resource($value)) { - return stream_get_contents($value); + $content = stream_get_contents($value); + rewind($value); + + return $content; } return $value; diff --git a/vendor/ipl/orm/src/Compat/FilterProcessor.php b/vendor/ipl/orm/src/Compat/FilterProcessor.php index 7956898..361aabb 100644 --- a/vendor/ipl/orm/src/Compat/FilterProcessor.php +++ b/vendor/ipl/orm/src/Compat/FilterProcessor.php @@ -139,6 +139,13 @@ class FilterProcessor extends \ipl\Sql\Compat\FilterProcessor if (! $behaviorsApplied) { $rewrittenFilter = $subjectBehaviors->rewriteCondition($filter, $path . '.'); if ($rewrittenFilter !== null) { + if ( + $rewrittenFilter instanceof MetaDataProvider + && $rewrittenFilter->metaData()->get('forceResolved', false) + ) { + return $rewrittenFilter; + } + return $this->requireAndResolveFilterColumns($rewrittenFilter, $query, $forceOptimization) ?: $rewrittenFilter; } @@ -328,6 +335,12 @@ class FilterProcessor extends \ipl\Sql\Compat\FilterProcessor $subQuerySelect->having(["COUNT(DISTINCT $targetKeys) >= ?" => $count]); $subQuerySelect->groupBy(array_values($subQuerySelect->getColumns())); + + if ($negate) { + $subQuerySelect->where(array_map(function ($k) { + return $k . ' IS NOT NULL'; + }, array_values($subQuerySelect->getColumns()))); + } } // TODO: Qualification is only necessary since the `In` and `NotIn` conditions are ignored by diff --git a/vendor/ipl/orm/src/Hydrator.php b/vendor/ipl/orm/src/Hydrator.php index e3cd23d..63b3ff2 100644 --- a/vendor/ipl/orm/src/Hydrator.php +++ b/vendor/ipl/orm/src/Hydrator.php @@ -13,6 +13,9 @@ class Hydrator /** @var array Additional hydration rules for the model's relations */ protected $hydrators = []; + /** @var array> Map of columns to referencing paths */ + protected $columnToTargetMap = []; + /** @var Query The query the hydration rules are for */ protected $query; @@ -70,11 +73,31 @@ class Hydrator } } + $this->updateColumnToTargetMap($path, $columnToPropertyMap); $this->hydrators[$path] = [$target, $relation, $columnToPropertyMap, $defaults]; return $this; } + /** + * Update which columns the given path is referencing + * + * @param string $path + * @param array $columnToPropertyMap + * + * @return void + */ + protected function updateColumnToTargetMap(string $path, array $columnToPropertyMap): void + { + foreach ($columnToPropertyMap as $qualifiedColumnPath => $_) { + if (isset($this->columnToTargetMap[$qualifiedColumnPath])) { + $this->columnToTargetMap[$qualifiedColumnPath][$path] = true; + } else { + $this->columnToTargetMap[$qualifiedColumnPath] = [$path => true]; + } + } + } + /** * Hydrate the given raw database rows into the specified model * @@ -86,6 +109,7 @@ class Hydrator public function hydrate(array $data, Model $model) { $defaultsToApply = []; + $columnToTargetMap = $this->columnToTargetMap; foreach ($this->hydrators as $path => $vars) { list($target, $relation, $columnToPropertyMap, $defaults) = $vars; @@ -120,33 +144,44 @@ class Hydrator } } - $subject->setProperties($this->extractAndMap($data, $columnToPropertyMap)); + $subject->setProperties($this->extractAndMap($data, $columnToPropertyMap, $path, $columnToTargetMap)); $this->query->getResolver()->getBehaviors($target)->retrieve($subject); $defaultsToApply[] = [$subject, $defaults]; } // If there are any columns left, propagate them to the targeted relation if possible, to the base otherwise foreach ($data as $column => $value) { + if (($aliasPrefix = $this->query->getResolver()->getAliasPrefix())) { + $column = substr($column, strlen($aliasPrefix)); + } + $columnName = $column; $steps = explode('_', $column); $baseTable = array_shift($steps); + while (! empty($steps) && $baseTable !== $model->getTableAlias()) { + $baseTable .= '_' . array_shift($steps); + } $subject = $model; $target = $this->query->getModel(); $stepsTaken = []; - foreach ($steps as $step) { + for ($i = 0; $i < count($steps); $i++) { + $step = $steps[$i]; $stepsTaken[] = $step; $relationPath = "$baseTable." . implode('.', $stepsTaken); try { $relation = $this->query->getResolver()->resolveRelation($relationPath); - } catch (InvalidArgumentException $_) { - // The base table is missing, which means the alias hasn't been qualified and is custom defined - break; } catch (InvalidRelationException $_) { - array_pop($stepsTaken); - $columnName = implode('_', array_slice($steps, count($stepsTaken))); - break; + if (isset($steps[$i + 1])) { + $steps[$i + 1] = $step . '_' . $steps[$i + 1]; + array_pop($stepsTaken); + continue; + } else { + array_pop($stepsTaken); + $columnName = implode('_', array_slice($steps, $i)); + break; + } } if (! $subject->hasProperty($step)) { @@ -181,15 +216,24 @@ class Hydrator * * @param array $data * @param array $columnToPropertyMap + * @param string $path + * @param array> $columnToTargetMap * * @return array */ - protected function extractAndMap(array &$data, array $columnToPropertyMap) + protected function extractAndMap(array &$data, array $columnToPropertyMap, string $path, array &$columnToTargetMap) { $extracted = []; foreach (array_intersect_key($columnToPropertyMap, $data) as $column => $property) { $extracted[$property] = $data[$column]; - unset($data[$column]); + + if (isset($columnToTargetMap[$column][$path])) { + unset($columnToTargetMap[$column][$path]); + if (empty($columnToTargetMap[$column])) { + // Only unset a column once it's really not required anymore + unset($data[$column], $columnToTargetMap[$column]); + } + } } return $extracted; diff --git a/vendor/ipl/web/phpstan-baseline-by-php-version.php b/vendor/ipl/web/phpstan-baseline-by-php-version.php new file mode 100644 index 0000000..05107df --- /dev/null +++ b/vendor/ipl/web/phpstan-baseline-by-php-version.php @@ -0,0 +1,12 @@ + $includes +]; diff --git a/vendor/ipl/web/src/Compat/StyleWithNonce.php b/vendor/ipl/web/src/Compat/StyleWithNonce.php index f4c7185..8c1be31 100644 --- a/vendor/ipl/web/src/Compat/StyleWithNonce.php +++ b/vendor/ipl/web/src/Compat/StyleWithNonce.php @@ -2,6 +2,7 @@ namespace ipl\Web\Compat; +use Icinga\Application\Icinga; use Icinga\Application\Version; use Icinga\Util\Csp; use ipl\Web\Style; @@ -15,9 +16,10 @@ class StyleWithNonce extends Style public function getNonce(): ?string { if ($this->nonce === null) { - $this->nonce = version_compare(Version::VERSION, '2.12.0', '>=') - ? Csp::getStyleNonce() ?? '' - : ''; + $this->nonce = ''; + if (version_compare(Version::VERSION, '2.12.0', '>=') && Icinga::app()->isWeb()) { + $this->nonce = Csp::getStyleNonce() ?? ''; + } } return parent::getNonce(); diff --git a/vendor/ipl/web/src/Compat/ViewRenderer.php b/vendor/ipl/web/src/Compat/ViewRenderer.php index 48ddcc3..0eaa8dd 100644 --- a/vendor/ipl/web/src/Compat/ViewRenderer.php +++ b/vendor/ipl/web/src/Compat/ViewRenderer.php @@ -2,11 +2,16 @@ namespace ipl\Web\Compat; +use Icinga\Web\View; +use ipl\Html\HtmlDocument; use Zend_Controller_Action_Helper_ViewRenderer as Zf1ViewRenderer; use Zend_Controller_Action_HelperBroker as Zf1HelperBroker; class ViewRenderer extends Zf1ViewRenderer { + /** @var View */ + public $view; + /** * Inject the view renderer */ @@ -41,9 +46,10 @@ class ViewRenderer extends Zf1ViewRenderer */ public function render($action = null, $name = null, $noController = null) { - $view = $this->view; + /** @var HtmlDocument $document */ + $document = $this->view->document; - if ($view->document->isEmpty() || $this->getRequest()->getParam('error_handler') !== null) { + if ($document->isEmpty() || $this->getRequest()->getParam('error_handler') !== null) { parent::render($action, $name, $noController); return; @@ -53,7 +59,7 @@ class ViewRenderer extends Zf1ViewRenderer $name = $this->getResponseSegment(); } - $this->getResponse()->appendBody($view->document->render(), $name); + $this->getResponse()->appendBody($document->render(), $name); $this->setNoRender(); } diff --git a/vendor/ipl/web/src/Control/LimitControl.php b/vendor/ipl/web/src/Control/LimitControl.php index b390a0a..376d6be 100644 --- a/vendor/ipl/web/src/Control/LimitControl.php +++ b/vendor/ipl/web/src/Control/LimitControl.php @@ -119,5 +119,11 @@ class LimitControl extends CompatForm 'title' => t('Change item count per page'), 'value' => $limit ]); + + if ($this->url->hasParam(PaginationControl::DEFAULT_PAGE_PARAM)) { + $this->addElement('hidden', PaginationControl::DEFAULT_PAGE_PARAM, [ + 'value' => 1 + ]); + } } } diff --git a/vendor/ipl/web/src/Control/PaginationControl.php b/vendor/ipl/web/src/Control/PaginationControl.php index 00f5c20..e704829 100644 --- a/vendor/ipl/web/src/Control/PaginationControl.php +++ b/vendor/ipl/web/src/Control/PaginationControl.php @@ -17,6 +17,9 @@ use ipl\Web\Widget\Icon; */ class PaginationControl extends BaseHtmlElement { + /** @var string Default page parameter */ + public const DEFAULT_PAGE_PARAM = 'page'; + /** @var int Default maximum number of items which should be shown per page */ protected $defaultPageSize; @@ -467,10 +470,8 @@ class PaginationControl extends BaseHtmlElement 'title' => t('Go to page …') ]); - if (isset($currentPageNumber)) { - if ($currentPageNumber === 1 || $currentPageNumber === $this->getPageCount()) { - $select->add(Html::tag('option', ['disabled' => '', 'selected' => ''], '…')); - } + if ($currentPageNumber === 1 || $currentPageNumber === $this->getPageCount()) { + $select->add(Html::tag('option', ['disabled' => '', 'selected' => ''], '…')); } foreach (range(2, $this->getPageCount() - 1) as $page) { diff --git a/vendor/ipl/web/src/FormElement/TermInput.php b/vendor/ipl/web/src/FormElement/TermInput.php index 352cce4..184be1d 100644 --- a/vendor/ipl/web/src/FormElement/TermInput.php +++ b/vendor/ipl/web/src/FormElement/TermInput.php @@ -151,14 +151,14 @@ class TermInput extends FieldsetElement public function setValue($value) { - $recipients = $value; + $separatedTerms = $value; if (is_array($value)) { - $recipients = $value['value'] ?? ''; + $separatedTerms = $value['value'] ?? ''; parent::setValue($value); } $terms = []; - foreach ($this->parseValue($recipients) as $term) { + foreach ($this->parseValue((string) $separatedTerms) as $term) { $terms[] = new RegisteredTerm($term); } -- cgit v1.2.3