mirror of
https://github.com/avecms/AVE.cms.git
synced 2026-08-01 08:45:44 +00:00
411 lines
23 KiB
PHP
411 lines
23 KiB
PHP
<?php
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------------------
|
|
| AVE.cms
|
|
|--------------------------------------------------------------------------------------
|
|
| @package AVE.cms
|
|
| @file system/App/Content/Documents/DocumentMutationService.php
|
|
| @author AVE.cms <support@ave-cms.ru>
|
|
| @copyright 2007-2026 (c) AVE.cms
|
|
| @link https://ave-cms.ru
|
|
| @version 3.3
|
|
*/
|
|
|
|
namespace App\Content\Documents;
|
|
|
|
defined('BASEPATH') || die('Direct access to this location is not allowed.');
|
|
|
|
use App\Content\ContentTables;
|
|
use App\Content\DocumentTerms;
|
|
use App\Content\Fields\FieldContext;
|
|
use App\Content\Fields\FieldConditionEvaluator;
|
|
use App\Content\Fields\FieldLifecycle;
|
|
use App\Content\Fields\FieldRegistry;
|
|
use App\Content\Fields\FieldValidator;
|
|
use App\Content\Fields\FieldValueCodec;
|
|
use App\Common\DatabaseSchema;
|
|
use App\Helpers\Str;
|
|
use DB;
|
|
|
|
/** Transactional native writer used by the JSON API. */
|
|
class DocumentMutationService
|
|
{
|
|
public function save($documentId, array $payload, $actorId, $source = 'api')
|
|
{
|
|
$documentId = (int) $documentId;
|
|
$existing = $documentId > 0 ? $this->document($documentId) : null;
|
|
if ($documentId > 0 && !$existing) { throw new DocumentSaveRejected('Документ не найден'); }
|
|
$operation = $existing ? 'update' : 'create';
|
|
$rubricId = $existing ? (int) $existing['rubric_id'] : (int) $this->pick($payload, array('rubric_id'), 0);
|
|
$rubric = $this->rubric($rubricId);
|
|
if (!$rubric) { throw new DocumentSaveRejected('Рубрика не найдена', array('rubric_id' => 'Выберите существующую рубрику')); }
|
|
if ($existing && isset($payload['rubric_id']) && (int) $payload['rubric_id'] !== $rubricId) {
|
|
throw new DocumentSaveRejected('Рубрику существующего документа менять нельзя', array('rubric_id' => 'Создайте новый документ в другой рубрике'));
|
|
}
|
|
|
|
$definitions = $this->fieldDefinitions($rubricId);
|
|
$fields = $this->fieldValues($documentId, $definitions, !$existing);
|
|
$storedFields = $fields;
|
|
$incomingFields = isset($payload['fields']) && is_array($payload['fields']) ? $payload['fields'] : array();
|
|
$actionOverrides = $this->conditionActionOverrides($incomingFields, $definitions);
|
|
$fieldErrors = $this->applyIncomingFields($incomingFields, $definitions, $fields);
|
|
$conditionsEnabled = !empty($rubric['rubric_form_conditions']);
|
|
$actions = $conditionsEnabled
|
|
? FieldConditionEvaluator::valueActions(array_values($definitions), $storedFields, $fields, !$existing)
|
|
: array();
|
|
foreach ($actionOverrides as $fieldId => $override) { unset($actions[$fieldId]); }
|
|
foreach ($actions as $fieldId => $action) {
|
|
$fields[$fieldId] = isset($action['action']) && (string) $action['action'] === 'set'
|
|
? (string) (isset($action['value']) ? $action['value'] : '')
|
|
: '';
|
|
}
|
|
|
|
$states = $conditionsEnabled ? FieldConditionEvaluator::states(array_values($definitions), $fields) : array();
|
|
foreach ($states as $fieldId => $state) {
|
|
if ((empty($state['visible']) || !empty($state['locked'])) && !isset($actions[$fieldId])) {
|
|
$fields[$fieldId] = isset($storedFields[$fieldId]) ? $storedFields[$fieldId] : '';
|
|
}
|
|
}
|
|
|
|
$data = $this->normalizeData($payload, $existing, $rubric);
|
|
DocumentSaveEvents::before($operation, $source, $documentId, $rubricId, $actorId, $data, $fields, $existing ?: array());
|
|
DocumentRubricCodeRunner::before($rubricId, $data, $fields, $documentId, $actorId, !$existing, $source);
|
|
$data = $this->normalizeData($data, $existing, $rubric, true);
|
|
$errors = array_merge(
|
|
$fieldErrors,
|
|
$this->validate($data, $documentId, $rubricId),
|
|
FieldValidator::validateValues(array_values($definitions), $fields, $conditionsEnabled)
|
|
);
|
|
if (!empty($errors)) { throw new DocumentSaveRejected('Проверьте данные документа', $errors); }
|
|
|
|
$previousDatabaseExceptionMode = DB::$throw_exception_on_error;
|
|
DB::$throw_exception_on_error = true;
|
|
$externalTransaction = DB::$transaction_in_progress;
|
|
$ownsTransaction = !$externalTransaction;
|
|
if ($ownsTransaction) { DB::startTransaction(); }
|
|
try {
|
|
if ($existing) { $this->captureRevision($documentId, $actorId); }
|
|
$documentId = $this->writeDocument($documentId, $data, $rubric, $actorId, $existing);
|
|
$identityState = $this->document($documentId);
|
|
DocumentRubricCodeRunner::after($rubricId, $data, $fields, $documentId, $actorId, !$existing, $source);
|
|
$data = $this->normalizeData($data, $this->document($documentId), $rubric, true);
|
|
$this->writeDocument($documentId, $data, $rubric, $actorId, $identityState ?: array(), false);
|
|
$this->writeFields($documentId, $data, $definitions, $fields);
|
|
DocumentTerms::sync($documentId, $rubricId, $data['document_meta_keywords'], $data['document_tags']);
|
|
if ($ownsTransaction) { DB::commit(); }
|
|
} catch (\Throwable $e) {
|
|
if ($ownsTransaction) { DB::rollback(); }
|
|
throw $e;
|
|
} finally {
|
|
DB::$throw_exception_on_error = $previousDatabaseExceptionMode;
|
|
}
|
|
|
|
$snapshot = array();
|
|
if ($externalTransaction) {
|
|
DB::afterCommit(function () use ($operation, $source, $documentId, $rubricId, $actorId, $data, $fields, $existing) {
|
|
ContentCacheInvalidator::document($documentId, true);
|
|
$savedSnapshot = (new DocumentSnapshotRepository())->find($documentId);
|
|
$savedSnapshot = is_array($savedSnapshot) ? $savedSnapshot : array();
|
|
DocumentSaveEvents::after($operation, $source, $documentId, $rubricId, $actorId, $data, $fields, $existing ?: array(), $savedSnapshot);
|
|
});
|
|
} else {
|
|
ContentCacheInvalidator::document($documentId, true);
|
|
$snapshot = (new DocumentSnapshotRepository())->find($documentId);
|
|
$snapshot = is_array($snapshot) ? $snapshot : array();
|
|
DocumentSaveEvents::after($operation, $source, $documentId, $rubricId, $actorId, $data, $fields, $existing ?: array(), $snapshot);
|
|
}
|
|
|
|
return array(
|
|
'id' => $documentId,
|
|
'operation' => $operation,
|
|
'document_version' => (int) DB::query('SELECT document_version FROM ' . ContentTables::table('documents') . ' WHERE Id=%i', $documentId)->getValue(),
|
|
'snapshot' => $snapshot,
|
|
'snapshot_warning' => ContentCacheInvalidator::consumeError($documentId),
|
|
);
|
|
}
|
|
|
|
/** Permanently remove a package-owned document and all core-owned derivatives. */
|
|
public function hardDelete($documentId, $source = 'content_package')
|
|
{
|
|
$documentId = (int) $documentId;
|
|
if ($documentId <= 2) {
|
|
throw new \RuntimeException('Системные документы #1 и #2 удалять нельзя');
|
|
}
|
|
|
|
$document = DB::query('SELECT * FROM ' . ContentTables::table('documents') . ' WHERE Id = %i LIMIT 1', $documentId)->getAssoc();
|
|
if (!$document) {
|
|
return false;
|
|
}
|
|
|
|
$event = \App\Common\Lifecycle::event('content.document.deleting', 'document', 'deleting', $documentId, array(
|
|
'document' => $document,
|
|
'source' => (string) $source,
|
|
), null, array('hard_delete' => true), (string) $source);
|
|
if ($event->cancelled()) {
|
|
throw new \RuntimeException($event->message() !== '' ? $event->message() : 'Удаление документа отменено модулем');
|
|
}
|
|
|
|
$ownsTransaction = !DB::$transaction_in_progress;
|
|
if ($ownsTransaction) { DB::startTransaction(); }
|
|
try {
|
|
foreach (array(
|
|
'document_fields_text' => 'document_id',
|
|
'document_fields' => 'document_id',
|
|
'document_rev' => 'doc_id',
|
|
'document_alias_history' => 'document_id',
|
|
'document_keywords' => 'document_id',
|
|
'document_tags' => 'document_id',
|
|
'document_remarks' => 'document_id',
|
|
'view_count' => 'document_id',
|
|
) as $suffix => $column) {
|
|
DB::Delete(ContentTables::table($suffix), $column . ' = %i', $documentId);
|
|
}
|
|
|
|
DB::Delete(ContentTables::table('documents'), 'Id = %i', $documentId);
|
|
\App\Content\Fields\DocumentRelationIndex::removeDocument($documentId);
|
|
if ($ownsTransaction) { DB::commit(); }
|
|
} catch (\Throwable $e) {
|
|
if ($ownsTransaction) { DB::rollback(); }
|
|
throw $e;
|
|
}
|
|
|
|
ContentCacheInvalidator::document($documentId, false);
|
|
\App\Common\Lifecycle::event(
|
|
'content.document.deleted',
|
|
'document',
|
|
'deleted',
|
|
$documentId,
|
|
array('source' => (string) $source),
|
|
true,
|
|
array('hard_delete' => true),
|
|
(string) $source
|
|
);
|
|
return true;
|
|
}
|
|
|
|
public function export(array $snapshot)
|
|
{
|
|
$fields = array();
|
|
foreach (isset($snapshot['fields']) && is_array($snapshot['fields']) ? $snapshot['fields'] : array() as $id => $field) {
|
|
$alias = isset($field['alias']) && trim((string) $field['alias']) !== '' ? (string) $field['alias'] : (string) $id;
|
|
$fields[$alias] = array('id' => (int) $id, 'type' => isset($field['type']) ? (string) $field['type'] : '', 'value' => isset($field['value']) ? $field['value'] : null);
|
|
if (isset($field['relation']) && is_array($field['relation'])) { $fields[$alias]['relation'] = $field['relation']; }
|
|
}
|
|
|
|
return array(
|
|
'format' => 'ave.document-api', 'version' => 1,
|
|
'document' => isset($snapshot['document']) ? $snapshot['document'] : array(),
|
|
'fields' => $fields,
|
|
'revision' => isset($snapshot['document_revision']) ? (int) $snapshot['document_revision'] : 0,
|
|
'generated_at' => isset($snapshot['generated_at']) ? (int) $snapshot['generated_at'] : time(),
|
|
);
|
|
}
|
|
|
|
protected function document($id)
|
|
{
|
|
return DB::query("SELECT * FROM " . ContentTables::table('documents') . " WHERE Id=%i AND document_deleted='0' LIMIT 1", (int) $id)->getAssoc() ?: null;
|
|
}
|
|
|
|
protected function rubric($id)
|
|
{
|
|
return (int) $id > 0 ? (DB::query('SELECT * FROM ' . ContentTables::table('rubrics') . ' WHERE Id=%i LIMIT 1', (int) $id)->getAssoc() ?: null) : null;
|
|
}
|
|
|
|
protected function fieldDefinitions($rubricId)
|
|
{
|
|
$fieldsTable = ContentTables::table('rubric_fields');
|
|
$groupsTable = ContentTables::table('rubric_fields_group');
|
|
static $hasGroupSettings = null;
|
|
if ($hasGroupSettings === null) {
|
|
$hasGroupSettings = DatabaseSchema::columnExists($groupsTable, 'group_settings');
|
|
}
|
|
|
|
$groupSettings = $hasGroupSettings ? 'g.group_settings' : 'NULL AS group_settings';
|
|
$rows = DB::query(
|
|
'SELECT f.*, ' . $groupSettings . ' FROM ' . $fieldsTable . ' f'
|
|
. ' LEFT JOIN ' . $groupsTable . ' g ON g.Id=f.rubric_field_group'
|
|
. ' WHERE f.rubric_id=%i ORDER BY f.rubric_field_position,f.Id',
|
|
(int) $rubricId
|
|
)->getAll();
|
|
$out = array();
|
|
foreach ($rows ?: array() as $row) { $out[(int) $row['Id']] = $row; }
|
|
return $out;
|
|
}
|
|
|
|
protected function fieldValues($documentId, array $definitions, $defaults)
|
|
{
|
|
$values = array();
|
|
foreach ($definitions as $id => $field) { $values[$id] = $defaults ? (string) $field['rubric_field_default'] : ''; }
|
|
if ((int) $documentId <= 0) { return $values; }
|
|
$rows = DB::query('SELECT df.rubric_field_id,df.field_value,COALESCE(dft.field_value,\'\') more FROM ' . ContentTables::table('document_fields') . ' df'
|
|
. ' LEFT JOIN ' . ContentTables::table('document_fields_text') . ' dft ON dft.document_id=df.document_id AND dft.rubric_field_id=df.rubric_field_id'
|
|
. ' WHERE df.document_id=%i', (int) $documentId)->getAll();
|
|
foreach ($rows ?: array() as $row) { $values[(int) $row['rubric_field_id']] = (string) $row['field_value'] . (string) $row['more']; }
|
|
return $values;
|
|
}
|
|
|
|
protected function applyIncomingFields(array $incoming, array $definitions, array &$values)
|
|
{
|
|
$aliases = array();
|
|
foreach ($definitions as $id => $field) { if (trim((string) $field['rubric_field_alias']) !== '') { $aliases[(string) $field['rubric_field_alias']] = $id; } }
|
|
$errors = array();
|
|
foreach ($incoming as $key => $value) {
|
|
$id = ctype_digit((string) $key) ? (int) $key : (isset($aliases[(string) $key]) ? (int) $aliases[(string) $key] : 0);
|
|
if ($id <= 0 || !isset($definitions[$id])) { $errors['fields.' . $key] = 'Поле не принадлежит выбранной рубрике'; continue; }
|
|
$values[$id] = is_array($value) && array_key_exists('value', $value) ? $value['value'] : $value;
|
|
}
|
|
|
|
return $errors;
|
|
}
|
|
|
|
protected function conditionActionOverrides(array $incoming, array $definitions)
|
|
{
|
|
$aliases = array();
|
|
foreach ($definitions as $id => $field) {
|
|
$alias = trim((string) $field['rubric_field_alias']);
|
|
if ($alias !== '') { $aliases[$alias] = (int) $id; }
|
|
}
|
|
|
|
$overrides = array();
|
|
foreach ($incoming as $key => $value) {
|
|
if (!is_array($value) || (empty($value['condition_action_override']) && empty($value['_condition_action_override']))) { continue; }
|
|
$id = ctype_digit((string) $key) ? (int) $key : (isset($aliases[(string) $key]) ? (int) $aliases[(string) $key] : 0);
|
|
if ($id > 0 && isset($definitions[$id])) { $overrides[$id] = true; }
|
|
}
|
|
|
|
return $overrides;
|
|
}
|
|
|
|
protected function normalizeData(array $payload, $existing, array $rubric, $legacyInput = false)
|
|
{
|
|
$base = is_array($existing) ? $existing : array();
|
|
$value = function ($canonical, $legacy, $default = '') use ($payload, $base, $legacyInput) {
|
|
if (array_key_exists($canonical, $payload)) { return $payload[$canonical]; }
|
|
if (array_key_exists($legacy, $payload)) { return $payload[$legacy]; }
|
|
return array_key_exists($legacy, $base) ? $base[$legacy] : $default;
|
|
};
|
|
if (array_key_exists('excerpt', $payload)) {
|
|
$excerpt = $payload['excerpt'];
|
|
} elseif (array_key_exists('document_excerpt', $payload)) {
|
|
$excerpt = $payload['document_excerpt'];
|
|
} elseif (array_key_exists('teaser', $payload)) {
|
|
$excerpt = $payload['teaser'];
|
|
} elseif (array_key_exists('document_teaser', $payload)) {
|
|
$excerpt = $payload['document_teaser'];
|
|
} elseif (array_key_exists('document_excerpt', $base)) {
|
|
$excerpt = $base['document_excerpt'];
|
|
} elseif (array_key_exists('document_teaser', $base)) {
|
|
$excerpt = $base['document_teaser'];
|
|
} else {
|
|
$excerpt = '';
|
|
}
|
|
|
|
$published = $this->timestamp($value('published_at', 'document_published', time()), time());
|
|
$status = $value('status', 'document_status', 0);
|
|
if (is_string($status)) { $status = in_array(strtolower($status), array('published', 'active', '1', 'true'), true) ? 1 : 0; }
|
|
$title = trim((string) $value('title', 'document_title', ''));
|
|
$alias = DocumentAliasRegistry::normalize($value('alias', 'document_alias', ''));
|
|
if (empty($base) && ($alias === '' || strpos($alias, '/') === false)) {
|
|
$leaf = $alias !== '' ? $alias : Str::slug($title);
|
|
$alias = DocumentAliasTemplate::compose((string) $rubric['rubric_alias'], $leaf !== '' ? $leaf : 'document', $published);
|
|
}
|
|
|
|
return array(
|
|
'rubric_id' => (int) $rubric['Id'], 'rubric_tmpl_id' => (int) $value('template_id', 'rubric_tmpl_id', 0),
|
|
'document_parent' => (int) $value('parent_id', 'document_parent', 0), 'document_alias' => DocumentAliasRegistry::normalize($alias),
|
|
'document_alias_header' => in_array((int) $value('redirect_code', 'document_alias_header', 301), array(301,302,307,308), true) ? (int) $value('redirect_code', 'document_alias_header', 301) : 301,
|
|
'document_alias_history' => (string) max(0, min(2, (int) $value('alias_history', 'document_alias_history', (int) $rubric['rubric_alias_history']))),
|
|
'document_short_alias' => substr(trim((string) $value('short_alias', 'document_short_alias', '')), 0, 10),
|
|
'document_title' => $title, 'document_breadcrumb_title' => trim((string) $value('breadcrumb_title', 'document_breadcrumb_title', '')),
|
|
'document_published' => $published, 'document_expire' => $this->timestamp($value('expire_at', 'document_expire', 0), 0),
|
|
'document_author_id' => (int) $value('author_id', 'document_author_id', 1), 'document_in_search' => (string) $this->boolean($value('in_search', 'document_in_search', 1)),
|
|
'document_meta_keywords' => trim((string) $value('meta_keywords', 'document_meta_keywords', '')),
|
|
'document_meta_description' => trim((string) $value('meta_description', 'document_meta_description', '')),
|
|
'document_meta_robots' => $this->robots($value('meta_robots', 'document_meta_robots', 'index,follow')),
|
|
'document_sitemap_freq' => max(0, min(6, (int) $value('sitemap_frequency', 'document_sitemap_freq', 3))),
|
|
'document_sitemap_pr' => max(0, min(1, (float) $value('sitemap_priority', 'document_sitemap_pr', 0.5))),
|
|
'document_status' => (string) $this->boolean($status), 'document_linked_navi_id' => (int) $value('navigation_id', 'document_linked_navi_id', 0),
|
|
'document_excerpt' => trim((string) $excerpt), 'document_tags' => is_array($value('tags', 'document_tags', '')) ? implode(',', $value('tags', 'document_tags', '')) : (string) $value('tags', 'document_tags', ''),
|
|
'document_property' => (string) $value('property', 'document_property', ''), 'document_position' => (int) $value('position', 'document_position', 0),
|
|
'guid' => substr(trim((string) $value('guid', 'guid', '')), 0, 100),
|
|
);
|
|
}
|
|
|
|
protected function validate(array $data, $documentId, $rubricId)
|
|
{
|
|
$errors = array();
|
|
if ($data['document_title'] === '') { $errors['title'] = 'Укажите название документа'; }
|
|
if ($data['document_alias'] !== '' && !preg_match('/^[A-Za-z0-9_\-\.\/]+$/', $data['document_alias'])) { $errors['alias'] = 'Alias содержит недопустимые символы'; }
|
|
elseif ($data['document_alias'] !== '' && DocumentAliasRegistry::conflict($data['document_alias'], (int) $documentId)) { $errors['alias'] = 'Такой alias уже используется'; }
|
|
if ($data['document_short_alias'] !== '' && !preg_match('/^[A-Za-z0-9_\-]+$/', $data['document_short_alias'])) { $errors['short_alias'] = 'Короткий alias содержит недопустимые символы'; }
|
|
elseif ($data['document_short_alias'] !== '' && DocumentAliasRegistry::conflict($data['document_short_alias'], (int) $documentId)) { $errors['short_alias'] = 'Такой короткий alias уже используется'; }
|
|
return $errors;
|
|
}
|
|
|
|
protected function writeDocument($id, array $data, array $rubric, $actorId, $existing, $bumpVersion = true)
|
|
{
|
|
$now = time();
|
|
$row = $data;
|
|
$row['document_title'] = htmlspecialchars($data['document_title'], ENT_QUOTES);
|
|
$row['document_breadcrumb_title'] = htmlspecialchars($data['document_breadcrumb_title'], ENT_QUOTES);
|
|
$row['document_changed'] = $now;
|
|
$row['document_version'] = is_array($existing)
|
|
? max(1, isset($existing['document_version']) ? (int) $existing['document_version'] : 1) + ($bumpVersion ? 1 : 0)
|
|
: 1;
|
|
if ((int) $id > 0) {
|
|
DB::Update(ContentTables::table('documents'), $row, 'Id=%i', (int) $id);
|
|
if (is_array($existing) && !empty($existing['document_alias']) && (string) $existing['document_alias'] !== (string) $data['document_alias'] && (int) $data['document_alias_history'] > 0) {
|
|
DB::Insert(ContentTables::table('document_alias_history'), array('document_id'=>(int)$id,'document_alias'=>(string)$existing['document_alias'],'document_alias_header'=>(int)$data['document_alias_header'],'document_alias_author'=>(int)$actorId,'document_alias_changed'=>$now));
|
|
}
|
|
|
|
return (int) $id;
|
|
}
|
|
|
|
if ((int) $row['rubric_tmpl_id'] <= 0) { $row['rubric_tmpl_id'] = 0; }
|
|
if ((int) $row['document_position'] <= 0) { $row['document_position'] = (int) DB::query('SELECT COALESCE(MAX(document_position),0)+1 FROM ' . ContentTables::table('documents'))->getValue(); }
|
|
$row['document_author_id'] = (int) $actorId > 0 ? (int) $actorId : max(1, (int) $row['document_author_id']);
|
|
$row['document_deleted'] = '0'; $row['document_count_print'] = 0; $row['document_count_view'] = 0; $row['module_catalog'] = '';
|
|
DB::Insert(ContentTables::table('documents'), $row);
|
|
return (int) DB::insertId();
|
|
}
|
|
|
|
protected function writeFields($documentId, array $document, array $definitions, array $values)
|
|
{
|
|
foreach ($definitions as $id => $field) {
|
|
$value = array_key_exists($id, $values) ? $values[$id] : '';
|
|
$type = FieldRegistry::get((string) $field['rubric_field_type']);
|
|
$value = FieldLifecycle::normalizeForStorage($value, $field, $document, 'document_mutation');
|
|
$saving = FieldLifecycle::saving($value, $field, $documentId, 'document_mutation');
|
|
if ($saving->cancelled()) { continue; }
|
|
$value = $saving->result();
|
|
$first = mb_substr((string) $value, 0, 500, 'UTF-8');
|
|
$more = mb_substr((string) $value, 500, null, 'UTF-8');
|
|
$numeric = $type && $type->isNumeric() ? $this->numeric($value) : 0;
|
|
$rowId = (int) DB::query('SELECT Id FROM ' . ContentTables::table('document_fields') . ' WHERE document_id=%i AND rubric_field_id=%i LIMIT 1', (int) $documentId, (int) $id)->getValue();
|
|
$row = array('field_value'=>$first,'field_number_value'=>$numeric,'document_in_search'=>(int)$document['document_in_search'] && (int)$field['rubric_field_search'] ? '1' : '0');
|
|
if ($rowId > 0) { DB::Update(ContentTables::table('document_fields'), $row, 'Id=%i', $rowId); }
|
|
else { $row['document_id']=(int)$documentId; $row['rubric_field_id']=(int)$id; DB::Insert(ContentTables::table('document_fields'), $row); }
|
|
$textId = (int) DB::query('SELECT Id FROM ' . ContentTables::table('document_fields_text') . ' WHERE document_id=%i AND rubric_field_id=%i LIMIT 1', (int)$documentId, (int)$id)->getValue();
|
|
if ($more !== '') { if ($textId > 0) { DB::Update(ContentTables::table('document_fields_text'), array('field_value'=>$more), 'Id=%i', $textId); } else { DB::Insert(ContentTables::table('document_fields_text'), array('document_id'=>(int)$documentId,'rubric_field_id'=>(int)$id,'field_value'=>$more)); } }
|
|
elseif ($textId > 0) { DB::Delete(ContentTables::table('document_fields_text'), 'Id=%i', $textId); }
|
|
FieldLifecycle::saved($value, $field, $documentId, 'document_mutation');
|
|
}
|
|
}
|
|
|
|
protected function captureRevision($documentId, $actorId)
|
|
{
|
|
$rows = DB::query('SELECT df.rubric_field_id,df.field_value,COALESCE(dft.field_value,\'\') more FROM ' . ContentTables::table('document_fields') . ' df LEFT JOIN ' . ContentTables::table('document_fields_text') . ' dft ON dft.document_id=df.document_id AND dft.rubric_field_id=df.rubric_field_id WHERE df.document_id=%i', (int)$documentId)->getAll();
|
|
$values=array(); foreach($rows?:array() as $row){$values[(int)$row['rubric_field_id']]=(string)$row['field_value'].(string)$row['more'];}
|
|
$document = $this->document($documentId);
|
|
if (!$document) { return; }
|
|
DB::Insert(ContentTables::table('document_rev'), array('doc_id'=>(int)$documentId,'doc_revision'=>time(),'doc_data'=>serialize(DocumentRevisionPayload::create($document, $values)),'user_id'=>(int)$actorId));
|
|
}
|
|
|
|
protected function pick(array $data, array $keys, $default) { foreach ($keys as $key) { if (array_key_exists($key, $data)) { return $data[$key]; } } return $default; }
|
|
protected function boolean($value) { return in_array(strtolower(trim((string)$value)), array('1','true','yes','on','published','active'), true) ? 1 : 0; }
|
|
protected function timestamp($value, $default) { if (is_int($value) || ctype_digit((string)$value)) { return max(0,(int)$value); } $time=strtotime((string)$value); return $time ? $time : (int)$default; }
|
|
protected function robots($value) { return in_array((string)$value,array('index,follow','index,nofollow','noindex,nofollow'),true)?(string)$value:'index,follow'; }
|
|
protected function numeric($value) { $value=str_replace(',','.',(string)$value); $value=preg_replace('/[^0-9.\-]/','',$value); return is_numeric($value)?(float)$value:0; }
|
|
}
|