private function repeaterHydrate($record, $app) { $contentTypeName = $record->contenttype['slug']; $contentType = $app['config']->get('contenttypes/' . $contentTypeName); $values = $this->localeValues; $localeSlug = $app['translate.slug']; if (isset($values[$localeSlug . 'data'])) { $localeData = json_decode($values[$localeSlug . 'data'], true); foreach ($localeData as $key => $value) { if ($key === 'templatefields') { $templateFields = $app['config']->get('theme/templatefields/' . $record['template'] . '/fields'); foreach ($templateFields as $key => $field) { if ($field['type'] === 'repeater') { $localeData = json_decode($value[$key], true); $originalMapping = null; $originalMapping[$key]['fields'] = $templateFields[$key]['fields']; $originalMapping[$key]['type'] = 'repeater'; $mapping = $app['storage.metadata']->getRepeaterMapping($originalMapping); $repeater = new RepeatingFieldCollection($app['storage'], $mapping); $repeater->setName($key); foreach ($localeData as $subValue) { $repeater->addFromArray($subValue); } $record['templatefields'][$key] = $repeater; } } } if (isset($contentType['fields'][$key]) && $contentType['fields'][$key]['type'] === 'repeater') { /** * Hackish fix until #5533 gets fixed, after that the * following four (4) lines can be replaced with * "$record[$key]->clear();" */ $originalMapping[$key]['fields'] = $contentType['fields'][$key]['fields']; $originalMapping[$key]['type'] = 'repeater'; $mapping = $app['storage.metadata']->getRepeaterMapping($originalMapping); $record[$key] = new RepeatingFieldCollection($app['storage'], $mapping); foreach ($value as $subValue) { $record[$key]->addFromArray($subValue); } } } } }
/** * Normalize step ensures that we have correctly hydrated objects at the collection * and entity level. * * @param $entity */ public function normalize($entity) { $key = $this->mapping['fieldname']; $accessor = 'get' . ucfirst($key); $outerCollection = $entity->{$accessor}(); $newVal = []; if (!$outerCollection instanceof RepeatingFieldCollection) { $collection = new RepeatingFieldCollection($this->em); $collection->setName($key); if (is_array($outerCollection)) { foreach ($outerCollection as $group => $fields) { if (is_array($fields)) { $collection->addFromArray($fields, $group); } } } $setter = 'set' . ucfirst($key); $entity->{$setter}($collection); } }
public function getRepeaters($content) { $ids = util::array_pluck($content, 'id'); if (empty($ids)) { return; } // Get the contenttype from first $content $contenttypeslug = $content[util::array_first_key($content)]->contenttype['slug']; $contenttype = $this->getContentType($contenttypeslug); $repo = $this->app['storage']->getRepository('Bolt\\Storage\\Entity\\FieldValue'); foreach ($ids as $id) { foreach ($contenttype['fields'] as $fieldkey => $field) { if ($field['type'] == 'repeater') { $collection = new RepeatingFieldCollection($this->app['storage'], $field); $existingFields = $repo->getExistingFields($id, $contenttypeslug, $fieldkey) ?: []; foreach ($existingFields as $group => $ids) { $collection->addFromReferences($ids, $group); } $content[$id]->setValue($fieldkey, $collection); } } } }
/** * Set a ContentType record's values. * * @param array $values */ public function setValues(array $values) { // Since Bolt 1.4, we use 'ownerid' instead of 'username' in the DB tables. If we get an array that has an // empty 'ownerid', attempt to set it from the 'username'. In $this->setValue the user will be set, regardless // of ownerid is an 'id' or a 'username'. if (empty($values['ownerid']) && !empty($values['username'])) { $values['ownerid'] = $values['username']; unset($values['username']); } foreach ($values as $key => $value) { if ($key !== 'templatefields') { $this->setValue($key, $value); } } // If default status is set in contentttype. if (empty($this->values['status']) && isset($this->contenttype['default_status'])) { $this->values['status'] = $this->contenttype['default_status']; } $serializedFieldTypes = ['geolocation', 'imagelist', 'image', 'file', 'filelist', 'video', 'select', 'templateselect', 'checkbox', 'repeater']; // Check if the values need to be unserialized, and pre-processed. foreach ($this->values as $key => $value) { if (in_array($this->fieldtype($key), $serializedFieldTypes) || $key === 'templatefields') { if (!empty($value) && is_string($value) && (substr($value, 0, 2) === 'a:' || $value[0] === '[' || $value[0] === '{')) { try { $unserdata = Lib::smartUnserialize($value); } catch (\Exception $e) { $unserdata = false; } if ($unserdata !== false) { $this->values[$key] = $unserdata; } } } if ($this->fieldtype($key) === 'video' && is_array($this->values[$key]) && !empty($this->values[$key]['url'])) { $video = $this->values[$key]; // update the HTML, according to given width and height if (!empty($video['width']) && !empty($video['height'])) { $video['html'] = preg_replace("/width=(['\"])([0-9]+)(['\"])/i", 'width=${1}' . $video['width'] . '${3}', $video['html']); $video['html'] = preg_replace("/height=(['\"])([0-9]+)(['\"])/i", 'height=${1}' . $video['height'] . '${3}', $video['html']); } $responsiveclass = 'responsive-video'; // See if it's widescreen or not. if (!empty($video['height']) && $video['width'] / $video['height'] > 1.76) { $responsiveclass .= ' widescreen'; } if (strpos($video['url'], 'vimeo') !== false) { $responsiveclass .= ' vimeo'; } $video['responsive'] = sprintf('<div class="%s">%s</div>', $responsiveclass, $video['html']); // Mark them up as Twig_Markup. $video['html'] = new \Twig_Markup($video['html'], 'UTF-8'); $video['responsive'] = new \Twig_Markup($video['responsive'], 'UTF-8'); $this->values[$key] = $video; } if ($this->fieldtype($key) === 'repeater' && is_array($this->values[$key]) && !$this->isRootType) { $originalMapping = null; $originalMapping[$key]['fields'] = $this->contenttype['fields'][$key]['fields']; $originalMapping[$key]['type'] = 'repeater'; $mapping = $this->app['storage.metadata']->getRepeaterMapping($originalMapping); $repeater = new RepeatingFieldCollection($this->app['storage'], $mapping); $repeater->setName($key); foreach ($this->values[$key] as $subValue) { $repeater->addFromArray($subValue); } $this->values[$key] = $repeater; } if ($this->fieldtype($key) === 'date' || $this->fieldtype($key) === 'datetime') { if ($this->values[$key] === '') { $this->values[$key] = null; } } } // Template fields need to be done last // As the template has to have been selected if ($this->isRootType) { if (empty($values['templatefields'])) { $this->setValue('templatefields', []); } else { $this->setValue('templatefields', $values['templatefields']); } } }
/** * @param RepeatingFieldCollection $collection * * @return RepeatingFieldCollection[] */ public function update(RepeatingFieldCollection $collection) { $updated = []; // First give priority to already existing entities foreach ($collection->flatten() as $entity) { $master = $this->getOriginal($entity); $master->setValue($entity->getValue()); $master->setFieldtype($entity->getFieldtype()); $master->handleStorage($this->getFieldType($entity->getFieldname())); $updated[] = $master; } $deleted = []; foreach ($this->flatten() as $old) { if (!in_array($old, $updated)) { $deleted[] = $old; } } // Clear the collection so that we re-add only the updated elements $this->clear(); foreach ($updated as $new) { $this->add($new); } return $deleted; }