1
0
mirror of https://github.com/processwire/processwire.git synced 2025-08-10 16:54:44 +02:00

Addition of a $page->numParents() method/property which reflects the number of parents the page has, aka depth in the tree. This commit also has several small adjustments and fixes, including a fix for the issue introduced last week that caused issues with WireArray in versions of PHP prior to 7.x

This commit is contained in:
Ryan Cramer
2018-10-26 12:18:46 -04:00
parent b964fd1a15
commit 7331bac132
11 changed files with 126 additions and 33 deletions

View File

@@ -1031,3 +1031,26 @@ function wireRegion($key, $value = null) {
return $result;
}
/**
* Create new WireArray, add given $items to it, and return it
*
* @param array|WireArray $items
* @return WireArray
*
*/
function WireArray($items = array()) {
return WireArray::newInstance($items);
}
/**
* Create new PageArray, add given $items (pages) to it, and return it
*
* @param array|PageArray $items
* @return WireArray
*
*/
function PageArray($items = array()) {
return PageArray::newInstance($items);
}

View File

@@ -611,6 +611,7 @@ class Page extends WireData implements \Countable, WireMatchable {
'namePrevious' => 'p',
'next' => 'm',
'numChildren' => 's',
'numParents' => 'm',
'numDescendants' => 'm',
'numLinks' => 't',
'numReferences' => 't',
@@ -2191,6 +2192,20 @@ class Page extends WireData implements \Countable, WireMatchable {
return $this->traversal()->parents($this, $selector);
}
/**
* Return number of parents (depth relative to homepage) that this page has, optionally filtered by a selector
*
* For example, homepage has 0 parents and root level pages have 1 parent (which is the homepage), and the
* number increases the deeper the page is in the pages structure.
*
* @param string $selector Optional selector to filter by (default='')
* @return int Number of parents
*
*/
public function numParents($selector = '') {
return $this->traversal()->numParents($this, $selector);
}
/**
* Return all parents from current page till the one matched by $selector
*

View File

@@ -174,6 +174,28 @@ class PageTraversal {
return strlen($selector) ? $parents->filter($selector) : $parents;
}
/**
* Return number of parents (depth relative to homepage) that this page has, optionally filtered by a selector
*
* For example, homepage has 0 parents and root level pages have 1 parent (which is the homepage), and the
* number increases the deeper the page is in the pages structure.
*
* @param Page $page
* @param string $selector Optional selector to filter by (default='')
* @return int Number of parents
*
*/
public function numParents(Page $page, $selector = '') {
$num = 0;
$parent = $page->parent();
while($parent && $parent->id) {
if($selector !== '' && !$parent->matches($selector)) continue;
$num++;
$parent = $parent->parent();
}
return $num;
}
/**
* Return all parent from current till the one matched by $selector
*
@@ -660,6 +682,7 @@ class PageTraversal {
$languages = $options['languages'] ? $page->wire('languages') : null;
$slashUrls = $page->template->slashUrls;
$httpHostUrl = $options['http'] ? $page->wire('input')->httpHostUrl() : '';
$urls = array();
if($options['language'] && $languages) {
if(!$options['language'] instanceof Page) {
@@ -682,6 +705,7 @@ class PageTraversal {
// add in historical URLs
if($options['past'] && $modules->isInstalled('PagePathHistory')) {
/** @var PagePathHistory $history */
$history = $modules->get('PagePathHistory');
$rootUrl = $page->wire('config')->urls->root;
$pastPaths = $history->getPathHistory($page, array(
@@ -691,11 +715,13 @@ class PageTraversal {
foreach($pastPaths as $pathInfo) {
$key = '';
if(!empty($pathInfo['language'])) {
/** @var Language $language */
$language = $pathInfo['language'];
if($options['languages']) {
$key .= $pathInfo['language']->name . ';';
$key .= $language->name . ';';
} else {
// they asked to have multi-language excluded
if(!$pathInfo['language']->isDefault()) continue;
if(!$language->isDefault()) continue;
}
}
$key .= wireDate('c', $pathInfo['date']);
@@ -774,6 +800,7 @@ class PageTraversal {
*/
public function referencing(Page $page, $field = false, $getCount = false) {
$fieldName = '';
$byField = null;
if(is_bool($field) || is_null($field)) {
$byField = $field ? true : false;
} else if(is_string($field)) {
@@ -793,7 +820,7 @@ class PageTraversal {
foreach($page->template->fieldgroup as $f) {
if($fieldName && $field->name != $fieldName) continue;
if(!$f->type instanceof FieldtypePage) continue;
if($byField) $itemsByField[$f->name] = $this->wire('pages')->newPageArray();
if($byField) $itemsByField[$f->name] = $page->wire('pages')->newPageArray();
$value = $page->get($f->name);
if($value instanceof Page && $value->id) {
$items->add($value);
@@ -916,6 +943,7 @@ class PageTraversal {
$next = $page;
do {
/** @var Page $next */
$next = $siblings->getNext($next, false);
if(empty($selector) || !$next || $next->matches($selector)) break;
} while($next && $next->id);
@@ -959,6 +987,7 @@ class PageTraversal {
$prev = $page;
do {
/** @var Page $prev */
$prev = $siblings->getPrev($prev, false);
if(empty($selector) || !$prev || $prev->matches($selector)) break;
} while($prev && $prev->id);
@@ -1006,7 +1035,7 @@ class PageTraversal {
* @param Page $page
* @param string|array $selector Optional selector. When specified, will filter the found siblings.
* @param PageArray $siblings Optional siblings to use instead of the default.
* @return Page|NullPage Returns all matching pages before this one.
* @return PageArray
*
*/
public function prevAllSiblings(Page $page, $selector = '', PageArray $siblings = null) {

View File

@@ -60,7 +60,7 @@ class User extends Page {
* }
* ~~~~~
*
* @param string|Role|int May be Role name, object or ID.
* @param string|Role|int $role May be Role name, object or ID.
* @return bool
*
*/
@@ -107,7 +107,7 @@ class User extends Page {
* $user->save();
* ~~~~~
*
* @param string|int|Role Maybe Role name, object, or ID.
* @param string|int|Role $role May be Role name, object, or ID.
* @return bool Returns false if role not recognized, true otherwise
*
*/
@@ -131,7 +131,7 @@ class User extends Page {
* $user->save();
* ~~~~~
*
* @param string|int|Role May be Role name, object or ID.
* @param string|int|Role $role May be Role name, object or ID.
* @return bool false if role not recognized, true otherwise
*
*/

View File

@@ -16,7 +16,7 @@
* https://processwire.com
*
* @method WireArray and($item)
* @method WireArray new($items = array())
* @method static WireArray new($items = array())
* @property int $count Number of items
* @property Wire|null $first First item
* @property Wire|null $last Last item
@@ -2446,39 +2446,36 @@ class WireArray extends Wire implements \IteratorAggregate, \ArrayAccess, \Count
// multiple items specified as arguments
$items = $arguments;
}
$a = new $class();
if(WireArray::iterable($items)) {
$a->import($items);
} else if($items !== null) {
$a->add($items);
}
return $a;
return self::newInstance($items, $class);
} else {
throw new WireException("Unrecognized static method: $class::$name()");
}
}
/**
* Create a new WireArray instance of this type, optionally adding $items to it
* Create new instance of this class
*
* This method call be called statically or non-statically, but is primarily useful as a static method call.
* Method for internal use, use `$a = WireArray::new($items)` or `$a = WireArrray($items)` instead.
*
* ~~~~~~
* // Create new WireArray with a, b and c items
* $a = WireArray::new([ 'a', 'b', 'c' ]);
* #pw-internal
*
* // This also works when called statically (array syntax can optionally be omitted)
* $a = WireArray::new('a', 'b', 'c');
* ~~~~~~
*
* @param array|WireArray|mixed|null $items Items (or item) to add to new WireArray
* @param array|WireArray|null $items Items to add or omit (null) for none
* @param string $class Class name to instantiate or omit for called class
* @return WireArray
* @since 3.0.117
*
*/
public function ___new($items = null) {
$a = self::new($items);
$this->wire($a);
public static function newInstance($items = null, $class = '') {
if(empty($class)) $class = get_called_class();
/** @var WireArray $a */
$a = new $class();
if($items instanceof WireArray) {
$items->wire($a);
$a->import($items);
} else if(is_array($items)) {
$a->import($items);
} else if($items !== null) {
$a->add($items);
}
return $a;
}
}

View File

@@ -386,6 +386,7 @@ class WireFileTools extends Wire {
for($i = 0; $i < $zip->numFiles; $i++) {
$name = $zip->getNameIndex($i);
if(strpos($name, '..') !== false) continue;
if($zip->extractTo($dst, $name)) {
$names[$i] = $name;
$filename = $dst . ltrim($name, '/');

View File

@@ -1814,6 +1814,8 @@ class FieldtypeComments extends FieldtypeMulti {
$updatePropertyCounts = array();
$skipUpdateProperties = array('id', 'created_user', 'created_users_id');
if(!$comments) return null;
foreach($comments as $comment) {
if($comment->status == Comment::statusSpam) continue;
$key = $this->getCommentExportKey($comment);

View File

@@ -103,7 +103,7 @@ class SelectableOption extends WireData { // implements LanguagesValueInterface
* @return string
*
*/
protected function getProperty($property) {
public function getProperty($property) {
if($this->wire('languages')) {
$language = $this->wire('user')->language;
if($language->isDefault()) {

View File

@@ -89,9 +89,13 @@ class InputfieldCheckbox extends Inputfield {
$attrs = $this->getAttributes();
$attrs['value'] = $this->checkedValue;
if($this->getSetting('entityEncodeLabel') !== false) {
$label = $this->entityEncode($label);
}
$out =
"<label><input type='checkbox' " . $this->getAttributesString($attrs) . " />" .
"<span class='pw-no-select'>" . $this->entityEncode($label) . "</span></label>";
"<span class='pw-no-select'>$label</span></label>";
return $out;
}

View File

@@ -72,6 +72,7 @@
* @method string executeConfig() ListerPro
* @method string executeActions() ListerPro
* @method string executeSave() ListerPro
* @method string renderExtraTabs() #pw-hooker
*
*
* @todo make system fields hookable for output like markupValue is for custom fields
@@ -1823,7 +1824,7 @@ class ProcessPageLister extends Process implements ConfigurableModule {
/**
* Render additional tabs, setup so that descending classes can use as a template method
*
*
* @return string
*
*/
@@ -1832,9 +1833,24 @@ class ProcessPageLister extends Process implements ConfigurableModule {
$resetLabel = $this->_('Reset filters and columns to default');
$out = "<div id='ProcessListerRefreshTab' title='$refreshLabel' class='WireTab WireTabTip'></div>";
$out .= "<div id='ProcessListerResetTab' title='$resetLabel' class='WireTab WireTabTip'></div>";
$out .= $this->renderExtraTabs();
return $out;
}
/**
* Optionally hook this if you want to add additional tabs
*
* See renderExtras() method above for examples.
*
* #pw-hooker
*
* @return string Markup for extra tabs
*
*/
public function ___renderExtraTabs() {
return '';
}
/**
* Prepare the session values for external assets
*

View File

@@ -605,7 +605,13 @@ class ProcessPagesExportImport extends Process {
$path = rtrim($importParentPath . substr($path, strlen($missingParentPath)), '/') . '/';
}
}
if($path == $item['path']) $path = $importParentPath . trim($path, '/') . '/';
if($path == $item['path']) {
if(strpos($path, $importParentPath) === 0) {
// parent already present in path
} else {
$path = $importParentPath . trim($path, '/') . '/';
}
}
$a['pages'][$key]['path'] = $path;
}
}