/** * remove protected properties and execute @name annotation * * @param Record $record */ protected function finalizeRecord(Record $record, DataDimensions $dataDimensions) { // Apply @name annotation if ($record->getDataTypeDefinition()->hasNamingPattern()) { $record->setName(Util::applyNamingPattern($record->getProperties(), $record->getDataTypeDefinition()->getNamingPattern())); } // remove protected properties $properties = $record->getProperties(); foreach ($record->getDataTypeDefinition()->getProtectedProperties($dataDimensions->getViewName()) as $property) { unset($properties[$property]); } $record->setProperties($properties); return $record; }
/** * @param $record * * @return int * @throws Exception */ public function saveRecord($record, $viewName = 'default', $workspace = 'default', $language = 'default') { $repositoryName = $this->repository->getName(); $contentTypeName = $this->contentTypeDefinition->getName(); $tableName = $repositoryName . '$' . $contentTypeName; if ($tableName != Util::generateValidIdentifier($repositoryName) . '$' . Util::generateValidIdentifier($contentTypeName)) { throw new RepositoryException('Invalid repository and/or content type name(s).', RepositoryException::REPOSITORY_INVALID_NAMES); } if ($language != 'default' and $this->contentTypeDefinition->hasLanguages()) { if (!array_key_exists($language, $this->contentTypeDefinition->getLanguages())) { throw new RepositoryException('Trying to store record, but invalid language ' . $language . ' has been provided', RepositoryException::REPOSITORY_INVALID_LANGUAGE); } } if ($workspace != 'default' and $this->contentTypeDefinition->hasWorkspaces()) { if (!array_key_exists($workspace, $this->contentTypeDefinition->getWorkspaces())) { throw new RepositoryException('Trying to store record, but invalid workspace ' . $language . ' has been provided', RepositoryException::REPOSITORY_INVALID_WORKSPACE); } } // Apply @name annotation if ($this->contentTypeDefinition->hasNamingPattern()) { $record['properties']['name'] = Util::applyNamingPattern($record['properties'], $this->contentTypeDefinition->getNamingPattern()); } // remove protected properties foreach ($this->contentTypeDefinition->getProtectedProperties($viewName) as $property) { unset($record['properties'][$property]); } $possibleProperties = $this->contentTypeDefinition->getProperties($viewName); $notallowed = array_diff(array_keys($record['properties']), $possibleProperties); if (count($notallowed) != 0) { throw new RepositoryException('Trying to store undefined properties: ' . join(',', $notallowed) . '.', RepositoryException::REPOSITORY_INVALID_PROPERTIES); } $mandatoryProperties = $this->contentTypeDefinition->getMandatoryProperties($viewName); $missing = array(); foreach ($mandatoryProperties as $property) { if (array_key_exists($property, $record['properties'])) { if ($record['properties'][$property] == '') { $missing[] = $property; } } else { $missing[] = $property; } } if (count($missing) != 0) { throw new RepositoryException('Trying to store record, but missing mandatory properties: ' . join(',', $missing) . '.', RepositoryException::REPOSITORY_MISSING_MANDATORY_PROPERTIES); } $dbh = $this->repository->getDatabaseConnection(); $mode = 'insert'; $record['revision'] = 1; // fix record array structure, if someone forgot the id if (!isset($record['id'])) { $record['id'] = 0; } if ($record['id'] != 0) { try { $row = self::getRecordTableRow($record['id'], $workspace, $language); $mode = 'update'; // transfer all properties, which are not set in the record to be saved foreach ($row as $key => $value) { if (Helper::startsWith($key, 'property_')) { $property = substr($key, 9); if (!array_key_exists($property, $record['properties'])) { $record['properties'][$property] = $value; } } } $mode = 'update'; $record['revision'] = $row['revision'] + 1; } catch (RepositoryException $e) { } } if ($mode == 'insert' and $record['id'] == 0) { // update counter for new record $sql = 'INSERT INTO _counter_ (repository,content_type,counter) VALUES (? , ? ,1) ON DUPLICATE KEY UPDATE counter=counter+1;'; $params = array(); $params[] = $repositoryName; $params[] = $contentTypeName; $stmt = $dbh->prepare($sql); $stmt->execute($params); $sql = 'SELECT counter FROM _counter_ WHERE repository = ? AND content_type = ?'; $stmt = $dbh->prepare($sql); $stmt->execute($params); $result = $stmt->fetchColumn(0); $record['id'] = $result; // make sure counter is always at least greater than the largest id, e.g. if the counter row got deleted $sql = 'SELECT MAX(id)+1 FROM ' . $tableName; $stmt = $dbh->prepare($sql); $stmt->execute($params); $result = $stmt->fetchColumn(0); if ($result > $record['id']) { $record['id'] = $result; $sql = 'INSERT INTO _counter_ (repository,content_type,counter) VALUES (? , ? ,?) ON DUPLICATE KEY UPDATE counter=?;'; $params = array(); $params[] = $repositoryName; $params[] = $contentTypeName; $params[] = $result; $params[] = $result; $stmt = $dbh->prepare($sql); $stmt->execute($params); } } $timestamp = time(); $timeshiftTimestamp = $this->repository->getTimeshiftTimestamp(); if ($mode == 'update') { // invalidate current revision $sql = 'UPDATE ' . $tableName . ' SET validuntil_timestamp = ? WHERE id = ? AND workspace = ? AND language = ? AND deleted = 0 AND validfrom_timestamp <=? AND validuntil_timestamp >?'; $params = array(); $params[] = $timeshiftTimestamp; $params[] = $record['id']; $params[] = $workspace; $params[] = $language; $params[] = $timeshiftTimestamp; $params[] = $timeshiftTimestamp; $stmt = $dbh->prepare($sql); $stmt->execute($params); } $values = array(); $values['id'] = $record['id']; $values['hash'] = md5(serialize($record['properties'])); $values['workspace'] = $workspace; $values['language'] = $language; $values['revision'] = $record['revision']; $values['deleted'] = 0; if ($mode == 'insert') { $values['creation_timestamp'] = $timestamp; $values['creation_apiuser'] = $this->repository->getAPIUser(); $values['creation_clientip'] = $this->repository->getClientIp(); $values['creation_username'] = $this->repository->getCurrentUserName(); $values['creation_firstname'] = $this->repository->getCurrentUserFirstname(); $values['creation_lastname'] = $this->repository->getCurrentUserLastname(); } else { $values['creation_timestamp'] = $row['creation_timestamp']; $values['creation_apiuser'] = $row['creation_apiuser']; $values['creation_clientip'] = $row['creation_clientip']; $values['creation_username'] = $row['creation_username']; $values['creation_firstname'] = $row['creation_firstname']; $values['creation_lastname'] = $row['creation_lastname']; } $values['lastchange_timestamp'] = $timestamp; $values['lastchange_apiuser'] = $this->repository->getAPIUser(); $values['lastchange_clientip'] = $this->repository->getClientIp(); $values['lastchange_username'] = $this->repository->getCurrentUserName(); $values['lastchange_firstname'] = $this->repository->getCurrentUserFirstname(); $values['lastchange_lastname'] = $this->repository->getCurrentUserLastname(); $values['validfrom_timestamp'] = $timeshiftTimestamp; $values['validuntil_timestamp'] = $this->repository->getMaxTimestamp(); foreach ($record['properties'] as $property => $value) { $property = Util::generateValidIdentifier($property); $values['property_' . $property] = $value; } if ($mode == 'update') { $values['parent_id'] = $row['parent_id']; $values['position'] = $row['position']; $values['position_left'] = $row['position_left']; $values['position_right'] = $row['position_right']; $values['position_level'] = $row['position_level']; } if ($mode == 'insert') { $event = new ContentRecordEvent($this->contentTypeDefinition, $values); $this->app['dispatcher']->dispatch('content.record.before.insert', $event); $values = $event->getValues(); } else { $event = new ContentRecordEvent($this->contentTypeDefinition, $values, $row); $this->app['dispatcher']->dispatch('content.record.before.update', $event); $values = $event->getValues(); } $sql = 'INSERT INTO ' . $tableName; $sql .= ' (' . join(',', array_keys($values)) . ')'; $sql .= ' VALUES ( ?'; $sql .= str_repeat(' , ?', count($values) - 1); $sql .= ')'; $stmt = $dbh->prepare($sql); $stmt->execute(array_values($values)); if ($mode == 'insert') { $event = new ContentRecordEvent($this->contentTypeDefinition, $values); $this->app['dispatcher']->dispatch('content.record.after.insert', $event); } else { $event = new ContentRecordEvent($this->contentTypeDefinition, $values, $row); $this->app['dispatcher']->dispatch('content.record.after.update', $event); } if ($this->contentTypeDefinition->hasSynchronizedProperties() && $this->currentlySynchronizingProperties === false) { $this->synchronizeProperties($record, $viewName, $workspace, $language); } return $record['id']; }