Overview

Namespaces

  • GAubry
    • ErrorHandler
    • Helpers
    • Logger
    • Shell
  • Himedia
    • Padocc
      • DB
      • Minifier
      • Numbering
      • Properties
      • Task
        • Base
        • Extended
  • None
  • Psr
    • Log

Classes

  • AttributeProperties
  • Deployment
  • DeploymentStatus
  • DIContainer
  • Padocc
  • Task

Interfaces

  • DIContainerInterface
  • Overview
  • Namespace
  • Class
  • Tree
  • Deprecated
  • Todo
  1: <?php
  2: 
  3: namespace Himedia\Padocc;
  4: 
  5: use GAubry\Shell\PathStatus;
  6: use GAubry\Shell\ShellAdapter;
  7: 
  8: /**
  9:  * Collection des propriétés possibles pour un attribut de tâche.
 10:  * Ces propriétés sont manipulées au sein de champs de bits dans la classe Task.
 11:  *
 12:  * @author Geoffroy AUBRY <gaubry@hi-media.com>
 13:  * @see Task::$aAttrProperties()
 14:  */
 15: class AttributeProperties
 16: {
 17:     /**
 18:      * Propriété d'attribut : autorise l'utilisation des '${parameter}'.
 19:      * @var int
 20:      */
 21:     const ALLOW_PARAMETER = 1;
 22: 
 23:     /**
 24:      * Propriété d'attribut : l'attribut désigne un répertoire.
 25:      * @var int
 26:      */
 27:     const DIR = 2;
 28: 
 29:     /**
 30:      * Propriété d'attribut : autorise l'utilisation des jokers shell ? et * pour les répertoires
 31:      * (implique AttributeProperties::DIR).
 32:      * @var int
 33:      */
 34:     const DIRJOKER = 4;
 35: 
 36:     /**
 37:      * Propriété d'attribut : l'attribut désigne un fichier.
 38:      * @var int
 39:      */
 40:     const FILE = 8;
 41: 
 42:     /**
 43:      * Propriété d'attribut : autorise l'utilisation des jokers shell ? et * pour les fichiers
 44:      * (implique AttributeProperties::FILE).
 45:      * @var int
 46:      */
 47:     const FILEJOKER = 16;
 48: 
 49:     /**
 50:      * Propriété d'attribut : l'attribut est obligatoire.
 51:      * @var int
 52:      */
 53:     const REQUIRED = 32;
 54: 
 55:     /**
 56:      * Propriété d'attribut : l'attribut est un fichier ou un répertoire source et doit donc exister
 57:      * (implique AttributeProperties::FILE et AttributeProperties::DIR).
 58:      * @var int
 59:      */
 60:     const SRC_PATH = 64;
 61: 
 62:     /**
 63:      * Propriété d'attribut : l'attribut est un booléen sous forme de chaîne de caractères,
 64:      * valant soit 'true' soit 'false'.
 65:      * @var int
 66:      */
 67:     const BOOLEAN = 128;
 68: 
 69:     /**
 70:      * Propriété d'attribut : l'attribut est une URL.
 71:      * @var int
 72:      */
 73:     const URL = 256;
 74: 
 75:     /**
 76:      * Propriété d'attribut : l'attribut est un email.
 77:      * @var int
 78:      */
 79:     const EMAIL = 512;
 80: 
 81:     /**
 82:      * Propriété d'attribut : l'attribut peut être multi-valué.
 83:      * @var int
 84:      */
 85:     const MULTI_VALUED = 1024;
 86: 
 87:     /**
 88:      * Pattern regex pour scinder les différentes valeurs d'un attribut doté de la propriété MULTI_VALUED.
 89:      * @var string
 90:      * @see checkAttributes()
 91:      */
 92:     public static $sMultiValuedSep = '/\s*,\s*/';
 93: 
 94:     /**
 95:      * Glue pour concaténer les différentes valeurs d'un attribut doté de la propriété MULTI_VALUED.
 96:      * @var string
 97:      * @see checkAttributes()
 98:      */
 99:     public static $sMultiValuedJoinGlue = ', ';
100: 
101:     /**
102:      * Shell adapter.
103:      * @var ShellAdapter
104:      */
105:     protected $oShell;
106: 
107:     /**
108:      * Constructeur.
109:      *
110:      * @param ShellAdapter $oShell
111:      */
112:     public function __construct (ShellAdapter $oShell)
113:     {
114:         $this->oShell = $oShell;
115:     }
116: 
117:     /**
118:      * Normalise les propriétés des attributs des tâches XML.
119:      * Par exemple si c'est un AttributeProperties::FILEJOKER, alors c'est forcément aussi
120:      * un AttributeProperties::FILE.
121:      *
122:      * @param array &$aProperties tableau associatif 'nom d'attribut' => propriétés de l'attribut
123:      * @see aAttributeProperties
124:      */
125:     private function normalizeAttributeProperties (array &$aProperties)
126:     {
127:         foreach ($aProperties as $sAttribute => $iProperties) {
128:             if (($iProperties & self::SRC_PATH) > 0) {
129:                 $aProperties[$sAttribute] |= self::FILE | self::DIR;
130:             }
131:             if (($iProperties & self::FILEJOKER) > 0) {
132:                 $aProperties[$sAttribute] |= self::FILE;
133:             }
134:             if (($iProperties & self::DIRJOKER) > 0) {
135:                 $aProperties[$sAttribute] |= self::DIR;
136:             }
137:         }
138:     }
139: 
140:     /**
141:      * Vérifie l'absence d'attribut non permis.
142:      *
143:      * @param array $aProperties tableau associatif (nom d'attribut => (int)champ de bits de propriétés d'attribut)
144:      *      Les propriétés sont une combinaisons de constantes de cette classe (ex. self::EMAIL).
145:      * @param array $aValues tableau associatif (nom d'attribut => (string)valeur)
146:      * @throws \DomainException en cas d'attribut non permis
147:      */
148:     private function checkUnknownAttributes (array $aProperties, array $aValues)
149:     {
150:         $aAvailablesAttr = array_keys($aProperties);
151:         $aUnknownAttributes = array_diff(array_keys($aValues), $aAvailablesAttr);
152:         if (count($aUnknownAttributes) > 0) {
153:             throw new \DomainException(
154:                 "Available attributes: " . print_r($aAvailablesAttr, true)
155:                 . " => Unknown attribute(s): " . print_r($aUnknownAttributes, true)
156:             );
157:         }
158:     }
159: 
160:     /**
161:      * Vérifie au moyen de tests basiques que les valeurs des attributs sont conformes à leurs propriétés.
162:      * Lance une exception si tel n'est pas le cas.
163:      *
164:      * @param array &$aProperties tableau associatif (nom d'attribut => (int)champ de bits de propriétés d'attribut)
165:      *      Les propriétés sont une combinaisons de constantes de cette classe (ex. self::EMAIL).
166:      *      Passé par référence car potentiellement modifié par normalizeAttributeProperties().
167:      * @param array &$aValues tableau associatif (nom d'attribut => (string)valeur)
168:      *      Passé par référence car potentiellement modifié par formatAttribute().
169:      * @throws \UnexpectedValueException en cas d'attribut ou fichier manquant
170:      * @throws \DomainException en cas d'attribut non permis
171:      */
172:     public function checkAttributes (array &$aProperties, array &$aValues)
173:     {
174:         $this->normalizeAttributeProperties($aProperties);
175:         $this->checkUnknownAttributes($aProperties, $aValues);
176: 
177:         foreach ($aProperties as $sName => $iProperties) {
178:             if (! empty($aValues[$sName])) {
179:                 if (($iProperties & self::MULTI_VALUED) > 0) {
180:                     $aSplittedValues = preg_split(
181:                         self::$sMultiValuedSep,
182:                         $aValues[$sName],
183:                         -1,
184:                         PREG_SPLIT_NO_EMPTY
185:                     );
186:                 } else {
187:                     $aSplittedValues = array($aValues[$sName]);
188:                 }
189: 
190:                 foreach ($aSplittedValues as $i => $sSplittedValue) {
191:                     $aSplittedValues[$i] = $this->formatAttribute($iProperties, $sSplittedValue);
192:                     $this->checkAttribute($sName, $iProperties, $sSplittedValue);
193:                 }
194:                 $aValues[$sName] = implode(self::$sMultiValuedJoinGlue, $aSplittedValues);
195: 
196:             } else {
197:                 $this->checkAttribute($sName, $iProperties, '');
198:             }
199:         }
200:     }
201: 
202:     /**
203:      * Formate la valeur d'un attribut au regard de ses propriétés.
204:      *
205:      * @param int $iProperties champ de bits de propriétés d'attribut,
206:      *      combinaisons de constantes de cette classe (ex. self::EMAIL).
207:      * @param string $sValue valeur de l'attribut
208:      * @return string valeur potentiellement formatée de l'attribut au regard de ses propriétés.
209:      */
210:     private function formatAttribute ($iProperties, $sValue)
211:     {
212:         if (! empty($sValue)) {
213:             if (($iProperties & self::DIR) > 0 || ($iProperties & self::FILE) > 0) {
214:                 $sValue = str_replace('\\', '/', $sValue);
215:             }
216:         }
217:         return $sValue;
218:     }
219: 
220:     /**
221:      * Vérifie au moyen de tests basiques que la valeur de l'attribut spécifié est conforme à ses propriétés.
222:      * Lance une exception si tel n'est pas le cas.
223:      *
224:      * @param string $sName nom d'attribut
225:      * @param int $iProperties champ de bits de propriétés d'attribut,
226:      *      combinaisons de constantes de cette classe (ex. self::EMAIL).
227:      * @param string $sValue valeur de l'attribut
228:      * @throws \UnexpectedValueException en cas d'attribut ou fichier manquant
229:      * @throws \DomainException en cas de valeur non permise
230:      */
231:     private function checkAttribute ($sName, $iProperties, $sValue)
232:     {
233:         if (empty($sValue) && ($iProperties & self::REQUIRED) > 0) {
234:             throw new \UnexpectedValueException("'$sName' attribute is required!");
235: 
236:         } elseif (! empty($sValue)) {
237:             if (($iProperties & self::BOOLEAN) > 0 && ! in_array($sValue, array('true', 'false'))) {
238:                 $sMsg = "Value of '$sName' attribute is restricted to 'true' or 'false'. Value: '$sValue'!";
239:                 throw new \DomainException($sMsg);
240:             }
241: 
242:             if (($iProperties & self::URL) > 0 && preg_match('#^http://#i', $sValue) === 0) {
243:                 throw new \DomainException("Bad URL: '" . $sValue . "'");
244:             }
245: 
246:             if (($iProperties & self::EMAIL) > 0
247:                 && preg_match(
248:                     '#^[[:alnum:]]([-_.]?[[:alnum:]_?])*@[[:alnum:]]([-.]?[[:alnum:]])+\.([a-z]{2,6})$#',
249:                     $sValue
250:                 ) === 0
251:             ) {
252:                 throw new \DomainException("Email invalid: '" . $sValue . "'");
253:             }
254: 
255:             if (preg_match('#[*?].*/#', $sValue) !== 0 && ($iProperties & self::DIRJOKER) === 0) {
256:                 $sMsg = "'*' and '?' jokers are not authorized for directory in '$sName' attribute!";
257:                 throw new \DomainException($sMsg);
258:             }
259: 
260:             if (preg_match('#[*?](.*[^/])?$#', $sValue) !== 0
261:                 && ($iProperties & self::FILEJOKER) === 0
262:                 && ($iProperties & self::URL) === 0
263:             ) {
264:                 $sMsg = "'*' and '?' jokers are not authorized for filename in '$sName' attribute!";
265:                 throw new \DomainException($sMsg);
266:             }
267: 
268:             if (preg_match('#\$\{[^}]*\}#', $sValue) !== 0 && ($iProperties & self::ALLOW_PARAMETER) === 0) {
269:                 $sMsg = "Parameters are not allowed in '$sName' attribute! Value: '$sValue'";
270:                 throw new \DomainException($sMsg);
271:             }
272: 
273:             // Vérification de présence de la source si chemin sans joker ni paramètre :
274:             if (($iProperties & self::SRC_PATH) > 0
275:                 && preg_match('#\*|\?|\$\{[^}]*\}#', $sValue) === 0
276:                 && $this->oShell->getPathStatus($sValue) === PathStatus::STATUS_NOT_EXISTS
277:             ) {
278:                 throw new \UnexpectedValueException("File or directory '$sValue' not found!");
279:             }
280:         }
281:     }
282: }
283: 
Platform for Automatized Deployments with pOwerful Concise Configuration API documentation generated by ApiGen 2.8.0