public function testSetupWithRecord() { $app = $this->getApp(); $content = new Content($app, 'pages'); $content->setValue('id', 5); $event = new StorageEvent($content); $this->assertEquals(5, $event->getId()); $this->assertEquals('pages', $event->getContentType()); }
public function testgetValues() { $app = $this->getApp(); $content = new Content($app, 'pages'); $content->setValue('title', 'Test Page'); $content->setValue('image', array('file' => 'image1.jpg', 'title' => 'Test image')); $values = $content->getValues(true); $this->assertEquals('Test Page', $values['title']); $this->assertEquals('{"file":"image1.jpg","title":"Test image"}', $values['image']); }
public function testDefaultCode() { $entry = new Content($this->app, 'entries'); $entry->setValue('title', 'Test'); $entry->setValue('slug', 'test-default-code'); $entry->setValue('ownerid', 1); $entry->setValue('status', 'published'); $id = $this->app['storage']->saveContent($entry); $values = ['source' => '/test-default-code', 'contentId' => $id, 'contentType' => 'entries', 'code' => null]; $redirect = new Redirect($values); $redirect->save(); $request = Request::create('/test-default-code'); $response = $this->app->handle($request); $default = $this->extension->config['default_status_code']; $default = empty($default) ? 302 : $default; $this->assertEquals($response->getStatusCode(), $default); }
/** * Check if a given name is a valid column, and if it can be used in queries. * * @param string $name * @param array $contenttype * @param bool $allowVariants * @return bool */ private function isValidColumn($name, $contenttype, $allowVariants = false) { // Strip the minus in '-title' if allowed.. if ($allowVariants) { if (strlen($name) > 0 && $name[0] == "-") { $name = substr($name, 1); } $name = $this->getFieldName($name); } // Check if the $name is in the contenttype's fields. if (isset($contenttype['fields'][$name])) { return true; } if (in_array($name, Content::getBaseColumns())) { return true; } return false; }
/** * Create a list of fields types used in regular, template and virtual fields. * * @param array $contenttype * @param Content $content * @param array $has * * @return array */ private function getUsedFieldtypes(array $contenttype, Content $content, array $has) { $fieldtypes = ['meta' => true]; foreach ([$contenttype['fields'], $content->get('templatefields')->contenttype['fields'] ?: []] as $fields) { foreach ($fields as $field) { $fieldtypes[$field['type']] = true; } } if ($has['relations'] || $has['incoming_relations']) { $fieldtypes['relationship'] = true; } if ($has['taxonomy'] || is_array($contenttype['groups']) && in_array('taxonomy', $contenttype['groups'])) { $fieldtypes['taxonomy'] = true; } if ($has['templatefields'] || is_array($contenttype['groups']) && in_array('template', $contenttype['groups'])) { $fieldtypes['template'] = true; } return array_keys($fieldtypes); }
/** * Update a Bolt contenttype record. * * @param \Bolt\Content $content The content object to be updated * @param string $comment Add a comment to save with change. * * @throws \Bolt\Exception\StorageException * * @return bool */ private function updateContent(Bolt\Content $content, $comment = null) { $tablename = $this->getContenttypeTablename($content->contenttype); // Set the date the record was changed $content->setValue('datechanged', date('Y-m-d H:i:s')); // Test that the record exists in the database $oldContent = $this->findContent($tablename, $content['id']); if (empty($oldContent)) { throw new StorageException('Attempted to update a non-existent record'); } // Get the JSON database prepared values and make sure it's valid $fieldvalues = $this->getValidSaveData($content->getValues(true), $content->contenttype); // Do the actual update, and log it. $res = $this->app['db']->update($tablename, $fieldvalues, array('id' => $content['id'])); if ($res > 0) { $this->logUpdate($content->contenttype['slug'], $content['id'], $fieldvalues, $oldContent, $comment); return true; } }
/** * Set a Contenttype record's individual value. * * @param string $key * @param mixed $value */ public function setValue($key, $value) { // Don't set templateFields if not a real contenttype if ($key === 'templatefields' && !$this->isRootType) { return; } // Check if the value need to be unserialized. if (is_string($value) && substr($value, 0, 2) === "a:") { try { $unserdata = Lib::smartUnserialize($value); } catch (\Exception $e) { $unserdata = false; } if ($unserdata !== false) { $value = $unserdata; } } if ($key == 'id') { $this->id = $value; } // Set the user in the object. if ($key === 'ownerid' && !empty($value)) { $this->user = $this->app['users']->getUser($value); } // Only set values if they have are actually a field. $allowedcolumns = self::getBaseColumns(); $allowedcolumns[] = 'taxonomy'; if (!isset($this->contenttype['fields'][$key]) && !in_array($key, $allowedcolumns)) { return; } if (in_array($key, ['datecreated', 'datechanged', 'datepublish', 'datedepublish'])) { if (!preg_match("/(\\d{4})-(\\d{2})-(\\d{2}) (\\d{2}):(\\d{2}):(\\d{2})/", $value)) { // @todo Try better date-parsing, instead of just setting it to // 'now' (or 'the past' for datedepublish) if ($key == 'datedepublish') { $value = null; } else { $value = date('Y-m-d H:i:s'); } } } if ($key === 'templatefields') { if (is_string($value) || is_array($value)) { if (is_string($value)) { try { $unserdata = Lib::smartUnserialize($value); } catch (\Exception $e) { $unserdata = false; } } else { $unserdata = $value; } if (is_array($unserdata)) { $templateContent = new Content($this->app, $this->getTemplateFieldsContentType(), [], false); $value = $templateContent; $this->populateTemplateFieldsContenttype($value); $templateContent->setValues($unserdata); } else { $value = null; } } } if (!isset($this->values['datechanged']) || !preg_match("/(\\d{4})-(\\d{2})-(\\d{2}) (\\d{2}):(\\d{2}):(\\d{2})/", $this->values['datechanged'])) { $this->values['datechanged'] = date("Y-m-d H:i:s"); } $this->values[$key] = $value; }
/** * Returns all field names for the given contenttype. * * @param string $contenttype The name of the contenttype. * @return string[] An array with all field definitions for the given * contenttype. This includes the base columns as well. */ private function getAllFieldNames($contenttype) { $baseFields = \Bolt\Content::getBaseColumns(); $definedFields = $this->app['config']->get("contenttypes/{$contenttype}/fields", []); $taxonomyFields = $this->getAllTaxonomies($contenttype); // Fields could be empty, although it's a rare case. if (!empty($definedFields)) { $definedFields = array_keys($definedFields); } $definedFields = array_merge($definedFields, $taxonomyFields); return array_merge($baseFields, $definedFields); }
protected function write(array $record) { // Simply exit if we're not enabled if (!$this->app['config']->get('general/changelog/enabled')) { return; } // Initialise ourselves if not already if (!$this->initialized) { $this->initialize(); } // Check for a valid call if (!in_array($record['context']['action'], $this->allowed)) { throw new \Exception("Invalid action '{$record['context']['action']}' specified for changelog (must be one of [ " . implode(', ', $this->allowed) . " ])"); } if (empty($record['context']['old']) && empty($record['context']['new'])) { throw new \Exception("Tried to log something that cannot be: both old and new content are empty"); } if (empty($record['context']['old']) && in_array($record['context']['action'], ['UPDATE', 'DELETE'])) { throw new \Exception("Cannot log action '{$record['context']['action']}' when old content doesn't exist"); } if (empty($record['context']['new']) && in_array($record['context']['action'], ['INSERT', 'UPDATE'])) { throw new \Exception("Cannot log action '{$record['context']['action']}' when new content is empty"); } $data = []; switch ($record['context']['action']) { case 'UPDATE': $diff = DeepDiff::diff($record['context']['old'], $record['context']['new']); foreach ($diff as $item) { list($k, $old, $new) = $item; if (isset($record['context']['new'][$k])) { $data[$k] = [$old, $new]; } } break; case 'INSERT': foreach ($record['context']['new'] as $k => $val) { $data[$k] = [null, $val]; } break; case 'DELETE': foreach ($record['context']['old'] as $k => $val) { $data[$k] = [$val, null]; } break; } if ($record['context']['new']) { $content = new Content($this->app, $record['context']['contenttype'], $record['context']['new']); } else { $content = new Content($this->app, $record['context']['contenttype'], $record['context']['old']); } $title = $content->getTitle(); if (empty($title)) { /** @var \Bolt\Content $content */ $content = $this->app['storage']->getContent($record['context']['contenttype'] . '/' . $record['context']['id']); $title = $content->getTitle(); } // Don't store datechanged, or records that are only datechanged unset($data['datechanged']); if (empty($data)) { return; } $str = json_encode($data); $user = $this->app['users']->getCurrentUser(); try { $this->app['db']->insert($this->tablename, ['date' => $record['datetime']->format('Y-m-d H:i:s'), 'ownerid' => $user['id'], 'title' => $title, 'contenttype' => $record['context']['contenttype'], 'contentid' => $record['context']['id'], 'mutation_type' => $record['context']['action'], 'diff' => $str, 'comment' => $record['context']['comment']]); } catch (\Exception $e) { // Nothing. } }
/** * Compare by search weights. * * Or fallback to dates or title * * @param \Bolt\Content $a * @param \Bolt\Content $b * * @return int */ private function compareSearchWeights(\Bolt\Content $a, \Bolt\Content $b) { if ($a->getSearchResultWeight() > $b->getSearchResultWeight()) { return -1; } if ($a->getSearchResultWeight() < $b->getSearchResultWeight()) { return 1; } if ($a['datepublish'] > $b['datepublish']) { // later is more important return -1; } if ($a['datepublish'] < $b['datepublish']) { // earlier is less important return 1; } return strcasecmp($a['title'], $b['title']); }
public function getEmptyContent($contenttypeslug) { $contenttype = $this->getContentType($contenttypeslug); $content = new Bolt\Content('', $contenttypeslug); $values = array('id' => '', 'slug' => '', 'datecreated' => '', 'datechanged' => '', 'datepublish' => '', 'username' => '', 'status' => ''); foreach ($contenttype['fields'] as $key => $field) { $values[$key] = ''; // Set the default values. if (isset($field['default'])) { $values[$key] = $field['default']; } else { $values[$key] = ''; } } $content->setValues($values); // echo "<pre>\n" . util::var_dump($content, true) . "</pre>\n"; return $content; }
/** * Check whether the status is allowed. * * We act as if a status *transition* were requested and fallback to the old * status otherwise. * * @param Application $app * @param Content $content * @param string $contentTypeSlug * @param integer $id * @param string $oldStatus */ private function setTransitionStatus(Application $app, Content $content, $contentTypeSlug, $id, $oldStatus) { $canTransition = $app['users']->isContentStatusTransitionAllowed($oldStatus, $content['status'], $contentTypeSlug, $id); if (!$canTransition) { $content->setValue('status', $oldStatus); } }
/** * Determine which templates will result in templatefields. * * @param array $contenttype * @param Content $content * * @return array */ private function getTempateFieldTemplates(array $contenttype, Content $content) { $templateFieldTemplates = []; if ($templateFieldsConfig = $this->app['config']->get('theme/templatefields')) { $templateFieldTemplates = array_keys($templateFieldsConfig); // Special case for default template $toRepair = []; foreach ($contenttype['fields'] as $name => $field) { if ($field['type'] === 'templateselect' && !empty($content->values[$name])) { $toRepair[$name] = $content->values[$name]; $content->setValue($name, ''); } } if ($content->hasTemplateFields()) { $templateFieldTemplates[] = ''; } foreach ($toRepair as $name => $value) { $content->setValue($name, $value); } } return $templateFieldTemplates; }
/** * Create the prototype context based on the parent. * * @param array $context * @param string $key * * @return array */ public function getPrototypeContext(array $context, $key) { list($fields, $groups) = $this->wrapParseFieldsAndGroups($context['contenttype']['fields'][$key]['children']); foreach ($fields as $childKey => &$value) { list($realName, $realId) = $this->getRealNameAndId($key, $childKey); $value['real_name'] = $realName; $value['real_id'] = $realId; } // Do content. $content = new Content($this->app, '', array()); foreach ($fields as $key => $options) { $content->setValue($key, $options['default']); } // Remove btn. list(, $realBtnId) = $this->getRealNameAndId($key, 'array_item_remove_btn'); $childrenContext = array('contenttype' => array('fields' => $fields), 'content' => $content, 'allowed_status' => $context['allowed_status'], 'contentowner' => $context['contentowner'], 'fields' => $context['fields'], 'fieldtemplates' => $context['fieldtemplates'], 'can_upload' => $context['can_upload'], 'groups' => $groups ?: array('ungrouped' => array_keys($fields)), 'has' => array('incoming_relations' => false, 'relations' => false, 'tabs' => false, 'taxonomy' => false, 'templatefields' => false), 'array_options' => array('btn_remove_id' => $realBtnId)); return $childrenContext; }