$options is a array which can contain following options. All options are optional.
'fields' Limit the columns selection. Use a array or a comma separated list (like in SQL SELECT)
If empty all columns will be selected.
'offset' Offset of the result set (in SQL OFFSET)
'limit' Limits the result set (in SQL LIMIT)
'order' The column to order. Example:
array(
array('field' => 'category', 'direction' => 'asc'),
array('field' => 'title', 'direction' => 'asc')
)
'foreignKeys' Define which column should be resolved. If empty all columns will be resolved.
Use a array or a comma separated list (like in SQL SELECT)
'permissionCheck' Defines whether we check against the ACL or not. true or false. default false
/** * {@inheritdoc} */ public function getParents($pk, $options = null) { $query = $this->getQueryClass(); $item = $query->findPK($this->getPropelPk($pk)); if (!$item) { throw new \Exception('Can not found entry. ' . var_export($pk, true)); } if (!$item->getRgt()) { throw new \Exception('Entry it not in a tree. ' . var_export($pk, true)); } list($fields, $relations, $relationFields) = $this->getFields(@$options['fields']); $selects = array_keys($fields); $selects[] = 'Lft'; $selects[] = 'Rgt'; // $selects[] = 'Title'; $query->select($selects); $this->mapOptions($query, $options); $this->mapToOneRelationFields($query, $relations, $relationFields); $query->ancestorsOf($item); $query->orderByLevel(); $stmt = $this->getStm($query); $clazz = $this->getPhpName(); $result = array(); if ($this->definition['nestedRootAsObject']) { //fetch root object entry $scopeField = 'get' . ucfirst($this->definition['nestedRootObjectField']); $scopeId = $item->{$scopeField}(); $root = $this->objects->get($this->definition['nestedRootObject'], $scopeId); $root['_object'] = $this->definition['nestedRootObject']; $result[] = $root; } $item = false; while ($row = $stmt->fetch(\PDO::FETCH_ASSOC)) { //propels nested set requires a own root item, we do not return this if (false === $item) { $item = true; continue; } $item = $this->populateRow($clazz, $row, $selects, $relations, $relationFields, $options['permissionCheck']); $result[] = $item; } return $result; }
/** * @param Objects $repo * @param $objectKey * @param $origItem * @return string */ protected function generateDiff(Objects $repo, $objectKey, $origItem) { $pk = $repo->getObjectPk($objectKey, $origItem); $currentItem = $repo->get($objectKey, $pk); $definition = $repo->getDefinition($objectKey); $changes = []; foreach ($definition->getFields() as $field) { if ($field->hasFieldType() && !$field->getFieldType()->isDiffAllowed()) { //todo, check $field->isDiffAllowed() as well continue; } $k = $field->getId(); if (!isset($origItem[$k]) || !isset($currentItem[$k])) { continue; } if (!is_string($origItem[$k]) && !is_numeric($origItem[$k])) { continue; } if (!is_string($currentItem[$k]) && !is_numeric($currentItem[$k])) { continue; } $from = strip_tags($origItem[$k]); $to = strip_tags($currentItem[$k]); if ($from != $to) { $htmlDiff = new HtmlDiff($from, $to, true); $out = $htmlDiff->outputDiff(); $changes[$k] = $out->toString(); } } $message = []; foreach ($changes as $changedKey => $diff) { if ($field = $definition->getField($changedKey)) { $message[] = ($field->getLabel() ?: $field->getId()) . ': ' . $diff; } } return $message ? '<div class="change">' . implode('</div><div class="change">', $message) . '</div>' : ''; }
/** * @param ACLRequest $aclRequest * * @return bool */ public function check(ACLRequest $aclRequest) { $objectKey = Objects::normalizeObjectKey($aclRequest->getObjectKey()); $targetType = $aclRequest->getTargetType(); $targetId = $aclRequest->getTargetId(); $pk = $aclRequest->getPrimaryKey(); $field = $aclRequest->getField(); $pk = $this->objects->normalizePkString($objectKey, $pk); if (ACL::TARGET_TYPE_USER === $targetType && null === $targetId) { //0 means guest $targetId = $this->pageStack->getUser() ? $this->pageStack->getUser()->getId() : 0; } $user = $this->pageStack->getUser(); if ($user) { $groupIds = $user->getGroupIds(); if (false !== strpos(',' . $groupIds . ',', ',1,')) { //user is in the admin group, so he has always access. return true; } } if (ACL::TARGET_TYPE_USER === $targetType && 1 === $targetId) { //user admin has always access return true; } if (ACL::TARGET_TYPE_GROUP === $targetType && 1 === $targetId) { //group admin has always access return true; } if (0 === $targetId) { //guests do always have no access return false; } if (ACL::TARGET_TYPE_GROUP === $targetType && !$targetId) { throw new \InvalidArgumentException('For type TARGET_TYPE_GROUP a targetId is required.'); } $cacheKey = null; if ($pk && $this->getCaching()) { $pkString = $this->objects->getObjectUrlId($objectKey, $pk); $cacheKey = md5($targetType . '.' . $targetId . '.' . $objectKey . '/' . $pkString . '/' . json_encode($field)); $cached = $this->cacher->getDistributedCache('core/acl/' . $cacheKey); if (null !== $cached) { return $cached; } } $rules = self::getRules($objectKey, $aclRequest->getMode(), $targetType, $targetId); if (count($rules) === 0) { //no rules found, so we have no access return false; } $access = null; $currentObjectPk = $pk; $definition = $this->objects->getDefinition($objectKey); $not_found = true; //starts directly as if we were in the parent checking. $parent_acl = $aclRequest->isAsParent(); $fCount = null; $fKey = null; $fValue = null; $fIsArray = is_array($field); if ($fIsArray) { $fCount = count($field); $fKey = key($field); $fValue = current($field); if (is_int($fKey)) { $fKey = $fValue; $fValue = null; } } $depth = 0; $match = false; $originObjectItemPk = $currentObjectPk; while ($not_found) { $currentObjectPkString = null; if ($currentObjectPk) { $currentObjectPkString = $this->objects->getObjectUrlId($objectKey, $currentObjectPk); } $depth++; if ($depth > 50) { $not_found = false; break; } foreach ($rules as $aclRule) { if ($parent_acl && !$aclRule['sub']) { //as soon we enter the parent_acl mode we only take acl rules into consideration //that are also valid for children (sub=true) continue; } $match = false; /* * CUSTOM CONSTRAINT */ if ($aclRule['constraint_type'] === ACL::CONSTRAINT_CONDITION) { $objectItem = null; if ($originObjectItemPk === $currentObjectPk && null !== $aclRequest->getPrimaryObjectItem()) { $objectItem = $aclRequest->getPrimaryObjectItem(); } else { if ($originObjectItemPk) { $objectItem = $this->objects->get($objectKey, $currentObjectPk); } } if ($objectItem && $this->conditionOperator->satisfy($aclRule['constraint_code'], $objectItem, $objectKey)) { $match = true; } /* * EXACT */ } else { if ($aclRule['constraint_type'] === ACL::CONSTRAINT_EXACT) { if ($currentObjectPk && $aclRule['constraint_code'] === $currentObjectPkString) { $match = true; } /** * ALL */ } else { $match = true; } } if (!$match && $aclRule['sub'] && $currentObjectPk) { // we need to check if a parent matches this $acl as we have sub=true $parentItem = $this->objects->normalizePkString($objectKey, $currentObjectPk); $parentCondition = Condition::create($aclRule['constraint_code']); $parentOptions['fields'] = $this->conditionOperator->extractFields($parentCondition); while ($parentItem = $this->objects->getParent($objectKey, $this->objects->getObjectPk($objectKey, $parentItem), $parentOptions)) { if ($aclRule['constraint_type'] === ACL::CONSTRAINT_CONDITION && $this->conditionOperator->satisfy($parentCondition, $parentItem)) { $match = true; break; } else { if ($aclRule['constraint_type'] === ACL::CONSTRAINT_EXACT && $aclRule['constraint_code'] === $this->objects->getObjectUrlId($objectKey, $parentItem)) { $match = true; break; } } } } if ($match) { //match, check all $field $field2Key = $field; if ($field) { if ($fIsArray && $fCount === 1) { if (is_string($fKey) && is_array($aclRule['fields'][$fKey])) { //this field has limits if (($field2Acl = $aclRule['fields'][$fKey]) !== null) { if (is_array($field2Acl[0])) { //complex field rule, $field2Acl = ([{access: no, condition: [['id', '>', 2], ..]}, {}, ..]) foreach ($field2Acl as $fRule) { $satisfy = false; if (($f = $definition->getField($fKey)) && $f->getType() === 'object') { $uri = $f->getObject() . '/' . $fValue; $uriObject = $this->objects->getFromUrl($uri); $satisfy = $this->conditionOperator->satisfy($fRule['condition'], $uriObject); } else { if (null !== $fValue) { $satisfy = $this->conditionOperator->satisfy($fRule['condition'], $field); } } if ($satisfy) { return $fRule['access'] === 1 ? true : false; } } //if no field rules fits, we consider the whole rule if ($aclRule['access'] !== 2) { return $aclRule['access'] === 1 ? true : false; } } else { //simple field rule $field2Acl = ({"value1": yes, "value2": no} if ($field2Acl[$fKey] !== null) { return $field2Acl[$fKey] === 1 ? true : false; } else { //current($field) is not exactly defined in $field2Acl, so we set $access to $acl['access'] // //if access = 2 then wo do not know it, cause 2 means 'inherited', so maybe //a other rule has more detailed rule if ($aclRule['access'] !== 2) { $access = $aclRule['access'] === 1 ? true : false; break; } } } } } else { //this field has only true or false $field2Key = $fKey; } } if (!is_array($field2Key)) { if ($aclRule['fields'] && ($field2Acl = $aclRule['fields'][$field2Key]) !== null && !is_array($aclRule['fields'][$field2Key])) { $access = $field2Acl === 1 ? true : false; break; } else { //$field is not exactly defined, so we set $access to $acl['access'] //and maybe a rule with the same code has the field defined // if access = 2 then this rule is only for exactly define fields if ($aclRule['access'] !== 2) { $access = $aclRule['access'] === 1 ? true : false; break; } } } } else { $access = $aclRule['access'] === 1 ? true : false; break; } } } //foreach if (null === $access && $definition->isNested() && $pk) { //$access has not defined yet (no rule matched yet). Check if nested and $pk is given //load its root and check again if (null === ($currentObjectPk = $this->objects->getParentPk($objectKey, $currentObjectPk))) { $access = $aclRequest->isRootHasAccess() ? true : $access; break; } $parent_acl = true; } else { break; } } $access = (bool) $access; if ($pk && $this->getCaching()) { $this->cacher->setDistributedCache('core/acl/' . $cacheKey, $access); } return $access; }
public function getRoot($scope = null) { if ($this->getObjectDefinition()->getNestedRootAsObject() && $scope === null) { throw new \Exception('No `scope` defined.'); } $options['fields'] = $this->getNestedSelection($this->getObjectDefinition()->getNestedRootObjectLabelField()); return $this->objects->get($this->getObjectDefinition()->getNestedRootObject(), $scope, $options); }