/** * Create a new version from a database row * * @param array $record */ public function __construct($record) { $this->record = $record; $record['ID'] = $record['RecordID']; $className = $record['ClassName']; $this->object = ClassInfo::exists($className) ? new $className($record) : new DataObject($record); $this->failover = $this->object; parent::__construct(); }
public function testExists() { $this->assertTrue(ClassInfo::exists('SilverStripe\\Core\\Object')); $this->assertTrue(ClassInfo::exists('SilverStripe\\Core\\object')); $this->assertTrue(ClassInfo::exists('ClassInfoTest')); $this->assertTrue(ClassInfo::exists('CLASSINFOTEST')); $this->assertTrue(ClassInfo::exists('stdClass')); $this->assertTrue(ClassInfo::exists('stdCLASS')); $this->assertFalse(ClassInfo::exists('SomeNonExistantClass')); }
/** * @skipUpgrade */ public function testFindClassOrInterfaceFromCandidateImports() { $method = new ReflectionMethod($this->manifest, 'findClassOrInterfaceFromCandidateImports'); $method->setAccessible(true); $this->assertTrue(ClassInfo::exists('silverstripe\\test\\ClassA')); $this->assertEquals('PermissionProvider', $method->invokeArgs($this->manifest, ['\\PermissionProvider', 'Test\\Namespace', array('TestOnly', 'Controller')])); $this->assertEquals('PermissionProvider', $method->invokeArgs($this->manifest, array('PermissionProvider', 'Test\\NAmespace', array('PermissionProvider')))); $this->assertEmpty($method->invokeArgs($this->manifest, array('', 'TextNamespace', array('PermissionProvider')))); $this->assertEmpty($method->invokeArgs($this->manifest, array('', '', array()))); $this->assertEquals('silverstripe\\test\\ClassA', $method->invokeArgs($this->manifest, array('ClassA', 'Test\\Namespace', array('silverstripe\\test\\ClassA', 'PermissionProvider')))); $this->assertEquals('ClassA', $method->invokeArgs($this->manifest, array('\\ClassA', 'Test\\Namespace', array('silverstripe\\test')))); $this->assertEquals('ClassA', $method->invokeArgs($this->manifest, array('ClassA', 'silverstripe\\test', array('\\ClassA')))); $this->assertEquals('ClassA', $method->invokeArgs($this->manifest, array('Alias', 'silverstripe\\test', array('Alias' => '\\ClassA')))); $this->assertEquals('silverstripe\\test\\ClassA', $method->invokeArgs($this->manifest, array('ClassA', 'silverstripe\\test', array('silverstripe\\test\\ClassB')))); }
/** * Gets name of this class * * @return string */ public function getClassName() { $className = $this->getField("ClassName"); if (!ClassInfo::exists($className)) { return static::class; } return $className; }
/** * Return a disabled version of this field. * * Tries to find a class of the class name of this field suffixed with "_Disabled", failing * that, finds a method {@link setDisabled()}. * * @return FormField */ public function performDisabledTransformation() { $disabledClassName = $this->class . '_Disabled'; if (ClassInfo::exists($disabledClassName)) { $clone = $this->castedCopy($disabledClassName); } else { $clone = clone $this; } $clone->setDisabled(true); return $clone; }
/** * Matches a URL pattern * The pattern can contain a number of segments, separated by / (and an extension indicated by a .) * * The parts can be either literals, or, if they start with a $ they are interpreted as variables. * - Literals must be provided in order to match * - $Variables are optional * - However, if you put ! at the end of a variable, then it becomes mandatory. * * For example: * - admin/crm/list will match admin/crm/$Action/$ID/$OtherID, but it won't match admin/crm/$Action!/$ClassName! * * The pattern can optionally start with an HTTP method and a space. For example, "POST $Controller/$Action". * This is used to define a rule that only matches on a specific HTTP method. * * @param $pattern * @param bool $shiftOnSuccess * @return array|bool */ public function match($pattern, $shiftOnSuccess = false) { // Check if a specific method is required if (preg_match('/^([A-Za-z]+) +(.*)$/', $pattern, $matches)) { $requiredMethod = $matches[1]; if ($requiredMethod != $this->httpMethod) { return false; } // If we get this far, we can match the URL pattern as usual. $pattern = $matches[2]; } // Special case for the root URL controller if (!$pattern) { return $this->dirParts == array() ? array('Matched' => true) : false; } // Check for the '//' marker that represents the "shifting point" $doubleSlashPoint = strpos($pattern, '//'); if ($doubleSlashPoint !== false) { $shiftCount = substr_count(substr($pattern, 0, $doubleSlashPoint), '/') + 1; $pattern = str_replace('//', '/', $pattern); $patternParts = explode('/', $pattern); } else { $patternParts = explode('/', $pattern); $shiftCount = sizeof($patternParts); } // Filter out any "empty" matching parts - either from an initial / or a trailing / $patternParts = array_values(array_filter($patternParts)); $arguments = array(); foreach ($patternParts as $i => $part) { $part = trim($part); // Match a variable if (isset($part[0]) && $part[0] == '$') { // A variable ending in ! is required if (substr($part, -1) == '!') { $varRequired = true; $varName = substr($part, 1, -1); } else { $varRequired = false; $varName = substr($part, 1); } // Fail if a required variable isn't populated if ($varRequired && !isset($this->dirParts[$i])) { return false; } /** @skipUpgrade */ $key = "Controller"; $arguments[$varName] = isset($this->dirParts[$i]) ? $this->dirParts[$i] : null; if ($part == '$Controller' && (!ClassInfo::exists($arguments[$key]) || !is_subclass_of($arguments[$key], 'SilverStripe\\Control\\Controller'))) { return false; } // Literal parts with extension } else { if (isset($this->dirParts[$i]) && $this->dirParts[$i] . '.' . $this->extension == $part) { continue; // Literal parts must always be there } else { if (!isset($this->dirParts[$i]) || $this->dirParts[$i] != $part) { return false; } } } } if ($shiftOnSuccess) { $this->shift($shiftCount); // We keep track of pattern parts that we looked at but didn't shift off. // This lets us say that we have *parsed* the whole URL even when we haven't *shifted* it all $this->unshiftedButParsedParts = sizeof($patternParts) - $shiftCount; } $this->latestParams = $arguments; // Load the arguments that actually have a value into $this->allParams // This ensures that previous values aren't overridden with blanks foreach ($arguments as $k => $v) { if ($v || !isset($this->allParams[$k])) { $this->allParams[$k] = $v; } } if ($arguments === array()) { $arguments['_matched'] = true; } return $arguments; }
/** * Returns true if a class or interface name exists in the manifest. * * @param string $class * @return bool */ public function classExists($class) { Deprecation::notice('4.0', 'Use ClassInfo::exists.'); return ClassInfo::exists($class); }
/** * @return string name of {@see GridFieldDetailForm_ItemRequest} subclass */ public function getItemRequestClass() { if ($this->itemRequestClass) { return $this->itemRequestClass; } else { if (ClassInfo::exists(get_class($this) . "_ItemRequest")) { return get_class($this) . "_ItemRequest"; } else { return __CLASS__ . '_ItemRequest'; } } }
/** * Determine if a class is supporting the Versioned extensions (e.g. * $table_Versions does exists). * * @param string $class Class name * @return boolean */ public function canBeVersioned($class) { return ClassInfo::exists($class) && is_subclass_of($class, DataObject::class) && DataObject::getSchema()->classHasTable($class); }
/** * Returns false if the prefilterable parts of the rule aren't met, and true if they are * * @param $rules array - A hash of rules as allowed in the only or except portion of a config fragment header * @return bool - True if the rules are met, false if not. (Note that depending on whether we were passed an * only or an except rule, * which values means accept or reject a fragment */ public function matchesPrefilterVariantRules($rules) { $matches = "undefined"; // Needs to be truthy, but not true foreach ($rules as $k => $v) { switch (strtolower($k)) { case 'classexists': $matches = $matches && ClassInfo::exists($v); break; case 'moduleexists': $matches = $matches && $this->moduleExists($v); break; default: // NOP } if ($matches === false) { return $matches; } } return $matches; }
/** * Tries to find the database key on another object that is used to store a * relationship to this class. If no join field can be found it defaults to 'ParentID'. * * If the remote field is polymorphic then $polymorphic is set to true, and the return value * is in the form 'Relation' instead of 'RelationID', referencing the composite DBField. * * @param string $class * @param string $component Name of the relation on the current object pointing to the * remote object. * @param string $type the join type - either 'has_many' or 'belongs_to' * @param boolean $polymorphic Flag set to true if the remote join field is polymorphic. * @return string * @throws Exception */ public function getRemoteJoinField($class, $component, $type = 'has_many', &$polymorphic = false) { // Extract relation from current object if ($type === 'has_many') { $remoteClass = $this->hasManyComponent($class, $component, false); } else { $remoteClass = $this->belongsToComponent($class, $component, false); } if (empty($remoteClass)) { throw new Exception("Unknown {$type} component '{$component}' on class '{$class}'"); } if (!ClassInfo::exists(strtok($remoteClass, '.'))) { throw new Exception("Class '{$remoteClass}' not found, but used in {$type} component '{$component}' on class '{$class}'"); } // If presented with an explicit field name (using dot notation) then extract field name $remoteField = null; if (strpos($remoteClass, '.') !== false) { list($remoteClass, $remoteField) = explode('.', $remoteClass); } // Reference remote has_one to check against $remoteRelations = Config::inst()->get($remoteClass, 'has_one'); // Without an explicit field name, attempt to match the first remote field // with the same type as the current class if (empty($remoteField)) { // look for remote has_one joins on this class or any parent classes $remoteRelationsMap = array_flip($remoteRelations); foreach (array_reverse(ClassInfo::ancestry($class)) as $class) { if (array_key_exists($class, $remoteRelationsMap)) { $remoteField = $remoteRelationsMap[$class]; break; } } } // In case of an indeterminate remote field show an error if (empty($remoteField)) { $polymorphic = false; $message = "No has_one found on class '{$remoteClass}'"; if ($type == 'has_many') { // include a hint for has_many that is missing a has_one $message .= ", the has_many relation from '{$class}' to '{$remoteClass}'"; $message .= " requires a has_one on '{$remoteClass}'"; } throw new Exception($message); } // If given an explicit field name ensure the related class specifies this if (empty($remoteRelations[$remoteField])) { throw new Exception("Missing expected has_one named '{$remoteField}'\n\t\t\t\ton class '{$remoteClass}' referenced by {$type} named '{$component}'\n\t\t\t\ton class {$class}"); } // Inspect resulting found relation if ($remoteRelations[$remoteField] === DataObject::class) { $polymorphic = true; return $remoteField; // Composite polymorphic field does not include 'ID' suffix } else { $polymorphic = false; return $remoteField . 'ID'; } }
/** * Persists the YAML data in a FixtureFactory, * which in turn saves them into the database. * Please use the passed in factory to access the fixtures afterwards. * * @param FixtureFactory $factory */ public function writeInto(FixtureFactory $factory) { $parser = new Parser(); if (isset($this->fixtureString)) { $fixtureContent = $parser->parse($this->fixtureString); } else { if (!file_exists($this->fixtureFile)) { return; } $contents = file_get_contents($this->fixtureFile); $fixtureContent = $parser->parse($contents); if (!$fixtureContent) { return; } } foreach ($fixtureContent as $class => $items) { foreach ($items as $identifier => $data) { if (ClassInfo::exists($class)) { $factory->createObject($class, $identifier, $data); } else { $factory->createRaw($class, $identifier, $data); } } } }
/** * Given a partial class name, attempt to determine the best module to assign strings to. * * @param string $class Either a FQN class name, or a non-qualified class name. * @return string Name of module */ protected function findModuleForClass($class) { if (ClassInfo::exists($class)) { return i18n::get_owner_module($class); } // If we can't find a class, see if it needs to be fully qualified if (strpos($class, '\\') !== false) { return null; } // Find FQN that ends with $class $classes = preg_grep('/' . preg_quote("\\{$class}", '\\/') . '$/i', ClassLoader::instance()->getManifest()->getClassNames()); // Find all modules for candidate classes $modules = array_unique(array_map(function ($class) { return i18n::get_owner_module($class); }, $classes)); if (count($modules) === 1) { return reset($modules); } // Couldn't find it! Exists in none, or multiple modules. return null; }