/** * Clone an entire page, it's assets and children and return it. * * @param Page $page Page that you want to clone * @param Page $parent New parent, if different (default=same parent) * @param bool $recursive Clone the children too? (default=true) * @param array|string $options Optional options that can be passed to clone or save * - forceID (int): force a specific ID * - set (array): Array of properties to set to the clone (you can also do this later) * - recursionLevel (int): recursion level, for internal use only. * @return Page the newly cloned page or a NullPage() with id=0 if unsuccessful. * @throws WireException|Exception on fatal error * */ public function ___clone(Page $page, Page $parent = null, $recursive = true, $options = array()) { if (is_string($options)) { $options = Selectors::keyValueStringToArray($options); } if (!isset($options['recursionLevel'])) { $options['recursionLevel'] = 0; } // recursion level // if parent is not changing, we have to modify name now if (is_null($parent)) { $parent = $page->parent; $n = 1; $name = $page->name . '-' . $n; } else { $name = $page->name; $n = 0; } // make sure that we have a unique name while (count($parent->children("name={$name}, include=all"))) { $name = $page->name; $nStr = "-" . ++$n; if (strlen($name) + strlen($nStr) > self::nameMaxLength) { $name = substr($name, 0, self::nameMaxLength - strlen($nStr)); } $name .= $nStr; } // Ensure all data is loaded for the page foreach ($page->template->fieldgroup as $field) { $page->get($field->name); } // clone in memory $copy = clone $page; $copy->id = isset($options['forceID']) ? (int) $options['forceID'] : 0; $copy->setIsNew(true); $copy->name = $name; $copy->parent = $parent; // set any properties indicated in options if (isset($options['set']) && is_array($options['set'])) { foreach ($options['set'] as $key => $value) { $copy->set($key, $value); } if (isset($options['set']['modified'])) { $options['quiet'] = true; // allow for modified date to be set if (!isset($options['set']['modified_users_id'])) { // since 'quiet' also allows modified user to be set, make sure that it // is still updated, if not specifically set. $copy->modified_users_id = $this->wire('user')->id; } } if (isset($options['set']['modified_users_id'])) { $options['quiet'] = true; // allow for modified user to be set if (!isset($options['set']['modified'])) { // since 'quiet' also allows modified tie to be set, make sure that it // is still updated, if not specifically set. $copy->modified = time(); } } } // tell PW that all the data needs to be saved foreach ($copy->template->fieldgroup as $field) { $copy->trackChange($field->name); } $o = $copy->outputFormatting; $copy->setOutputFormatting(false); $this->cloneReady($page, $copy); try { $this->cloning = true; $options['ignoreFamily'] = true; // skip family checks during clone $this->save($copy, $options); } catch (Exception $e) { $this->cloning = false; throw $e; } $this->cloning = false; $copy->setOutputFormatting($o); // check to make sure the clone has worked so far if (!$copy->id || $copy->id == $page->id) { return new NullPage(); } // copy $page's files over to new page if (PagefilesManager::hasFiles($page)) { $copy->filesManager->init($copy); $page->filesManager->copyFiles($copy->filesManager->path()); } // if there are children, then recurisvely clone them too if ($page->numChildren && $recursive) { $start = 0; $limit = 200; do { $children = $page->children("include=all, start={$start}, limit={$limit}"); $numChildren = $children->count(); foreach ($children as $child) { /** @var Page $child */ $this->clone($child, $copy, true, array('recursionLevel' => $options['recursionLevel'] + 1)); } $start += $limit; $this->uncacheAll(); } while ($numChildren); } $copy->parentPrevious = null; // update pages_parents table, only when at recursionLevel 0 since pagesParents is already recursive if ($recursive && $options['recursionLevel'] === 0) { $this->saveParents($copy->id, $copy->numChildren); } $copy->resetTrackChanges(); $this->cloned($page, $copy); $this->debugLog('clone', "page={$page}, parent={$parent}", $copy); return $copy; }
/** * Clone an entire page, it's assets and children and return it. * * @param Page $page Page that you want to clone * @param Page $parent New parent, if different (default=same parent) * @param bool $recursive Clone the children too? (default=true) * @param array $options Optional options that can be passed to clone or save * - forceID (int): force a specific ID * - set (array): Array of properties to set to the clone (you can also do this later) * @return Page the newly cloned page or a NullPage() with id=0 if unsuccessful. * */ public function ___clone(Page $page, Page $parent = null, $recursive = true, $options = array()) { // if parent is not changing, we have to modify name now if (is_null($parent)) { $parent = $page->parent; $n = 1; $name = $page->name . '-' . $n; } else { $name = $page->name; $n = 0; } // make sure that we have a unique name while (count($parent->children("name={$name}, include=all"))) { $name = $page->name . '-' . ++$n; } // Ensure all data is loaded for the page foreach ($page->template->fieldgroup as $field) { $page->get($field->name); } // clone in memory $copy = clone $page; $copy->id = isset($options['forceID']) ? (int) $options['forceID'] : 0; $copy->setIsNew(true); $copy->name = $name; $copy->parent = $parent; // set any properties indicated in options if (isset($options['set']) && is_array($options['set'])) { foreach ($options['set'] as $key => $value) { $copy->set($key, $value); } } // tell PW that all the data needs to be saved foreach ($copy->template->fieldgroup as $field) { $copy->trackChange($field->name); } $o = $copy->outputFormatting; $copy->setOutputFormatting(false); $this->cloneReady($page, $copy); $this->save($copy, $options); $copy->setOutputFormatting($o); // check to make sure the clone has worked so far if (!$copy->id || $copy->id == $page->id) { return new NullPage(); } // copy $page's files over to new page if (PagefilesManager::hasFiles($page)) { $copy->filesManager->init($copy); $page->filesManager->copyFiles($copy->filesManager->path()); } // if there are children, then recurisvely clone them too if ($page->numChildren && $recursive) { foreach ($page->children("include=all") as $child) { $this->clone($child, $copy); } } $copy->parentPrevious = null; $copy->resetTrackChanges(); $this->cloned($page, $copy); $this->debugLog('clone', "page={$page}, parent={$parent}", $copy); return $copy; }