TODO переписать логику на $includeSelf = true делать gte, lte иначе gt, lt соответственно
Named scope. Gets descendants for node.

@param bool $includeSelf
@param int  $depth       the depth

@return QuerySet
14363
public function descendants($includeSelf = false, $depth = null)
    {
        $this->filter([
            'lft__gte' => $this->getModel()->lft,
            'rgt__lte' => $this->getModel()->rgt,
            'root' => $this->getModel()->root,
        ])->order(['lft']);

        if (false === $includeSelf) {
            $this->exclude([
                'pk' => $this->getModel()->pk,
            ]);
        }

        if (null !== $depth) {
            $this->filter([
                'level__lte' => $this->getModel()->level + $depth,
            ]);
        }

        return $this;
    }
809317
private function getNodeChildren(array $options)
    {
        /** @noinspection PhpUnusedParameterInspection */
        $options = (new OptionsResolver)->setDefaults([
            'depth'           => 1,
            'refName'         => null,
            'parent'          => null,
            'lang'            => $this->currentLocale->getCurrentLocale(),
            'include_root'    => false,
            'include_hidden'  => false,
            'include_offline' => false,
            'flatten'         => false,
            'limit'           => 0,
        ])
            ->setNormalizer('refName', function ($options, $value) {
                return $value ? (array)$value : [];
            })
            ->setAllowedTypes('parent', ['null', Node::class])
            ->setAllowedTypes('depth', 'integer')
            ->setAllowedTypes('limit', 'integer')
            ->setAllowedTypes('include_root', 'bool')
            ->setAllowedTypes('include_hidden', 'bool')
            ->setAllowedTypes('flatten', 'bool')
            ->resolve($options);

        $qb = $this->nodeRepository
            ->createQueryBuilder('node')
            ->leftJoin('node.nodeTranslations', 'nt', Join::WITH, 'nt.node = node and nt.lang = :lang')
            ->leftJoin('nt.publicNodeVersion', 'nv')
            ->leftJoin('node.parent', 'parent')
            ->select('parent.id as parentId', 'node.id', 'nt.title', 'nt.url', 'nt.lang', 'nv.refId', 'nv.refEntityName', 'node.internalName')
            ->where('nt.lang = :lang')
            ->andWhere('node.deleted = 0')
            ->orderBy('node.lvl, nt.weight')
            ->setParameter('lang', $options['lang']);

        if ($options['limit']) {
            $qb->setMaxResults($options['limit']);
        }

        if (false === $options['include_hidden']) {
            $qb->andWhere('node.hiddenFromNav = 0');
        }

        if (false === $options['include_offline']) {
            $qb->andWhere('nt.online = 1');
        }

        if ($options['refName']) {
            $qb
                ->andWhere('node.refEntityName in (:refName)')
                ->setParameter('refName', $options['refName']);
        }

        $level = 0;
        $nodeId = null;
        if ($options['parent']) {
            /** @var Node $parent */
            $parent = $options['parent'];
            $nodeId = $parent->getId();
            $level = $parent->getLevel();


            $qb->andWhere('node.lft >= :minLeft')
                ->andWhere('node.rgt <= :maxRight')
                ->setParameter('minLeft', $parent->getLeft())
                ->setParameter('maxRight', $parent->getRight());

            if (false === $options['include_root']) {
                $qb->andWhere('node.id != :nodeId')
                    ->setParameter('nodeId', $nodeId);
            }
        }

        if ($options['depth']) {
            $qb->andWhere('node.lvl <= :maxLevel')
                ->setParameter('maxLevel', $level + $options['depth']);
        }

        $children = $qb->getQuery()->getResult();

        $flatten = $options['flatten'];

        /** @noinspection PhpInternalEntityUsedInspection */
        return array_reduce($children, function (TreeBuilder $treeBuilder, $item) use ($nodeId, $flatten) {
            $branch = new Branch($item['title'], $item['id'], $item['url'], $item['lang'], $item['refId'], $item['refEntityName'], $item['internalName']);

            if ($branch->getNodeId() === $nodeId) {
                $item['parentId'] = null;
            } elseif ($flatten) {
                $item['parentId'] = $nodeId;
            }

            return $treeBuilder->add($item['parentId'], $branch);
        }, new TreeBuilder)->getRoot();

    }
380662
protected function arrayDepth($element, $depth = 1) {
        if (is_array($element)) {
            $maxDepth = $depth;
            foreach($element as $el) {
                $d = $this->arrayDepth($el, $depth + 1);
                if ($d > $maxDepth) {
                    $maxDepth = $d;
                }
            }
            return $maxDepth;
        } else {
            return $depth;
        }
    }
310878
public function traverseChildren(Link $sourceUrl, $childLinks, $depth)
    {                
        foreach ($childLinks as $url => $info) {            
            
            $filterCallback = $this->filterCallback;
            $childLink = new Link($url,$sourceUrl);
            $hash = $childLink->getAbsoluteUrl(false);
            $this->links[$hash]  = $childLink;
            
            if ($filterCallback && $filterCallback($url)===false &&
                    isset($this->links[$hash]) === false) {
                    $childLink->setAsShouldVisit(false);
                    $this->log(LogLevel::INFO, 'skipping '.$url.' link not match filter criteria');
                    return;
            }
            if (isset($this->links[$hash]) === false) {
                $this->links[$hash] = $info;
                $childLink->setCrawlDepth($depth);		
            } else {		
                $originalLink = $this->links[$hash];
                $originalLink->addMetaInfo('originalUrls',$childLink->getOriginalUrl());
                $originalLink->addMetaInfo('linksText',$childLink->getMetaInfo('linksText'));                
            }

            $this->childrenByDepth[$depth][$sourceUrl->getAbsoluteUrl(false)][] = $hash;                        
        }
        
    }
443601
public function getSiblings($andSelf = false)
    {
        $tableName = $this->owner->tableName();
        $path = $this->getParentPath();
        $like = strtr($path . $this->delimiter, ['%' => '\%', '_' => '\_', '\\' => '\\\\']);

        $query = $this->owner->find()
            ->andWhere(['like', "{$tableName}.[[{$this->pathAttribute}]]", $like . '%', false])
            ->andWhere(['<=', "{$tableName}.[[{$this->depthAttribute}]]", $this->owner->{$this->depthAttribute}]);

        if (!$andSelf) {
            $query->andWhere(["!=", "{$tableName}.[[{$this->itemAttribute}]]", $this->owner->{$this->itemAttribute}]);
        }

        $orderBy = [];
        $orderBy["{$tableName}.[[{$this->depthAttribute}]]"] = SORT_ASC;
        if ($this->sortable !== false) {
            $orderBy["{$tableName}.[[{$this->behavior->sortAttribute}]]"] = SORT_ASC;
        }
        $orderBy["{$tableName}.[[{$this->itemAttribute}]]"] = SORT_ASC;

        $query
            ->andWhere($this->treeCondition())
            ->addOrderBy($orderBy);
        $query->multiple = true;
        return $query;
    }
250407
public function getDescendants($levelLimit = 0, $includeNode = false)
	{
		$left = $this->getLeftValue();
		$right = $this->getRightValue();
		$level = $this->getLevel();

		$searchCondition = $this->repository->createSearchCondition();
		if ($includeNode) {
			$searchCondition->leftGreaterThanOrEqualsTo($left)
					->rightLessThanOrEqualsTo($right);
		} else {
			$searchCondition->leftGreaterThan($left)
					->rightLessThan($right);
		}

		if ($levelLimit < 0) {
			throw new Exception\Domain("Level limit cannot be negative in getDescendants method");
		} elseif ($levelLimit > 0) {
			$searchCondition->levelLessThanOrEqualsTo($level + $levelLimit);
		}

		$orderRule = $this->repository->createSelectOrderRule()
				->byLeftAscending();

		$descendants = $this->repository->search($searchCondition, $orderRule);
		
		return $descendants;
	}
1039484
function levelsToSelect($levelIds, $mode)
    {
        $levelsToSelect = array();
        foreach ($this->schema->getLevels() as $level) {
            if (self::INCLUDE_PARTIALS == $mode && !$levelIds[$level]) {
                continue;
            }
            if (self::INCLUDE_PARTIALS == $mode && !$levelIds[$level]) {
                continue;
            }
            array_push($levelsToSelect, $level);
        }
        return $levelsToSelect;
    }
480284
protected function getHierarchicalChoicesAttributes($nodes, $depth = 0)
    {
        $choices = array();
        $lastNode = end($nodes);
        foreach ($nodes as $node) {
            $choices[$node['node']['nodeId']] = array(
                'data-depth' => $depth,
                'data-last' => $node === $lastNode,
            );
            if (array_key_exists('child', $node)) {
                $choices = array_merge($choices, $this->getHierarchicalChoicesAttributes($node['child'], $depth + 1));
            }
        }

        return $choices;

    }
423679
private function getValidatedIncludes(iterable $includesFromParent): iterable
    {
        $ruleIndexes = $this->serializerClass::readIncludesRuleIndexes($this->getSerializedRuleSet());

        if ($ruleIndexes === null) {
            // without validation
            foreach ($includesFromParent as $path => $split) {
                yield $path => $split;
            }
        } else {
            // with validation
            $ruleIndex = $this->serializerClass::readRuleMainIndex($ruleIndexes);
            $this->validationStarts(static::PARAM_INCLUDE, $ruleIndexes);
            foreach ($includesFromParent as $path => $split) {
                $this->getCaptures()->clear();
                $this->validateAndAccumulateError($path, $ruleIndex);
                if ($this->getCaptures()->count() > 0) {
                    yield $this->readSingleCapturedValue() => $split;
                }
            }
            $this->validateEnds(static::PARAM_INCLUDE, $ruleIndexes);
        }
    }
689561
public function get_parent_contexts($includeself = false) {
        if (!$contextids = $this->get_parent_context_ids($includeself)) {
            return array();
        }

        // Preload the contexts to reduce DB calls.
        context_helper::preload_contexts_by_id($contextids);

        $result = array();
        foreach ($contextids as $contextid) {
            $parent = context::instance_by_id($contextid, MUST_EXIST);
            $result[$parent->id] = $parent;
        }

        return $result;
    }
553173
private function checkInclude($include,$deep = false){
		if (is_string($include)){
			$include = array($include);
		}
		$include = Hash::normalize($include);

		foreach($include as $key => $val){
			$val = Hash::merge($this->includeDef,$val);
			// if Embed in config is true all include array set true
			if($this->config['embed']){
				$val['embed'] = true;
			}
			if ($val['include']){
				$val['include'] = $this->checkInclude($val['include'],true);
			}
			$include[$key] = $val;

		}
		
		
		if (!$deep){
			$this->include = $include;
		}
    	return $include;
	}
1336986
function modes($includeSelf = true, $unique = false) {
		$rotateme = $this->scale;
		$modes = array();

		$modes[] = $this->scale;

		for ($i = 0; $i < 11; $i++) {
			$rotateme = BitmaskUtils::rotateBitmask($rotateme);
			if (($rotateme & 1) == 0) {
				continue;
			}
			if ($rotateme == $this->scale) {
				break;
			}

			// if (!$includeSelf && $rotateme != $this->scale) {
				$modes[] = $rotateme;
			// }
		}

		// // take self off the end and put it at the start
		// $end = array_pop($modes);
		// array_unshift($modes, $end);

		// // remove self if it's not wanted
		if (!$includeSelf) {
			array_shift($modes);
		}

		if ($unique) {
			$modes = array_unique($modes);
		}

		return $modes;
	}
454800
public function getChildren(Node $node, $includeHiddenFromNav = true)
    {
        $this->init();
        $children = array();

        if (array_key_exists($node->getId(), $this->childNodes)) {
            $nodes = $this->childNodes[$node->getId()];
            /* @var Node $childNode */
            foreach ($nodes as $childNode) {
                $nodeTranslation = $childNode->getNodeTranslation(
                    $this->locale,
                    $this->includeOffline
                );
                if (!is_null($nodeTranslation)) {
                    $children[] = new NodeMenuItem(
                        $childNode,
                        $nodeTranslation,
                        false,
                        $this
                    );
                }
            }

            $children = array_filter(
                $children,
                function (NodeMenuItem $entry) use ($includeHiddenFromNav) {
                    if ($entry->getNode()->isHiddenFromNav(
                        ) && !$includeHiddenFromNav
                    ) {
                        return false;
                    }

                    return true;
                }
            );
        }

        return $children;
    }
671571
public function getChildren($includeDeleted = false)
    {
        if ($includeDeleted) {
            return $this->children;
        }

        return $this->children->filter(function (Folder $entry) {
            if ($entry->isDeleted()) {
                return false;
            }

            return true;
        });
    }
193399
protected function getIncluded(ElementInterface $element, $includeParent = false)
    {
        $included = [];

        foreach ($element->getResources() as $resource) {
            if ($resource->isIdentifier()) {
                continue;
            }

            if ($includeParent) {
                $included = $this->mergeResource($included, $resource);
            } else {
                $type = $resource->getType();
                $id = $resource->getId();
            }

            foreach ($resource->getUnfilteredRelationships() as $relationship) {
                $includedElement = $relationship->getData();

                if (! $includedElement instanceof ElementInterface) {
                    continue;
                }

                foreach ($this->getIncluded($includedElement, true) as $child) {
                    // If this resource is the same as the top-level "data"
                    // resource, then we don't want it to show up again in the
                    // "included" array.
                    if (! $includeParent && $child->getType() === $type && $child->getId() === $id) {
                        continue;
                    }

                    $included = $this->mergeResource($included, $child);
                }
            }
        }

        $flattened = [];

        array_walk_recursive($included, function ($a) use (&$flattened) {
            $flattened[] = $a;
        });

        return $flattened;
    }
1045974
public function limit($var, $depth, array &$references = [])
    {
        if ($depth > $this->depthLimit) {
            return '*DEPTH LIMIT*';
        }

        if (is_array($var)) {
            return $this->limitArray($var, $depth, $references);
        }

        if (is_object($var)) {
            return $this->limitObject($var, $depth, $references);
        }

        return $var;
    }
695945
public function parse_recursive(DOMElement $context = null, $depth = 0) {
		$mfs = array();
		$mfElements = $this->getRootMF($context);

		foreach ($mfElements as $node) {
			$is_backcompat = !$this->hasRootMf2($node);

			if ($this->convertClassic && $is_backcompat) {
				$this->backcompat($node);
			}

			$recurse = $this->parse_recursive($node, $depth + 1);

			// set bool flag for nested mf
			$has_nested_mf = ($recurse);

			// parse for root mf
			$result = $this->parseH($node, $is_backcompat, $has_nested_mf);

			// TODO: Determine if clearing this is required?
			$this->elementPrefixParsed($node, 'h');
			$this->elementPrefixParsed($node, 'p');
			$this->elementPrefixParsed($node, 'u');
			$this->elementPrefixParsed($node, 'dt');
			$this->elementPrefixParsed($node, 'e');

			// parseH returned a parsed result
			if ($result) {

				// merge recursive results into current results
				if ($recurse) {
					$result = array_merge_recursive($result, $recurse);
				}

				// currently a nested mf; check if node is an mf property of parent
				if ($depth > 0) {
					$temp_properties = nestedMfPropertyNamesFromElement($node);

					// properties found; set up parsed result in 'properties'
					if (!empty($temp_properties)) {

						foreach ($temp_properties as $property => $prefixes) {
							// Note: handling microformat nesting under multiple conflicting prefixes is not currently specified by the mf2 parsing spec.
							$prefixSpecificResult = $result;
							if (in_array('p-', $prefixes)) {
								$prefixSpecificResult['value'] = (!is_array($prefixSpecificResult['properties']) || empty($prefixSpecificResult['properties']['name'][0])) ? $this->parseP($node) : $prefixSpecificResult['properties']['name'][0];
							} elseif (in_array('e-', $prefixes)) {
								$eParsedResult = $this->parseE($node);
								$prefixSpecificResult['html'] = $eParsedResult['html'];
								$prefixSpecificResult['value'] = $eParsedResult['value'];
							} elseif (in_array('u-', $prefixes)) {
								$prefixSpecificResult['value'] = (!is_array($result['properties']) || empty($result['properties']['url'])) ? $this->parseU($node) : reset($result['properties']['url']);
							} elseif (in_array('dt-', $prefixes)) {
								$parsed_property = $this->parseDT($node);
								$prefixSpecificResult['value'] = ($parsed_property) ? $parsed_property : '';
							}

							$mfs['properties'][$property][] = $prefixSpecificResult;
						}

					// otherwise, set up in 'children'
					} else {
						$mfs['children'][] = $result;
					}
				// otherwise, top-level mf
				} else {
					$mfs[] = $result;
				}
			}
		}

		return $mfs;
	}