protected function _chunkHtmlHandling() { $iLastKey = ArrayHelper::lastKey($this->_aTagTexts['texts']); if ($this->_bIdentical) { return self::identical($this->_sEndExpression, $this->_aTagTexts['texts'][$iLastKey], $this->_oString->getEncoding()); } return self::equals($this->_sEndExpression, $this->_aTagTexts['texts'][$iLastKey], $this->_oString->getEncoding()); }
/** * Définit les expressions à envelopper. * * @param string|array $mPhrasesToWrap Expressions * @throws \Exception */ protected function _setPhrases($mPhrasesToWrap) { if (is_string($mPhrasesToWrap)) { $this->_mPhrases = $mPhrasesToWrap; } else { if ($mPhrasesToWrap && is_array($mPhrasesToWrap)) { $this->_mPhrases = $mPhrasesToWrap; $this->_mPhrases = ArrayHelper::flatten($mPhrasesToWrap); } else { throw ExceptionType::invalidArgument("Argument #1 doit être une chaîne de caractères ou un tableau.", Exception::FROM_HANDLER); } } }
protected function _process() { $this->_initializePositionAnalyzer(); $sString = $this->_oString->get(); // S'il y a des URLs if ($this->_aPositionStats['index']['matching_regex_elem']) { // On récupère leur position de début et de fin $aTagsToInsert = array(); // Pour chacune d'elles foreach ($this->_aPositionStats['index']['matching_regex_elem'] as $aUrl) { $aUrlIndexes = array('tag_text_pos' => array('start' => $aUrl['tag_text_pos'][0], 'end' => $aUrl['tag_text_pos'][ArrayHelper::lastKey($aUrl['tag_text_pos'])]), 'regex_pos' => $aUrl['regex_pos']); // Si le tag précédent n'est pas une balise <a> if ($aUrlIndexes['tag_text_pos']['start'] === 0 || !$this->_alreadyLinked($aUrlIndexes['tag_text_pos']['start'])) { // On ajoute la balise <a> dans le texte $sUrl = $this->_aUrlPositions[$aUrlIndexes['regex_pos']]['element']; $iStartPos = $this->_aUrlPositions[$aUrlIndexes['regex_pos']]['pos']['string'][0]['start']; $iEndPos = $this->_aUrlPositions[$aUrlIndexes['regex_pos']]['pos']['string'][ArrayHelper::lastKey($this->_aUrlPositions[$aUrlIndexes['regex_pos']]['pos']['string'])]['end']; $aTagsToInsert[$iStartPos] = $this->_buildLinkOpenTag($sUrl); $aTagsToInsert[$iEndPos] = '</a>'; } } $aSlices = array(); $aBreakingPositions = array_keys($aTagsToInsert); $iNbBreakingPos = count($aBreakingPositions); for ($i = 0; $i < $iNbBreakingPos; $i++) { $aSlice = array_slice($aBreakingPositions, $i, 2); if (!isset($aSlice[1])) { $aSlice[1] = mb_strlen($this->_oString->get(), $this->_oString->getEncoding()); } $aSlices[] = $aSlice; } if ($aSlices) { // Si la première tranche ne commence pas au début de la chaîne if ($aSlices[0][0] !== 0) { // On ajoute une tranche array_unshift($aSlices, array(0, $aSlices[0][0])); } $aParts = array(); foreach ($aSlices as $aSlice) { $sSlice = mb_substr($this->_oString->get(), $aSlice[0], $aSlice[1] - $aSlice[0], $this->_oString->getEncoding()); // FAIRE MODIF ICI !!!! NE PAS FAIRE DE TEST STRIP_TAGS if ($this->_oRegex->test(strip_tags($sSlice))) { $sSlice = array_shift($aTagsToInsert) . $sSlice . array_shift($aTagsToInsert); } $aParts[] = $sSlice; } $sString = implode('', $aParts); } } return $this->_oString->setString($sString); }
protected function _htmlHandling() { $aTagTexts = $this->_splitTagText($this->_oString->get(), true, true); if ($aTagTexts['texts']) { $iFirstKey = ArrayHelper::firstKey($aTagTexts['texts']); if ($this->_sCharList !== null) { $aTagTexts['texts'][$iFirstKey] = ltrim($aTagTexts['texts'][$iFirstKey], $this->_sCharList); } else { $aTagTexts['texts'][$iFirstKey] = ltrim($aTagTexts['texts'][$iFirstKey]); } $this->_oString->setString(implode('', self::_coordinatingMerge($aTagTexts['tags'], $aTagTexts['texts']))); } return $this->_oString; }
/** * Initialise la structure par défaut du tableau des stats. * * @param string|array $sKeys Clés des éléments des statistiques à initialiser. Si aucune clé n'est renseignée, * l'intégralité du tableau des stats sera initialisé. */ protected function _setDefaultStatStructure($sKeys = null) { if (!$sKeys || $sKeys === '_aStats') { $this->_aStats = self::$_aDefaultStatStructure; } else { $aSubProperties = explode('.', $sKeys); // on retire la première prorpiété du tableau qui, en fait, est "_aStats" array_shift($aSubProperties); $mDefaultValue = ArrayHelper::getNestedValue(self::$_aDefaultStatStructure, $aSubProperties, $bKeyExists); if ($bKeyExists) { ArrayHelper::setNestedValue($this->_aStats, $aSubProperties, $mDefaultValue); } } }
protected function _chunkHtmlHandling() { if ($this->_aTagTexts['texts']) { $iLastKey = ArrayHelper::lastKey($this->_aTagTexts['texts']); if (mb_strrpos($this->_aTagTexts['texts'][$iLastKey], $this->_mEndValue, -1, $this->_oString->getEncoding()) !== mb_strlen($this->_aTagTexts['texts'][$iLastKey], $this->_oString->getEncoding()) - mb_strlen($this->_mEndValue, $this->_oString->getEncoding())) { self::_appendInLastElement($this->_aTagTexts['texts'], $this->_mEndValue); } } else { if ($this->_aTagTexts['tags']) { self::_appendInLastElement($this->_aTagTexts['tags'], $this->_mEndValue); } else { return $this->_oString->setString($this->_mEndValue); } } return $this->_oString->setString(self::_getMergedTagTexts(true)); }
protected function _chunkHtmlHandling() { if ($this->_aTagTexts['texts']) { $iFirstKey = ArrayHelper::firstKey($this->_aTagTexts['texts']); if (0 !== mb_strpos($this->_aTagTexts['texts'][$iFirstKey], $this->_sStartValue, 0, $this->_oString->getEncoding())) { self::_prependInFirstElement($this->_aTagTexts['texts'], $this->_sStartValue); } } else { if ($this->_aTagTexts['tags']) { self::_prependInFirstElement($this->_aTagTexts['tags'], $this->_sStartValue); } else { return $this->_oString->setString($this->_sStartValue); } } return $this->_oString->setString(self::_getMergedTagTexts(true)); }
protected static function _getAllValuesFromArray($aArray, $sKeyName) { $mResult = $aArray; if ($mResult === null) { return []; } return ArrayHelper::findAllElementsByKey($sKeyName, $mResult); }
/** * Retourne la ou les propriétés pointées par $sPropertyKeys. * * @param string $sPropertyKeys Propriété(s) à récupérer. Si vaut NULL, toutes les propriétés sont retournées.<br/> * Pour récupérér une valeur située en profondeur, il suffit de séparer les niveaux d'imbrication par des points. * @return mixed Propriété(s) pointée(s) par $sPropertyKeys. * @throws InvalidArgumentException * @throws OutOfBoundsException */ public function getProperty($sPropertyKeys = null, $mDefaultValue = null, &$bUnknownProperty = false) { if (!is_string($sPropertyKeys) && $sPropertyKeys !== null) { throw new InvalidArgumentException("Argument #1 doit être une chaîne de caractères désignant une propriété de configuration ou bien être NULL."); } if (is_string($sPropertyKeys)) { $aNestedPropertyKeys = explode('.', $sPropertyKeys); $mPropertyValue = ArrayHelper::getNestedValue($this->_aProperties, $aNestedPropertyKeys, $bKeyExists); if (!$bKeyExists) { $bUnknownProperty = true; $mPropertyValue = $mDefaultValue; } } else { $mPropertyValue = $this->_aProperties; } return $mPropertyValue; }
protected function _updateUriComponents($cUriPathType) { // Définition du type de chemin de l'uri $aDefinition = $this->_getDefinitions($cUriPathType); // Si aucune base d'url réécrite n'a été définie dans la configuration if (!isset($aDefinition[self::REWRITE])) { throw new UnderflowException("La section [" . self::REWRITE . "] doit être renseignée pour la route d'ID \"" . $this->_getRouteIds()[$cUriPathType] . "\"."); } // Récupération de la liste des valeurs des paramètres précisées par le développeur $aInputParams = $this->_aConf[self::_PARAM][$cUriPathType] ?: self::$_aDefaultConf[self::_PARAM][$cUriPathType]; // Si la définition ne comprend de section de paramètres matchables if (!isset($aDefinition[self::PARAM][self::PARAM_MATCH])) { // on retourne directement l'url rewritée telle quelle $this->_setFinalUriComponent($aDefinition[self::REWRITE], $cUriPathType); return; } if (!is_array($aDefinition[self::PARAM][self::PARAM_MATCH])) { throw new UnexpectedValueException("La section [" . self::PARAM . "][" . self::PARAM_MATCH . "] de la définition " . "de {$cUriPathType} est invalide. Elle doit être de type tableau."); } // Liste des propriétés de chaque paramètre défini dans les définitions comme à utiliser pour le rewriting $aDefinitionParams = []; // Pour chaque paramètre matchable foreach ($aDefinition[self::PARAM][self::PARAM_MATCH] as $iIndex => $aConfParam) { // Si sa valeur est un tableau associatif $bAssociativeMatch = ArrayHelper::isAssociative($aConfParam); if ($bAssociativeMatch) { // On la met dans un tableau indexé $aConfParam = [$aConfParam]; } // Pour chaque sous-paramètre matchable foreach ($aConfParam as $iSubIndex => $aSubConfParam) { if (!isset($aSubConfParam[self::PARAM_NAME])) { throw new UnderflowException("Le champ [" . self::PARAM . "][" . self::PARAM_MATCH . "][{$iIndex}]" . (!$bAssociativeMatch ? "[{$iSubIndex}]" : '') . "[" . self::PARAM_NAME . "] pour la route d'ID \"" . ".{$this->_getRouteIds}()[{$cUriPathType}]." . "\"."); } $sConfParamName = $aSubConfParam[self::PARAM_NAME]; // S'il n'est pas précisé que le sous-paramètre est à exclure du rewriting if (!isset($aSubConfParam[self::PARAM_REWRITE_USE]) || $aSubConfParam[self::PARAM_REWRITE_USE]) { // On stocke les propriétés du sous-paramètres pour les utiliser dans le rewriting // Si ce paramètre à déjà des propriétés définies if (isset($aDefinitionParams[$sConfParamName])) { // on regarde lequel des deux est obligatoire pour le rewriting $bOldParamPriority = isset($aDefinitionParams[$sConfParamName][self::PARAM_REWRITE_PRIORITY]) ? $aDefinitionParams[$sConfParamName][self::PARAM_REWRITE_PRIORITY] : 0; $bNewParamPriority = isset($aSubConfParam[self::PARAM_REWRITE_PRIORITY]) ? $aSubConfParam[self::PARAM_REWRITE_PRIORITY] : 0; // Si la nouvelle propriété à une valeur de priorité supérieure ou égale à l'ancienne if ($bOldParamPriority <= $bNewParamPriority) { // Si la nouvelle valeur est obligatoire if (!isset($aSubConfParam[self::PARAM_REWRITE_MANDATORY]) || $aSubConfParam[self::PARAM_REWRITE_MANDATORY] || isset($aInputParams[$sConfParamName]) || isset($aDefinitionParams[$sConfParamName][self::PARAM_REWRITE_MANDATORY]) && $aDefinitionParams[$sPlaceholderName][self::PARAM_REWRITE_MANDATORY]) { // On remplace l'ancienne valeur par la nouvelle $aDefinitionParams[$sConfParamName] = $aSubConfParam; } } } else { $aDefinitionParams[$sConfParamName] = $aSubConfParam; } } } } // Liste des remplacements à effectuer dans l'url à réécrire $aReplacements = []; // Pour chaque paramètre défini dans les définitions comme à utiliser pour le rewriting foreach ($aDefinitionParams as $aDefProperties) { // Si le développeur n'a pas fourni de valeur pour ce paramètre if (!isset($aInputParams[$aDefProperties[self::PARAM_NAME]])) { // Si ce paramètre est obligatoire if (!isset($aDefProperties[self::PARAM_REWRITE_MANDATORY]) || $aDefProperties[self::PARAM_REWRITE_MANDATORY]) { throw new UnderflowException("Le paramètre \"" . $aDefProperties[self::PARAM_NAME] . "\" doit être renseigné pour la route d'ID \"" . $this->_getRouteIds()[$cUriPathType] . "\"."); } else { continue; } } // Si le paramètre n'a pas de propriété VALUE sous forme de tableau if (!is_array($aDefProperties) || !isset($aDefProperties[self::PARAM_VALUE]) || !is_array($aDefProperties[self::PARAM_VALUE])) { // On stocke directement la valeur fournie par le développeur $sInputValue = $aInputParams[$aDefProperties[self::PARAM_NAME]]; } else { if (!in_array($aInputParams[$aDefProperties[self::PARAM_NAME]], $aDefProperties[self::PARAM_VALUE]) && isset($aDefProperties[self::PARAM_REWRITE_DEFAULT_VALUE])) { // C'est cette valeur par défaut qu'on stocke $sInputValue = array_search($aDefProperties[self::PARAM_REWRITE_DEFAULT_VALUE], $aDefProperties[self::PARAM_VALUE]); } else { // On stocke la valeur associée à la valeur fournie par le développeur $sInputValue = array_search($aInputParams[$aDefProperties[self::PARAM_NAME]], $aDefProperties[self::PARAM_VALUE]); } } $sPlaceholderName = isset($aDefProperties[self::PARAM_REWRITE_PLACEHOLDER]) ? $aDefProperties[self::PARAM_REWRITE_PLACEHOLDER] : $aDefProperties[self::PARAM_NAME]; $aReplacements[$sPlaceholderName] = $sInputValue; } // On procède au remplacement des placeholder de l'url réécrite par le valeurs fournies par le développeur $sRewritedUrl = $aDefinition[self::REWRITE]; foreach ($aReplacements as $sPlaceholder => $sValue) { $iNbReplacements = 0; $sRewritedUrl = str_replace('{{' . $sPlaceholder . '}}', $sValue, $sRewritedUrl, $iNbReplacements); // S'il y a eu au moins un remplacement de réalisé if ($iNbReplacements) { // on supprime des paramètres GET une éventuelle variable ayant le même nom, // stockée précedemment en GET par une autre route $this->_removeGetParam($sPlaceholder); } } // On stocke le composant réécrit de l'url $this->_setFinalUriComponent($sRewritedUrl, $cUriPathType); // Récupération de tous les paramètres qui, à première vue, n'ont pas été utilisés pour des remplacements $aGetParams = array_diff_key($aInputParams, $aReplacements); // Pour chacun de ces paramètres GET foreach ($aGetParams as $sGetName => $sGetValue) { // On vérifie s'il n'a effectivement pas été utilisé pour un remplacement, via à une propriété PLACEHOLDER différente de son nom if (isset($aDefinitionParams[$sGetName][self::PARAM_REWRITE_PLACEHOLDER]) && !isset($aGetParams[$aDefinitionParams[$sGetName][self::PARAM_REWRITE_PLACEHOLDER]])) { // Ensemble des propriétés de paramètre GET $aGetDef = $aDefinitionParams[$sGetName]; // Si le paramètre GET a une propriété VALUE sous forme de tableau, possédant une valeur par défaut, // et que la valeur du paramètre n'est pas présente dans le tableau $bGetParamNotUsed = isset($aGetDef[self::PARAM_VALUE]) && is_array($aGetDef[self::PARAM_VALUE]) && isset($aGetDef[self::PARAM_REWRITE_DEFAULT_VALUE]) && !in_array($sGetValue, $aGetDef[self::PARAM_VALUE]); // Si le paramètre a été utilisé pour une réécriture if (!$bGetParamNotUsed) { // on supprime le paramètre unset($aGetParams[$sGetName]); } } } // On enregistre les paramètres non utilisés $this->_setGetParams($aGetParams, $cUriPathType); }
/** * Stocke les paramètres capturés dynamiquement et liés à la route induite par la portion d'URI $cRoutePathType. * * @param array $aParams Liste des paramètres capturés. * @param const $cRoutePathType Portion d'URI sur laquelle porte la route. */ protected function _storeCapturedVars($aParams, $cRoutePathType) { $aRoute = $this->_aDefinitions[$cRoutePathType]; if (isset($aRoute[AbstractRouting::PARAM][AbstractRouting::PARAM_MATCH])) { $aAllComputedParams = $aRoute[AbstractRouting::PARAM][AbstractRouting::PARAM_MATCH]; foreach ($aAllComputedParams as &$aComputedParams) { if (ArrayHelper::isAssociative($aComputedParams)) { $aComputedParams = [$aComputedParams]; } } foreach ($aParams as $sName => $sValue) { if (is_numeric($sName)) { continue; } $aComputedParam = $aAllComputedParams[$sName]; foreach ($aComputedParam as $aCParam) { $sParamValue = $sValue; if (isset($aCParam[AbstractRouting::PARAM_TYPE], $aCParam[AbstractRouting::PARAM_NAME])) { if (isset($aCParam[AbstractRouting::PARAM_VALUE][$sValue])) { $sParamValue = $aCParam[AbstractRouting::PARAM_VALUE][$sValue]; } $this->_aParams[$aCParam[AbstractRouting::PARAM_TYPE]][$aCParam[AbstractRouting::PARAM_NAME]] = $sParamValue; } } } } }
/** * Insère dans chaque texte de Wrap::_aTagTexts un prependice et/ou un appendice, si la position de ces derniers s'y trouve. * * @param array $aPhrasePos Tableau des positions des prependices et appendices de la forme :<br/> * Array([0] => Array(prependice => 2, appendice => 9), [1] => Array(prependice => 15, appendice => 23)) */ protected function _insertWrappers($aPhrasePos) { $aTextStats = $this->_textStats($this->_aTagTexts['texts']); // On applatit le tableau des positions. // Ainsi, les éléments pairs correspondent aux positions des prependices // et les éléments impairs aux appendices $aTagPositions = ArrayHelper::flatten($aPhrasePos); $aInsertions = array(); $iLastTextLength = 0; foreach ($aTextStats as $iTextIndex => $aTextStat) { foreach ($aTagPositions as $iKey => &$iPos) { if ($aTextStat[0] <= $iPos && $iPos <= $aTextStat[1]) { if (!isset($aInsertions[$iTextIndex])) { $aInsertions[$iTextIndex] = array(); } if (!isset($aInsertions[$iTextIndex][$iPos - $iLastTextLength])) { $aInsertions[$iTextIndex][$iPos - $iLastTextLength] = !($iKey % 2) ? $this->_sPrependice : $this->_sAppendice; } else { $aInsertions[$iTextIndex][$iPos - $iLastTextLength] .= !($iKey % 2) ? $this->_sPrependice : $this->_sAppendice; } unset($aTagPositions[$iKey]); } } $iLastTextLength = $aTextStat[1]; } foreach ($aInsertions as $iTextIndex => $aInsertion) { $aPos = array_keys($aInsertion); $aInsertion = array_values($aInsertion); for ($i = count($aPos) - 1; $i >= 0; $i--) { $this->_aTagTexts['texts'][$iTextIndex] = substr_replace($this->_aTagTexts['texts'][$iTextIndex], $aInsertion[$i], $aPos[$i], 0); } } }
protected function _getAnchorPos($aRegexPositions, $aAnchor) { $bNegativeAnchor = $aAnchor['offset'] < 0; $iAbsAnchorPos = abs($aAnchor['offset']); // Liste des index des élements de $aRegexPositions['regex_pos'] qui répondent à la regex $aElemRegexIndexes = $aRegexPositions['stats']['regex_pos']['matching_regex_indexes']; // Si la position recherchée est, dans l'absolu, supérieure au nombre d'éléments regex // alors c'est que l'ancre est extérieure à la chaîne if (count($aElemRegexIndexes) < $iAbsAnchorPos) { return null; } // Si la position recherchée est négative, la recherche commence à la fin du tableau if ($bNegativeAnchor) { $iAnchorIndex = array_reverse($aElemRegexIndexes)[$iAbsAnchorPos - 1]; } else { $iAnchorIndex = $aElemRegexIndexes[$iAbsAnchorPos - 1]; } // On renvoie les positions de début et de fin de l'ancre dans la chaîne de caractères. $aAnchorPositions = ArrayHelper::flatten($aRegexPositions['regex_pos'][$iAnchorIndex]['pos']['string']); return array($aAnchorPositions[0], end($aAnchorPositions)); }
protected static function _isValidParamValueDetail(array $aRouteDefinition) { $bValid = true; $aParamValueDetailExist = [AbstractRouting::PARAM_MATCH => isset($aRouteDefinition[AbstractRouting::PARAM][AbstractRouting::PARAM_MATCH]), AbstractRouting::PARAM_DEFAULT => isset($aRouteDefinition[AbstractRouting::PARAM][AbstractRouting::PARAM_DEFAULT])]; foreach ($aParamValueDetailExist as $sParamName => $bExists) { if ($bExists) { $aParamValueDetails = $aRouteDefinition[AbstractRouting::PARAM][$sParamName]; // On harmonise les détails uniques avec les détails en liste // pour ça, on passe tous les détails uniques en liste. if (ArrayHelper::isAssociative($aParamValueDetails)) { $aParamValueDetails = [$aParamValueDetails]; } foreach ($aParamValueDetails as $mKey => $mParamValueDetailValue) { if (is_array($mParamValueDetailValue)) { // Dans le cas des paramètres par défaut if ($sParamName === AbstractRouting::PARAM_DEFAULT) { // Si l'une des clés du tableau est un mot réservé if (array_intersect(self::$_aReservedKeywords, array_keys($mParamValueDetailValue))) { // Alors la clé AbstractRouting::PARAM_NAME doit être obligatoirement définie if (!isset($mParamValueDetailValue[AbstractRouting::PARAM_NAME])) { self::_recordInvalid($aRouteDefinition, "La propriété [" . AbstractRouting::PARAM . "][{$sParamName}][" . AbstractRouting::PARAM_NAME . "]" . " doit être définie."); $bValid = false; break 2; } } } foreach ($mParamValueDetailValue as $sName => $mValue) { switch ($sName) { case AbstractRouting::PARAM_NAME: if (!is_string($mValue)) { self::_recordInvalid($aRouteDefinition, "La propriété [" . AbstractRouting::PARAM . "][{$sParamName}][{$sName}]" . " doit être définie en tant que chaîne de caractères."); $bValid = false; break 4; } break; case AbstractRouting::PARAM_TYPE: if (!in_array($mValue, self::$_aValidVarTypes)) { self::_recordInvalid($aRouteDefinition, "La propriété [" . AbstractRouting::PARAM . "][{$sParamName}][{$sName}]" . " doit être égale à l'une des valeurs suivantes : \"" . implode('", "', self::$_aValidVarTypes) . "\"."); $bValid = false; break 4; } break; case AbstractRouting::PARAM_VALUE: if (!is_string($mValue) && !is_array($mValue)) { self::_recordInvalid($aRouteDefinition, "La propriété [" . AbstractRouting::PARAM . "][{$sParamName}][{$sName}]" . " doit être une chaîne de caractères ou un tableau de valeurs."); $bValid = false; break 4; } elseif (is_array($mValue) && ArrayHelper::isMulti($mValue)) { self::_recordInvalid($aRouteDefinition, "La propriété [" . AbstractRouting::PARAM . "][{$sParamName}][{$sName}]" . " ne peut pas être un tableau multidimensionnel."); $bValid = false; break 4; } } } } } } } return $bValid; }
protected function _setNestedPropertyValue($sPropertyKeys, $mPropertyValue) { $aNestedPropertyKeys = explode('.', $sPropertyKeys); return ArrayHelper::setNestedValue($this->_aProperties, $aNestedPropertyKeys, $mPropertyValue); }
/** * @see InterfaceConfigSource */ public function getAllValues($sKeyName) { $mResult = self::$_aConfs[$this->_sUid]; if ($mResult === null) { return []; } return ArrayHelper::findAllElementsByKey($sKeyName, $mResult); }