<?php /** * Abstracts operations against the Perforce protections table. * * @copyright 2011 Perforce Software. All rights reserved. * @license Please see LICENSE.txt in top-level folder of this distribution. * @version <release>/<patch> */ namespace P4\Spec; class Protections extends SingularAbstract { const SPEC_TYPE = 'protect'; protected $fields = array( 'Protections' => array( 'accessor' => 'getProtections', 'mutator' => 'setProtections' ) ); /** * Get protections in array form. Format of array is as follows: * * array ( * array ( * 'mode' => 'super', * 'type' => 'user', * 'name' => '*', * 'host' => '*', * 'path' => '//...' * ) * ) * * @return array array of protect entries. */ public function getProtections() { $protections = array(); foreach ((array) $this->getRawValue('Protections') as $line) { $protections[] = $this->toProtectArray($line); } return $protections; } /** * Set protections table entries. * * Individual protection entries may be specified in array or * raw string format for convienence. See getProtections() for format. * * @param array $protections array of protect entries in array or raw string format. * @return Protections provides a fluent interface. */ public function setProtections($protections) { if (!is_array($protections)) { throw new \InvalidArgumentException( 'Protections must be passed as an array' ); } $strings = array(); foreach ($protections as $protect) { // Normalize protection entries to array format for validation if (is_string($protect)) { $protect = $this->toProtectArray($protect); } $strings[] = $this->fromProtectArray($protect); } $this->setRawValue('Protections', $strings); return $this; } /** * Add a protection table entry. * * @param string $mode the access level (e.g. read, write, super, etc.) * @param string $type the type of protection (user or group) * @param string $name the user or group name * @param string $host the host restriction * @param string $path the path to apply the protection to. * @return Protections provides a fluent interface. * @throws \InvalidArgumentException if any inputs are invalid. */ public function addProtection($mode, $type, $name, $host, $path) { if (!is_string($mode) || !is_string($type) || !is_string($name) || !is_string($host) || !is_string($path) ) { throw new \InvalidArgumentException( "Cannot add protection. All parameters must be in string form." ); } // add to protections array. $protections = $this->getRawValue('Protections'); $protections[] = $this->fromProtectArray( array( 'mode' => $mode, 'type' => $type, 'name' => $name, 'host' => $host, 'path' => $path, ) ); $this->setRawValue('Protections', $protections); return $this; } /** * Remove a protection table entry. * * @param string $mode the access level (e.g. read, write, super, etc.) * @param string $type the type of protection (user or group) * @param string $name the user or group name * @param string $host the host restriction * @param string $path the path to apply the protection to. * @return Protections provides a fluent interface. * @throws \InvalidArgumentException if any inputs are invalid. */ public function removeProtection($mode, $type, $name, $host, $path) { if (!is_string($mode) || !is_string($type) || !is_string($name) || !is_string($host) || !is_string($path) ) { throw new \InvalidArgumentException( "Cannot add protection. All parameters must be in string form." ); } $removeArray = array( 'mode' => $mode, 'type' => $type, 'name' => $name, 'host' => $host, 'path' => $path, ); if (!$this->isValidProtectArray($removeArray)) { throw new \InvalidArgumentException( 'Protection array entry is invalid.' ); } // When retrieving the protects value from the depot, the path is not // encapsulated in quotes, so fromProtectArray cannot be used in this case. $remove = $removeArray['mode'] ." ". $removeArray['type'] ." ". $removeArray['name'] ." ". $removeArray['host'] ." ". $removeArray['path'] ; $protections = $this->getRawValue('Protections'); $key = array_search($remove, $protections); if ($key !== false) { unset($protections[$key]); } $this->setRawValue('Protections', $protections); return $this; } /** * Convert a raw protections string (single entry) into an array, * see getProtections for format. * * @param string $entry A single protection entry in string format * @return array A single protect entry array * @throws \InvalidArgumentException If passed string is unparsable */ protected function toProtectArray($entry) { $keys = array('mode', 'type', 'name', 'host', 'path'); $protection = str_getcsv($entry, ' '); if (count($protection) != count($keys)) { throw new \InvalidArgumentException( 'Protection entry with missing field(s) encountered' ); } return array_combine($keys, $protection); } /** * Convert a protection array (single entry) into a string, see * getProtections for format. Will validate input array and throw * on errors. * * @param array $array The single protection entry to validate and convert to string * @return string A single protections entry in string format * @throws \InvalidArgumentException If input is poorly formatted */ protected function fromProtectArray($array) { // Validate the array, will throw if invalid if (!$this->isValidProtectArray($array)) { throw new \InvalidArgumentException( 'Protection array entry is invalid.' ); } $protect = $array['mode'] ." ". $array['type'] ." ". $array['name'] ." ". $array['host'] ." ". '"'. $array['path'] .'"'; return $protect; } /** * Validates a single protection entry in array format, see getProtections * for format details. * * @param array $array A single protect entry in array format * @return bool True - Valid, False - Error(s) found */ protected function isValidProtectArray($array) { if (!is_array($array)) { return false; } // Validate all 'word' fields are present and don't contain spaces $fields = array('mode', 'type', 'name', 'host'); foreach ($fields as $key) { if (!array_key_exists($key, $array) || trim($array[$key]) === '' || preg_match('/\s/', $array[$key])) { return false; } } // Validate 'path' field is present, spaces are permitted if (!array_key_exists('path', $array) || trim($array['path']) === '') { return false; } return true; } }