/** * Automatically extracts and replaces the category, keywords and entities * for a data object. * * @param DataObject $object */ public function alchemise(DataObject $object) { if (!$object->hasExtension('Alchemisable')) { throw new Exception('The object must have the Alchemisable extension.'); } $text = $object->getContentForAlchemy(); if (strlen($text) < $this->charLimit) { return; } $alchemyInfo = $object->AlchemyMetadata->getValues(); if (!$alchemyInfo) { $alchemyInfo = array(); } $cat = $this->getCategoryFor($text); $keywords = $this->getKeywordsFor($text); $entities = $this->getEntitiesFor($text); $alchemyInfo['Category'] = $cat; $alchemyInfo['Keywords'] = $keywords; $alchemyInfo['Entities'] = $entities; $object->AlchemyMetadata = $alchemyInfo; // foreach (Alchemisable::entity_fields() as $field => $name) { // $name = substr($field, 3); // // if (array_key_exists($name, $entities)) { // $object->$field = $entities[$name]; // } else { // $object->$field = array(); // } // } }
/** * Gets the workflow definition for a given dataobject, if there is one * * Will recursively query parent elements until it finds one, if available * * @param DataObject $dataObject */ public function getDefinitionFor(DataObject $dataObject) { if ($dataObject->hasExtension('WorkflowApplicable') || $dataObject->hasExtension('FileWorkflowApplicable')) { if ($dataObject->WorkflowDefinitionID) { return DataObject::get_by_id('WorkflowDefinition', $dataObject->WorkflowDefinitionID); } if ($dataObject->ParentID) { return $this->getDefinitionFor($dataObject->Parent()); } if ($dataObject->hasMethod('workflowParent')) { $obj = $dataObject->workflowParent(); if ($obj) { return $this->getDefinitionFor($obj); } } } return null; }
/** * @param DataObject $record * @param int $index */ public function deleteRecord($record, $index) { if ($record->hasExtension('Versioned')) { $record->deleteFromStage('Stage'); $record->deleteFromStage('Live'); } else { $record->delete(); } }
/** * Return true or false as to whether a given user can access an object * * @param DataObject $node * The object to check perms on * @param string $perm * The permission to check against * @param Member $member * The member to check - if not set, the current user is used * * @return type */ public function checkPerm(DataObject $node, $perm, $member = null) { // if the node doesn't use the extension, fall back to SS logic if (!$node->hasExtension('Restrictable')) { switch ($perm) { case 'View': return $node->canView($member); case 'Write': return $node->canEdit($member); default: return $node->can($perm, $member); } } if (!$node) { return false; } if (!$member) { $member = singleton('SecurityContext')->getMember(); } if (is_int($member)) { $member = DataObject::get_by_id('Member', $member); } if (Permission::check('ADMIN', 'any', $member)) { return true; } $permCache = $this->getCache(); /* @var $permCache Zend_Cache_Core */ $key = $this->permCacheKey($node, $perm); $userGrants = null; if ($key) { $userGrants = $permCache->load($key); if (count($userGrants)) { $userGrants = $this->sanitiseCacheData($userGrants); } } if ($member && $userGrants && isset($userGrants[$perm][$member->ID])) { return $userGrants[$perm][$member->ID]; } // okay, we need to build up all the info we have about the node for permissions $s = $this->realiseAllSources($node); if (!$userGrants) { $userGrants = array(); } if (!isset($userGrants[$perm])) { $userGrants[$perm] = array(); } $result = null; // if no member, just check public view $public = $this->checkPublicPerms($node, $perm); if ($public) { $result = true; } // can return immediately if (!$member) { return $result; } if (is_null($result)) { // see whether we're the owner, and if the perm we're checking is in that list if ($this->checkOwnerPerms($node, $perm, $member)) { $result = true; } } $accessAuthority = ''; $directGrant = null; $can = false; if (is_null($result)) { $filter = array('ItemID' => $node->ID, 'ItemType' => $node->class); $existing = DataList::create('AccessAuthority')->filter($filter); // get all access authorities for this object $gids = isset($this->groups[$member->ID]) ? $this->groups[$member->ID] : null; if (!$gids) { $groups = $member ? $member->Groups() : array(); $gids = array(); if ($groups && $groups->Count()) { $gids = $groups->map('ID', 'ID')->toArray(); } $this->groups[$member->ID] = $gids; } $can = false; $directGrant = 'NONE'; if ($existing && $existing->count()) { foreach ($existing as $access) { // check if this mentions the perm in question $perms = $access->Perms->getValues(); if ($perms) { if (!in_array($perm, $perms)) { continue; } } $grant = null; $authority = $access->getAuthority(); if ($authority instanceof Group) { if (isset($gids[$access->AuthorityID])) { $grant = $access->Grant; } } elseif ($authority instanceof Member) { if ($member->ID == $access->AuthorityID) { $grant = $access->Grant; } } else { // another mechanism that will require a lookup of members in a list // TODO cache this if ($authority instanceof ListOfMembers) { $listMembers = $authority->getAllMembers()->map('ID', 'Title'); if (isset($listMembers[$member->ID])) { $grant = $access->Grant; } } } if ($grant) { // if it's deny, we can just break away immediately, otherwise we need to evaluate all the // others in case there's another DENY in there somewhere if ($grant === 'DENY') { $directGrant = 'DENY'; // immediately break break; } else { // mark that it's been granted for now $directGrant = 'GRANT'; } } } } } // return immediately if we have something if ($directGrant === 'GRANT') { $result = true; } if ($directGrant === 'DENY') { $result = false; } // otherwise query our parents if (is_null($result) && $node->InheritPerms) { $permParents = $this->getEffectiveParents($node); if (count($permParents) || $permParents instanceof IteratorAggregate) { foreach ($permParents as $permParent) { if ($permParent && $this->checkPerm($permParent, $perm, $member)) { $result = true; } } } } if (is_null($result)) { $result = false; } $userGrants[$perm][$member->ID] = $result; if ($key) { $permCache->save($userGrants, $key); } return $result; }
/** * @param DataObject $rec This would normally just be a singleton but we don't want to have to create it over and over * @param string $filterField * @param mixed $filterVal * @return array - returns the new filter added */ public function processFilterField($rec, $filterField, $filterVal) { // First check for VFI fields if ($rec->hasExtension('VirtualFieldIndex') && ($spec = $rec->getVFISpec($filterField))) { if ($spec['Type'] == VirtualFieldIndex::TYPE_LIST) { // Lists have to be handled a little differently $f = $rec->getVFIFieldName($filterField) . ':PartialMatch'; if (is_array($filterVal)) { foreach ($filterVal as &$val) { $val = '|' . $val . '|'; } return array($f => $filterVal); } else { return array($f => '|' . $filterVal . '|'); } } else { // Simples are simple $filterField = $rec->getVFIFieldName($filterField); } } // Next check for regular db fields if ($rec->dbObject($filterField)) { // Is it a range value? if (preg_match('/^RANGE\\~(.+)\\~(.+)$/', $filterVal, $m)) { $filterField .= ':Between'; $filterVal = array_slice($m, 1, 2); } return array($filterField => $filterVal); } return array(); }
/** * Start a workflow based on a particular definition for a particular object. * * The object is optional; if not specified, it is assumed that this workflow * is simply a task based checklist type of workflow. * * @param WorkflowDefinition $definition * @param DataObject $for */ public function beginWorkflow(WorkflowDefinition $definition, DataObject $for = null) { if (!$this->ID) { $this->write(); } if ($for && ($for->hasExtension('WorkflowApplicable') || $for->hasExtension('FileWorkflowApplicable'))) { $this->TargetClass = ClassInfo::baseDataClass($for); $this->TargetID = $for->ID; } // lets create the first WorkflowActionInstance. $action = $definition->getInitialAction()->getInstanceForWorkflow(); $action->WorkflowID = $this->ID; $action->write(); $title = $for && $for->hasField('Title') ? sprintf(_t('WorkflowInstance.TITLE_FOR_DO', '%s - %s'), $definition->Title, $for->Title) : sprintf(_t('WorkflowInstance.TITLE_STUB', 'Instance #%s of %s'), $this->ID, $definition->Title); $this->Title = $title; $this->DefinitionID = $definition->ID; $this->CurrentActionID = $action->ID; $this->InitiatorID = Member::currentUserID(); $this->write(); $this->Users()->addMany($definition->Users()); $this->Groups()->addMany($definition->Groups()); }
/** * Get the available stages for the given DataObject. * * @param DataObject $dataObject * * @return array */ public function getDataObjectStages(DataObject $dataObject) { return $dataObject->hasExtension('Versioned')? $dataObject->getStages(): array('Stage'); }
/** * Extracts tags from an object's content where the tag is preceded by a # * * @param MicroPost $object * */ public function extractTags(DataObject $object, $field = 'Content') { if (!$object->hasExtension('TaggableExtension')) { return array(); } $content = $object->{$field}; if (preg_match_all('/#([a-z0-9_-]+)/is', $content, $matches)) { $object->tag($matches[1], true); } return $object->Tags(); }
/** * Counts as "archived" if the current record is a different version from both live and draft. * * @return boolean */ public function isArchived() { if (!$this->record->hasExtension('Versioned')) { return false; } if (!isset($this->record->_cached_isArchived)) { $baseTable = ClassInfo::baseDataClass($this->record->class); $currentDraft = Versioned::get_one_by_stage($baseTable, 'Stage', array("\"{$baseTable}\".\"ID\"" => $this->record->ID)); $currentLive = Versioned::get_one_by_stage($baseTable, 'Live', array("\"{$baseTable}\".\"ID\"" => $this->record->ID)); $this->record->_cached_isArchived = (!$currentDraft || $currentDraft && $this->record->Version != $currentDraft->Version) && (!$currentLive || $currentLive && $this->record->Version != $currentLive->Version); } return $this->record->_cached_isArchived; }
/** * this method is a bit of a hack. * if a product variation does not have any specific tax rules * but the product does, then it uses the rules from the product. * @param DataObject $buyable */ function dealWithProductVariationException($buyable) { if ($buyable instanceof ProductVariation) { if (!$buyable->hasExtension("GSTTaxDecorator")) { if ($parent = $buyable->Parent()) { if ($parent->hasExtension("GSTTaxDecorator")) { $buyable = $parent; } } } } }