/**
  * Returns a readonly span containing the correct value.
  *
  * @param array $properties
  *
  * @return string
  */
 public function Field($properties = array())
 {
     $source = ArrayLib::flatten($this->getSource());
     $values = $this->getValueArray();
     // Get selected values
     $mapped = array();
     foreach ($values as $value) {
         if (isset($source[$value])) {
             $mapped[] = $source[$value];
         }
     }
     // Don't check if string arguments are matching against the source,
     // as they might be generated HTML diff views instead of the actual values
     if ($this->value && is_string($this->value) && empty($mapped)) {
         $mapped = array(trim($this->value));
         $values = array();
     }
     if ($mapped) {
         $attrValue = implode(', ', array_values($mapped));
         $attrValue = Convert::raw2xml($attrValue);
         $inputValue = implode(', ', array_values($values));
     } else {
         $attrValue = '<i>(' . _t('FormField.NONE', 'none') . ')</i>';
         $inputValue = '';
     }
     $properties = array_merge($properties, array('AttrValue' => DBField::create_field('HTMLFragment', $attrValue), 'InputValue' => $inputValue));
     return parent::Field($properties);
 }
 public function testFlatten()
 {
     $options = array('1' => 'one', '2' => 'two');
     $expected = $options;
     $this->assertEquals($expected, ArrayLib::flatten($options));
     $options = array('1' => array('2' => 'two', '3' => 'three'), '4' => 'four');
     $expected = array('2' => 'two', '3' => 'three', '4' => 'four');
     $this->assertEquals($expected, ArrayLib::flatten($options));
 }
 public function testRefusesToWrapAnIndexedArray()
 {
     $array = array(0 => "One", 1 => "Two");
     $this->assertFalse(ArrayLib::is_associative($array));
     /*
      * Expect user_error() to be called below, if enabled
      * (tobych) That should be an exception. Something like:
      * $this->setExpectedException('InvalidArgumentException');
      */
     // $arrayData = new ArrayData($array);
 }
 /**
  * Gets a field from this object.
  *
  *
  * If the value is an object but not an instance of
  * ViewableData, it will be converted recursively to an
  * ArrayData.
  *
  * If the value is an associative array, it will likewise be
  * converted recursively to an ArrayData.
  *
  * @param string $field
  * @return mixed
  */
 public function getField($field)
 {
     $value = $this->array[$field];
     if (is_object($value) && !$value instanceof ViewableData) {
         return new ArrayData($value);
     } elseif (ArrayLib::is_associative($value)) {
         return new ArrayData($value);
     } else {
         return $value;
     }
 }
 /**
  * Builds a new currency field based on the allowed currencies configured
  *
  * @return FormField
  */
 protected function buildCurrencyField()
 {
     $name = $this->getName();
     $allowedCurrencies = $this->getAllowedCurrencies();
     if ($allowedCurrencies) {
         $field = new DropdownField("{$name}[Currency]", _t('MoneyField.FIELDLABELCURRENCY', 'Currency'), ArrayLib::is_associative($allowedCurrencies) ? $allowedCurrencies : array_combine($allowedCurrencies, $allowedCurrencies));
     } else {
         $field = new TextField("{$name}[Currency]", _t('MoneyField.FIELDLABELCURRENCY', 'Currency'));
     }
     $field->setReadonly($this->isReadonly());
     $field->setDisabled($this->isDisabled());
     return $field;
 }
 /**
  * @covers SilverStripe\Core\ClassInfo::ancestry()
  */
 public function testAncestry()
 {
     $ancestry = ClassInfo::ancestry('ClassInfoTest_ChildClass');
     $expect = ArrayLib::valuekey(array('SilverStripe\\Core\\Object', 'SilverStripe\\View\\ViewableData', 'SilverStripe\\ORM\\DataObject', 'ClassInfoTest_BaseClass', 'ClassInfoTest_ChildClass'));
     $this->assertEquals($expect, $ancestry);
     ClassInfo::reset_db_cache();
     $this->assertEquals($expect, ClassInfo::ancestry('classINFOTest_Childclass'));
     ClassInfo::reset_db_cache();
     $this->assertEquals($expect, ClassInfo::ancestry('classINFOTest_Childclass'));
     ClassInfo::reset_db_cache();
     $ancestry = ClassInfo::ancestry('ClassInfoTest_ChildClass', true);
     $this->assertEquals(array('ClassInfoTest_BaseClass' => 'ClassInfoTest_BaseClass'), $ancestry, '$tablesOnly option excludes memory-only inheritance classes');
 }
    public function testEnumParsing()
    {
        $enum = new DBEnum('testField', "\n\t\t\t,\n\t\t\t0,\n\t\t\tItem1,\n\t\t\tItem2,\n\t\t\tItem 3,\n\t\t\tItem-4,\n\t\t\titem 5\n\t\t\tstill 5,\n\t\t\ttrailing comma,\n\t\t");
        $this->assertEquals(ArrayLib::valuekey(array('', '0', 'Item1', 'Item2', 'Item 3', 'Item-4', 'item 5
			still 5', 'trailing comma')), $enum->enumValues());
    }
 /**
  * Returns all combined HTTP GET and POST parameters
  * passed into this request. If a parameter with the same
  * name exists in both arrays, the POST value is returned.
  *
  * @return array
  */
 public function requestVars()
 {
     return ArrayLib::array_merge_recursive($this->getVars, $this->postVars);
 }
 /**
  * Merge some arbitrary data in with this object. This method returns a {@link ViewableData_Customised} instance
  * with references to both this and the new custom data.
  *
  * Note that any fields you specify will take precedence over the fields on this object.
  *
  * @param array|ViewableData $data
  * @return ViewableData_Customised
  */
 public function customise($data)
 {
     if (is_array($data) && (empty($data) || ArrayLib::is_associative($data))) {
         $data = new ArrayData($data);
     }
     if ($data instanceof ViewableData) {
         return new ViewableData_Customised($this, $data);
     }
     throw new InvalidArgumentException('ViewableData->customise(): $data must be an associative array or a ViewableData instance');
 }
 public function getList()
 {
     $context = $this->getSearchContext();
     $params = $this->getRequest()->requestVar('q');
     if (is_array($params)) {
         $params = ArrayLib::array_map_recursive('trim', $params);
         // Parse all DateFields to handle user input non ISO 8601 dates
         foreach ($context->getFields() as $field) {
             if ($field instanceof DatetimeField) {
                 $params[$field->getName()] = date('Y-m-d', strtotime($params[$field->getName()]));
             }
         }
     }
     $list = $context->getResults($params);
     $this->extend('updateList', $list);
     return $list;
 }
 /**
  * Test a URL request, returning a response object. This method is the counterpart of
  * Director::direct() that is used in functional testing. It will execute the URL given, and
  * return the result as an HTTPResponse object.
  *
  * @uses Controller::handleRequest() Handles the page logic for a Director::direct() call.
  *
  * @param string $url The URL to visit.
  * @param array $postVars The $_POST & $_FILES variables.
  * @param array|Session $session The {@link Session} object representing the current session.
  * By passing the same object to multiple  calls of Director::test(), you can simulate a persisted
  * session.
  * @param string $httpMethod The HTTP method, such as GET or POST.  It will default to POST if
  * postVars is set, GET otherwise. Overwritten by $postVars['_method'] if present.
  * @param string $body The HTTP body.
  * @param array $headers HTTP headers with key-value pairs.
  * @param array|Cookie_Backend $cookies to populate $_COOKIE.
  * @param HTTPRequest $request The {@see SS_HTTP_Request} object generated as a part of this request.
  *
  * @return HTTPResponse
  *
  * @throws HTTPResponse_Exception
  */
 public static function test($url, $postVars = null, $session = array(), $httpMethod = null, $body = null, $headers = array(), $cookies = array(), &$request = null)
 {
     Config::nest();
     Injector::nest();
     // These are needed so that calling Director::test() does not muck with whoever is calling it.
     // Really, it's some inappropriate coupling and should be resolved by making less use of statics.
     $oldReadingMode = Versioned::get_reading_mode();
     $getVars = array();
     if (!$httpMethod) {
         $httpMethod = $postVars || is_array($postVars) ? "POST" : "GET";
     }
     if (!$session) {
         $session = Injector::inst()->create('SilverStripe\\Control\\Session', array());
     }
     $cookieJar = $cookies instanceof Cookie_Backend ? $cookies : Injector::inst()->createWithArgs('SilverStripe\\Control\\Cookie_Backend', array($cookies ?: array()));
     // Back up the current values of the superglobals
     $existingRequestVars = isset($_REQUEST) ? $_REQUEST : array();
     $existingGetVars = isset($_GET) ? $_GET : array();
     $existingPostVars = isset($_POST) ? $_POST : array();
     $existingSessionVars = isset($_SESSION) ? $_SESSION : array();
     $existingCookies = isset($_COOKIE) ? $_COOKIE : array();
     $existingServer = isset($_SERVER) ? $_SERVER : array();
     $existingRequirementsBackend = Requirements::backend();
     Cookie::config()->update('report_errors', false);
     Requirements::set_backend(Requirements_Backend::create());
     // Set callback to invoke prior to return
     $onCleanup = function () use($existingRequestVars, $existingGetVars, $existingPostVars, $existingSessionVars, $existingCookies, $existingServer, $existingRequirementsBackend, $oldReadingMode) {
         // Restore the super globals
         $_REQUEST = $existingRequestVars;
         $_GET = $existingGetVars;
         $_POST = $existingPostVars;
         $_SESSION = $existingSessionVars;
         $_COOKIE = $existingCookies;
         $_SERVER = $existingServer;
         Requirements::set_backend($existingRequirementsBackend);
         // These are needed so that calling Director::test() does not muck with whoever is calling it.
         // Really, it's some inappropriate coupling and should be resolved by making less use of statics
         Versioned::set_reading_mode($oldReadingMode);
         Injector::unnest();
         // Restore old CookieJar, etc
         Config::unnest();
     };
     if (strpos($url, '#') !== false) {
         $url = substr($url, 0, strpos($url, '#'));
     }
     // Handle absolute URLs
     if (parse_url($url, PHP_URL_HOST)) {
         $bits = parse_url($url);
         // If a port is mentioned in the absolute URL, be sure to add that into the HTTP host
         if (isset($bits['port'])) {
             $_SERVER['HTTP_HOST'] = $bits['host'] . ':' . $bits['port'];
         } else {
             $_SERVER['HTTP_HOST'] = $bits['host'];
         }
     }
     // Ensure URL is properly made relative.
     // Example: url passed is "/ss31/my-page" (prefixed with BASE_URL), this should be changed to "my-page"
     $url = self::makeRelative($url);
     $urlWithQuerystring = $url;
     if (strpos($url, '?') !== false) {
         list($url, $getVarsEncoded) = explode('?', $url, 2);
         parse_str($getVarsEncoded, $getVars);
     }
     // Replace the super globals with appropriate test values
     $_REQUEST = ArrayLib::array_merge_recursive((array) $getVars, (array) $postVars);
     $_GET = (array) $getVars;
     $_POST = (array) $postVars;
     $_SESSION = $session ? $session->inst_getAll() : array();
     $_COOKIE = $cookieJar->getAll(false);
     Injector::inst()->registerService($cookieJar, 'SilverStripe\\Control\\Cookie_Backend');
     $_SERVER['REQUEST_URI'] = Director::baseURL() . $urlWithQuerystring;
     $request = new HTTPRequest($httpMethod, $url, $getVars, $postVars, $body);
     if ($headers) {
         foreach ($headers as $k => $v) {
             $request->addHeader($k, $v);
         }
     }
     // Pre-request filtering
     // @see issue #2517
     $model = DataModel::inst();
     $output = Injector::inst()->get('SilverStripe\\Control\\RequestProcessor')->preRequest($request, $session, $model);
     if ($output === false) {
         $onCleanup();
         throw new HTTPResponse_Exception(_t('Director.INVALID_REQUEST', 'Invalid request'), 400);
     }
     // TODO: Pass in the DataModel
     $result = Director::handleRequest($request, $session, $model);
     // Ensure that the result is an HTTPResponse object
     if (is_string($result)) {
         if (substr($result, 0, 9) == 'redirect:') {
             $response = new HTTPResponse();
             $response->redirect(substr($result, 9));
             $result = $response;
         } else {
             $result = new HTTPResponse($result);
         }
     }
     $output = Injector::inst()->get('SilverStripe\\Control\\RequestProcessor')->postRequest($request, $result, $model);
     if ($output === false) {
         $onCleanup();
         throw new HTTPResponse_Exception("Invalid response");
     }
     // Return valid response
     $onCleanup();
     return $result;
 }
 /**
  * Returns a list of classes that inherit from the given class.
  * The resulting array includes the base class passed
  * through the $class parameter as the first array value.
  *
  * Example usage:
  * <code>
  * ClassInfo::subclassesFor('BaseClass');
  * 	array(
  * 	'BaseClass' => 'BaseClass',
  * 	'ChildClass' => 'ChildClass',
  * 	'GrandChildClass' => 'GrandChildClass'
  * )
  * </code>
  *
  * @param string|object $nameOrObject The classname or object
  * @return array Names of all subclasses as an associative array.
  */
 public static function subclassesFor($nameOrObject)
 {
     if (is_string($nameOrObject) && !class_exists($nameOrObject)) {
         return [];
     }
     //normalise class case
     $className = self::class_name($nameOrObject);
     $descendants = ClassLoader::instance()->getManifest()->getDescendantsOf($className);
     $result = array($className => $className);
     if ($descendants) {
         return $result + ArrayLib::valuekey($descendants);
     } else {
         return $result;
     }
 }
示例#13
0
 /**
  * This is the main translator function. Returns the string defined by $class and $entity according to the
  * currently set locale.
  *
  * @param string $entity Entity that identifies the string. It must be in the form "Namespace.Entity" where
  *                       Namespace will be usually the class name where this string is used and Entity identifies
  *                       the string inside the namespace.
  * @param string $string The original string itself. In a usual call this is a mandatory parameter, but if you are
  *                       reusing a string which has already been "declared" (using another call to this function,
  *                       with the same class and entity), you can omit it.
  * @param string $context (optional) If the string can be difficult to translate by any reason, you can help
  *                        translators with some more info using this param
  * @param array $injection (optional) array of key value pairs that are used to replace corresponding
  *                              expressions in {curly brackets} in the $string. The injection array can also be
  *                              used as the their argument to the _t() function
  * @return string The translated string, according to the currently set locale {@link i18n::set_locale()}
  */
 public static function _t($entity, $string = "", $context = "", $injection = null)
 {
     //fetch the injection array out of the parameters (if it is present)
     $argList = func_get_args();
     $argNum = func_num_args();
     //_t($entity, $string = "", $context (optional), $injectionArray (optional))
     $injectionArray = null;
     for ($i = 0; $i < $argNum; $i++) {
         if (is_array($argList[$i])) {
             //we have reached the injectionArray
             $injectionArray = $argList[$i];
             //any array in the args will be the injection array
         }
     }
     // Find best translation
     $locale = i18n::get_locale();
     $returnValue = static::with_translators(function (Zend_Translate_Adapter $adapter) use($entity, $locale) {
         // Return translation only if we found a match thats not the entity itself (Zend fallback)
         $translation = $adapter->translate($entity, $locale);
         if ($translation && $translation != $entity) {
             return $translation;
         }
         return null;
     });
     // Fall back to default string argument
     if ($returnValue === null) {
         $returnValue = is_string($string) ? $string : '';
     }
     // inject the variables from injectionArray (if present)
     if ($injectionArray) {
         $regex = '/\\{[\\w\\d]*\\}/i';
         if (!preg_match($regex, $returnValue)) {
             // Legacy mode: If no injection placeholders are found,
             // replace sprintf placeholders in fixed order.
             // Fail silently in case the translation is outdated
             preg_match_all('/%[s,d]/', $returnValue, $returnValueArgs);
             if ($returnValueArgs) {
                 foreach ($returnValueArgs[0] as $i => $returnValueArg) {
                     if ($i >= count($injectionArray)) {
                         $injectionArray[] = '';
                     }
                 }
             }
             $replaced = vsprintf($returnValue, array_values($injectionArray));
             if ($replaced) {
                 $returnValue = $replaced;
             }
         } else {
             if (!ArrayLib::is_associative($injectionArray)) {
                 // Legacy mode: If injection placeholders are found,
                 // but parameters are passed without names, replace them in fixed order.
                 $returnValue = preg_replace_callback($regex, function () use(&$injectionArray) {
                     return $injectionArray ? array_shift($injectionArray) : '';
                 }, $returnValue);
             } else {
                 // Standard placeholder replacement with named injections and variable order.
                 foreach ($injectionArray as $variable => $injection) {
                     $placeholder = '{' . $variable . '}';
                     $returnValue = str_replace($placeholder, $injection, $returnValue, $count);
                     if (!$count) {
                         Injector::inst()->get('Logger')->log('notice', sprintf("Couldn't find placeholder '%s' in translation string '%s' (id: '%s')", $placeholder, $returnValue, $entity));
                     }
                 }
             }
         }
     }
     return $returnValue;
 }
 /**
  * Add {@link RequiredField} objects together
  *
  * @param RequiredFields $requiredFields
  * @return RequiredFields
  */
 public function appendRequiredFields($requiredFields)
 {
     $this->required = $this->required + ArrayLib::valuekey($requiredFields->getRequired());
     return $this;
 }