/** * Create * * $ref may be nullRef, then auto increment is used. */ protected function create(Reference $ref, $properties) { // filter out unknown keys $properties = array_intersect_key($properties, $this->properties); if (!$ref->isNullRef()) { $properties = array_merge($properties, array_combine($this->describeId(), (array) $ref->id)); } // Set times if ($this->time_created_table_column) { $properties[$this->time_created_table_column] = new \Smalldb\Flupdo\FlupdoRawSql('CURRENT_TIMESTAMP'); } if ($this->time_modified_table_column) { $properties[$this->time_modified_table_column] = new \Smalldb\Flupdo\FlupdoRawSql('CURRENT_TIMESTAMP'); } if (empty($properties)) { throw new \InvalidArgumentException('No valid properties provided.'); } // Set owner if ($this->user_id_table_column) { $properties[$this->user_id_table_column] = $this->backend->getAuth()->getUserId(); } // Check permission of owning machine if ($this->owner_relation && $this->owner_create_transition) { $ref_ref = $this->resolveMachineReference($this->owner_relation, $properties); if (!$ref_ref->machine->isTransitionAllowed($ref_ref, $this->owner_create_transition)) { throw new \RuntimeException(sprintf('Permission denied to create machine %s because transition %s of %s is not allowed.', $this->machine_type, $this->owner_create_transition, $ref->machine_type)); } } // Insert $data = $this->encodeProperties($properties); $q = $this->flupdo->insert()->into($this->flupdo->quoteIdent($this->table)); foreach ($data as $k => $v) { $q->insert($this->flupdo->quoteIdent($k)); } $q->values([$data]); $n = $q->debugDump()->exec(); if (!$n) { // Insert failed return false; } // Return ID of inserted row if ($ref->isNullRef()) { $id_keys = $this->describeId(); $id = array(); foreach ($id_keys as $k) { if (isset($properties[$k])) { $id[] = $properties[$k]; } else { // If part of ID is missing, it must be autoincremented // column, otherwise the insert would have failed. $id[] = $this->flupdo->lastInsertId(); } } } else { $id = $ref->id; } if ($this->nested_sets_enabled) { $this->recalculateTree(); } return $id; }
/** * Returns true if user has required access_policy. * * TODO: Caching ? Reference object has property cache. It would be * nice to pass it here. */ protected function checkAccessPolicy($access_policy_name, Reference $ref) { // Allow by default if (empty($access_policy_name)) { return true; } if (!isset($this->access_policies[$access_policy_name])) { throw new \InvalidArgumentException('Unknown policy: ' . $access_policy_name); } $access_policy = $this->access_policies[$access_policy_name]; //debug_dump($access_policy, 'POLICY: '.$access_policy_name.' @ '.get_class($this)); if ($this->auth->isAllMighty()) { return true; } switch ($access_policy['type']) { // anyone: Completely open for anyone case 'anyone': return true; // nobody: Nobody is allowed, except all mighty users. // nobody: Nobody is allowed, except all mighty users. case 'nobody': return false; // anonymous: Only anonymous users allowed (not logged in) // anonymous: Only anonymous users allowed (not logged in) case 'anonymous': $user_id = $this->auth->getUserId(); return $user_id === null; // user: All logged-in users allowed // user: All logged-in users allowed case 'user': $user_id = $this->auth->getUserId(); return $user_id !== null; // owner: Owner must match current user // owner: Owner must match current user case 'owner': if ($ref->isNullRef()) { // Everyone owns nothing :) return true; } $properties = $ref->properties; $user_id = $this->auth->getUserId(); $owner_property = $access_policy['owner_property']; if (isset($access_policy['session_state'])) { if ($this->auth->getSessionMachine()->state != $access_policy['session_state']) { return false; } } return $user_id !== null ? $user_id == $properties[$owner_property] : $properties[$owner_property] === null; // role: Current user must have specified role ($ref is ignored) // role: Current user must have specified role ($ref is ignored) case 'role': return $this->auth->hasUserRoles($access_policy['required_role']); // These are done by SQL select. // These are done by SQL select. case 'condition': if ($ref->isNullRef()) { // Nonexistent entity has nulls everywhere // FIXME: Are we sure? return false; } $properties = $ref->properties; return !empty($properties['_access_policy_' . $access_policy_name]); // These are done by SQL select. // These are done by SQL select. case 'user_relation': if ($ref->isNullRef()) { // No relation to nonexistent entity. return false; } $properties = $ref->properties; return !empty($properties['_access_policy_' . $access_policy_name]); // unknown policies are considered unsafe // unknown policies are considered unsafe default: return false; } // This should not happen. throw new \RuntimeException('Policy ' . $policy . ' did not decide.'); }