-
-
Save voku/3aba12eb898dfa209a787c398a331f9c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
declare(strict_types=1); | |
use PhpCsFixer\Preg; | |
use PhpCsFixer\Tokenizer\Token; | |
use PhpCsFixer\Tokenizer\Tokens; | |
require_once __DIR__ . '/AbstractVdmgFixerHelper.php'; | |
final class VdmgFactoryDoctypeFixer extends AbstractVdmgFixerHelper { | |
/** | |
* @var string | |
*/ | |
private $className = ''; | |
/** | |
* @var string | |
*/ | |
private $parentClassName = ''; | |
/** | |
* @var string[] | |
*/ | |
private $foundMethods = []; | |
/** | |
* @param SplFileInfo $file | |
* @param Token[]|Tokens $tokens | |
* | |
* @return void | |
*/ | |
public function applyFix(\SplFileInfo $file, Tokens $tokens): void { | |
// init | |
$this->className = null; | |
foreach ($tokens as $index => $token) { | |
if (!$token->isGivenKind(\T_EXTENDS)) { | |
continue; | |
} | |
$this->parentClassName = $this->getParentClassName($tokens, $index); | |
if (!$this->isFactory($tokens, $index)) { | |
continue; | |
} | |
$classNamePosition = (int)$tokens->getPrevMeaningfulToken($index); | |
$classNameToken = $tokens[$classNamePosition]; | |
$this->className = $classNameToken->getContent(); | |
} | |
if (!$this->className) { | |
return; | |
} | |
$specialClasses = [ | |
ManagedFactoryVertragsDB::class, | |
ManagedTreeFactory::class, | |
ManagedTreeNetworkFactory::class, | |
]; | |
if (in_array($this->className, $specialClasses, true)) { | |
return; | |
} | |
// init | |
$this->foundMethods = []; | |
if ( | |
$this->parentClassName == ManagedTreeFactory::class | |
|| | |
$this->parentClassName == ManagedTreeNetworkFactory::class | |
) { | |
$this->foundMethods['fetchRoots'] = false; | |
$this->foundMethods['fetchChildrenById'] = false; | |
$this->foundMethods['fetchAllChildrenById'] = false; | |
$this->foundMethods['fetchLeafsById'] = false; | |
$this->foundMethods['fetchLeafsByIdYield'] = false; | |
$this->foundMethods['fetchParentsById'] = false; | |
} | |
$this->foundMethods['fetchEmpty'] = false; | |
$this->foundMethods['fetchAll'] = false; | |
$this->foundMethods['fetchAllYield'] = false; | |
$this->foundMethods['fetchByIds'] = false; | |
$this->foundMethods['fetchById'] = false; | |
$this->foundMethods['fetchByIdWithStaticCache'] = false; | |
$this->foundMethods['fetchByIdIfExists'] = false; | |
$this->foundMethods['fetchByIdIfExistsWithStaticCache'] = false; | |
$this->foundMethods['fetchByQuery'] = false; | |
$this->foundMethods['fetchByQueryWithStaticCache'] = false; | |
$this->foundMethods['fetchByQueryYield'] = false; | |
$this->foundMethods['fetchByQueryPrimaryKeyAsArrayIndex'] = false; | |
$this->foundMethods['fetchOneByQuery'] = false; | |
$this->foundMethods['fetchOneOrThrowExceptionByQuery'] = false; | |
$this->foundMethods['fetchAllPrimaryKeyAsArrayIndex'] = false; | |
$this->foundMethods['fetchByIdsPrimaryKeyAsArrayIndex'] = false; | |
$this->foundMethods['createFromArray'] = false; | |
$this->foundMethods['fetchFirst'] = false; | |
$this->foundMethods['fetchLast'] = false; | |
$this->foundMethods['delete'] = false; | |
$this->foundMethods['insert'] = false; | |
$this->foundMethods['update'] = false; | |
$this->foundMethods['replace'] = false; | |
$this->foundMethods['construct'] = false; | |
foreach ($tokens as $index => $token) { | |
if (!$token->isGivenKind(\T_FUNCTION)) { | |
if (isset($tokens[$index - 1])) { | |
$prevContent = $tokens[$index - 1]->getContent(); | |
if ($prevContent == '->') { | |
continue; | |
} | |
if ($prevContent == '::') { | |
continue; | |
} | |
} | |
switch ($tokens[(int)$index]->getContent()) { | |
case 'fetchEmpty': | |
$this->foundMethods['fetchEmpty'] = true; | |
break; | |
case 'fetchAll': | |
$this->foundMethods['fetchAll'] = true; | |
break; | |
case 'fetchAllYield': | |
$this->foundMethods['fetchAllYield'] = true; | |
break; | |
case 'fetchByIds': | |
$this->foundMethods['fetchByIds'] = true; | |
break; | |
case 'fetchById': | |
$this->foundMethods['fetchById'] = true; | |
break; | |
case 'fetchByIdWithStaticCache': | |
$this->foundMethods['fetchByIdWithStaticCache'] = true; | |
break; | |
case 'fetchByIdIfExists': | |
$this->foundMethods['fetchByIdIfExists'] = true; | |
break; | |
case 'fetchByIdIfExistsWithStaticCache': | |
$this->foundMethods['fetchByIdIfExistsWithStaticCache'] = true; | |
break; | |
case 'fetchByQuery': | |
$this->foundMethods['fetchByQuery'] = true; | |
break; | |
case 'fetchByQueryWithStaticCache': | |
$this->foundMethods['fetchByQueryWithStaticCache'] = true; | |
break; | |
case 'fetchByQueryYield': | |
$this->foundMethods['fetchByQueryYield'] = true; | |
break; | |
case 'fetchByQueryPrimaryKeyAsArrayIndex': | |
$this->foundMethods['fetchByQueryPrimaryKeyAsArrayIndex'] = true; | |
break; | |
case 'fetchOneByQuery': | |
$this->foundMethods['fetchOneByQuery'] = true; | |
break; | |
case 'fetchOneOrThrowExceptionByQuery': | |
$this->foundMethods['fetchOneOrThrowExceptionByQuery'] = true; | |
break; | |
case 'fetchAllPrimaryKeyAsArrayIndex': | |
$this->foundMethods['fetchAllPrimaryKeyAsArrayIndex'] = true; | |
break; | |
case 'fetchByIdsPrimaryKeyAsArrayIndex': | |
$this->foundMethods['fetchByIdsPrimaryKeyAsArrayIndex'] = true; | |
break; | |
case 'createFromArray': | |
$this->foundMethods['createFromArray'] = true; | |
break; | |
case 'fetchFirst': | |
$this->foundMethods['fetchFirst'] = true; | |
break; | |
case 'fetchLast': | |
$this->foundMethods['fetchLast'] = true; | |
break; | |
case 'delete': | |
$this->foundMethods['delete'] = true; | |
break; | |
case 'insert': | |
$this->foundMethods['insert'] = true; | |
break; | |
case 'update': | |
$this->foundMethods['update'] = true; | |
break; | |
case 'replace': | |
$this->foundMethods['replace'] = true; | |
break; | |
case 'construct': | |
$this->foundMethods['construct'] = true; | |
break; | |
default: | |
// nothing | |
break; | |
} | |
if ( | |
$this->parentClassName == ManagedTreeFactory::class | |
|| | |
$this->parentClassName == ManagedTreeNetworkFactory::class | |
) { | |
switch ($tokens[(int)$index]->getContent()) { | |
case 'fetchRoots': | |
$this->foundMethods['fetchRoots'] = true; | |
break; | |
case 'fetchChildrenById': | |
$this->foundMethods['fetchChildrenById'] = true; | |
break; | |
case 'fetchAllChildrenById': | |
$this->foundMethods['fetchAllChildrenById'] = true; | |
break; | |
case 'fetchLeafsById': | |
$this->foundMethods['fetchLeafsById'] = true; | |
break; | |
case 'fetchLeafsByIdYield': | |
$this->foundMethods['fetchLeafsByIdYield'] = true; | |
break; | |
case 'fetchParentsById': | |
$this->foundMethods['fetchParentsById'] = true; | |
break; | |
default: | |
// nothing | |
break; | |
} | |
} | |
} | |
} | |
// figure out where the comment should be placed | |
$headerNewIndex = $this->findHeaderCommentInsertionIndex($tokens); | |
// check if there is already a comment | |
$headerCurrentIndex = $this->findHeaderCommentCurrentIndex($tokens, $headerNewIndex - 1); | |
if ($headerCurrentIndex === null) { | |
$this->insertHeader($tokens, $headerNewIndex); | |
} elseif ($this->getHeaderAsComment() !== $tokens[$headerCurrentIndex]->getContent()) { | |
$tokens->clearTokenAndMergeSurroundingWhitespace($headerCurrentIndex); | |
$this->insertHeader($tokens, $headerNewIndex); | |
} else { | |
$headerNewIndex = $headerCurrentIndex; | |
} | |
$this->fixWhiteSpaceAroundHeader($tokens, $headerNewIndex); | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function getDocumentation(): string { | |
return 'Extended "Factory" (& ManagedFactory ...) needs some extra @method phpdocs.'; | |
} | |
/** | |
* Run after other class name fixes etc. .... | |
*/ | |
public function getPriority(): int { | |
return -50; | |
} | |
/** | |
* {@inheritdoc} | |
* | |
* @noinspection AutoloadingIssuesInspection | |
* @noinspection EmptyClassInspection | |
*/ | |
public function getSampleCode(): string { | |
return <<<'PHP' | |
<?php | |
class TenderFactory extends ManagedFactory { | |
} | |
PHP; | |
} | |
/** | |
* @param Token[]|Tokens $tokens | |
* | |
* @return bool | |
*/ | |
public function isCandidate(Tokens $tokens): bool { | |
return $tokens->isAllTokenKindsFound([\T_CLASS, \T_EXTENDS, \T_STRING]); | |
} | |
/** | |
* @param Token[]|Tokens $tokens | |
* @param int $headerNewIndex | |
* | |
* @return null|int | |
*/ | |
private function findHeaderCommentCurrentIndex(Tokens $tokens, $headerNewIndex) { | |
$index = $tokens->getNextNonWhitespace($headerNewIndex); | |
return $index === null || !$tokens[(int)$index]->isComment() ? null : $index; | |
} | |
/** | |
* Find the index where the header comment must be inserted. | |
* | |
* @param Token[]|Tokens $tokens | |
* | |
* @return int | |
*/ | |
private function findHeaderCommentInsertionIndex(Tokens $tokens): int { | |
$index = $tokens->getNextMeaningfulToken(0); | |
if ($index === null) { | |
// file without meaningful tokens but an open tag, comment should always be placed directly after the open tag | |
return 1; | |
} | |
if (!$tokens[(int)$index]->isGivenKind(\T_DECLARE)) { | |
return 1; | |
} | |
$next = $tokens->getNextMeaningfulToken($index); | |
if ($next === null || !$tokens[(int)$next]->equals('(')) { | |
return 1; | |
} | |
$next = $tokens->getNextMeaningfulToken($next); | |
if ($next === null || !$tokens[(int)$next]->equals([\T_STRING, 'strict_types'], false)) { | |
return 1; | |
} | |
$next = $tokens->getNextMeaningfulToken($next); | |
if ($next === null || !$tokens[(int)$next]->equals('=')) { | |
return 1; | |
} | |
$next = $tokens->getNextMeaningfulToken($next); | |
if ($next === null || !$tokens[(int)$next]->isGivenKind(\T_LNUMBER)) { | |
return 1; | |
} | |
$next = $tokens->getNextMeaningfulToken($next); | |
if ($next === null || !$tokens[(int)$next]->equals(')')) { | |
return 1; | |
} | |
$next = $tokens->getNextMeaningfulToken($next); | |
if ($next === null || !$tokens[(int)$next]->equals(';')) { // don't insert after close tag | |
return 1; | |
} | |
return $next + 1; | |
} | |
/** | |
* @param Token[]|Tokens $tokens | |
* @param int $headerIndex | |
*/ | |
private function fixWhiteSpaceAroundHeader(Tokens $tokens, $headerIndex): void { | |
$lineEnding = "\n"; | |
// fix lines after header comment | |
$expectedLineCount = 2; | |
if ($headerIndex === \count($tokens) - 1) { | |
$tokens->insertAt( | |
$headerIndex + 1, | |
new Token( | |
[ | |
\T_WHITESPACE, | |
\str_repeat($lineEnding, $expectedLineCount), | |
] | |
) | |
); | |
} else { | |
$afterCommentIndex = $tokens->getNextNonWhitespace($headerIndex); | |
$lineBreakCount = $this->getLineBreakCount($tokens, $headerIndex + 1, $afterCommentIndex ?? count($tokens)); | |
if ($lineBreakCount < $expectedLineCount) { | |
$missing = \str_repeat($lineEnding, $expectedLineCount - $lineBreakCount); | |
if ($tokens[$headerIndex + 1]->isWhitespace()) { | |
$tokens[$headerIndex + 1] = new Token( | |
[ | |
\T_WHITESPACE, | |
$missing . $tokens[$headerIndex + 1]->getContent(), | |
] | |
); | |
} else { | |
$tokens->insertAt($headerIndex + 1, new Token([\T_WHITESPACE, $missing])); | |
} | |
} elseif ($lineBreakCount > 2) { | |
// remove extra line endings | |
if ($tokens[$headerIndex + 1]->isWhitespace()) { | |
$tokens[$headerIndex + 1] = new Token([\T_WHITESPACE, $lineEnding . $lineEnding]); | |
} | |
} | |
} | |
// fix lines before header comment | |
$expectedLineCount = 2; | |
$prev = $tokens->getPrevNonWhitespace($headerIndex); | |
$regex = '/[\t ]$/'; | |
if ($prev && $tokens[(int)$prev]->isGivenKind(\T_OPEN_TAG) && Preg::match($regex, $tokens[(int)$prev]->getContent())) { | |
$tokens[(int)$prev] = new Token( | |
[ | |
\T_OPEN_TAG, | |
Preg::replace($regex, $lineEnding, $tokens[(int)$prev]->getContent()), | |
] | |
); | |
} | |
$lineBreakCount = $this->getLineBreakCount($tokens, $prev, $headerIndex); | |
if ($lineBreakCount < $expectedLineCount) { | |
// because of the way the insert index was determined for header comment there cannot be an empty token here | |
$tokens->insertAt( | |
$headerIndex, | |
new Token( | |
[ | |
\T_WHITESPACE, | |
\str_repeat($lineEnding, $expectedLineCount - $lineBreakCount), | |
] | |
) | |
); | |
} | |
} | |
/** | |
* @return mixed | |
*/ | |
private function getActiveRecordName() { | |
return \str_replace('Factory', '', $this->className); | |
} | |
/** | |
* Enclose the given text in a comment block. | |
* | |
* @return string | |
*/ | |
private function getHeaderAsComment(): string { | |
$activeRecordName = $this->getActiveRecordName(); | |
// init | |
$lines = []; | |
if ($this->foundMethods['fetchEmpty'] === false) { | |
$lines['fetchEmpty'] = ' * @method ' . $activeRecordName . ' fetchEmpty()'; | |
} | |
if ($this->foundMethods['fetchAll'] === false) { | |
$lines['fetchAll'] = ' * @method ' . $activeRecordName . '[] fetchAll(int $limit = null, int $offset = null, bool $sharded = false)'; | |
} | |
if ($this->foundMethods['fetchAllYield'] === false) { | |
$lines['fetchAllYield'] = ' * @method Generator|' . $activeRecordName . '[] fetchAllYield(int $limit = null, int $offset = null, bool $sharded = false)'; | |
} | |
if ($this->foundMethods['fetchByIds'] === false) { | |
$lines['fetchByIds'] = ' * @method ' . $activeRecordName . '[] fetchByIds(int[]|string[] $ids)'; | |
} | |
if ($this->foundMethods['fetchById'] === false) { | |
$lines['fetchById'] = ' * @method ' . $activeRecordName . ' fetchById(int|string $id)'; | |
} | |
if ($this->foundMethods['fetchByIdWithStaticCache'] === false) { | |
$lines['fetchByIdWithStaticCache'] = ' * @method ' . $activeRecordName . ' fetchByIdWithStaticCache(int|string $id)'; | |
} | |
if ($this->foundMethods['fetchByIdIfExists'] === false) { | |
$lines['fetchByIdIfExists'] = ' * @method null|' . $activeRecordName . ' fetchByIdIfExists(int|string $id)'; | |
} | |
if ($this->foundMethods['fetchByIdIfExistsWithStaticCache'] === false) { | |
$lines['fetchByIdIfExistsWithStaticCache'] = ' * @method null|' . $activeRecordName . ' fetchByIdIfExistsWithStaticCache(int|string $id)'; | |
} | |
if ($this->foundMethods['fetchByQuery'] === false) { | |
$lines['fetchByQuery'] = ' * @method ' . $activeRecordName . '[] fetchByQuery(string $query, bool $sharded = false, bool $remote = false, null|DatabaseConnection $db = null)'; | |
} | |
if ($this->foundMethods['fetchByQueryWithStaticCache'] === false) { | |
$lines['fetchByQueryWithStaticCache'] = ' * @method ' . $activeRecordName . '[] fetchByQueryWithStaticCache(string $query, bool $sharded = false, bool $remote = false, null|DatabaseConnection $db = null)'; | |
} | |
if ($this->foundMethods['fetchByQueryYield'] === false) { | |
$lines['fetchByQueryYield'] = ' * @method Generator|' . $activeRecordName . '[] fetchByQueryYield(string $query, bool $sharded = false, bool $remote = false, null|DatabaseConnection $db = null)'; | |
} | |
if ($this->foundMethods['fetchByQueryPrimaryKeyAsArrayIndex'] === false) { | |
$lines['fetchByQueryPrimaryKeyAsArrayIndex'] = ' * @method ' . $activeRecordName . '[] fetchByQueryPrimaryKeyAsArrayIndex(string $query, string $primaryKeyName, bool $sharded = false)'; | |
} | |
if ($this->foundMethods['fetchOneByQuery'] === false) { | |
$lines['fetchOneByQuery'] = ' * @method null|' . $activeRecordName . ' fetchOneByQuery(string $query, bool $sharded = false, bool $remote = false, null|DatabaseConnection $db = null)'; | |
} | |
if ($this->foundMethods['fetchOneOrThrowExceptionByQuery'] === false) { | |
$lines['fetchOneOrThrowExceptionByQuery'] = ' * @method ' . $activeRecordName . ' fetchOneOrThrowExceptionByQuery(string $query, bool $sharded = false, bool $remote = false, null|DatabaseConnection $db = null)'; | |
} | |
if ($this->foundMethods['fetchAllPrimaryKeyAsArrayIndex'] === false) { | |
$lines['fetchAllPrimaryKeyAsArrayIndex'] = ' * @method ' . $activeRecordName . '[] fetchAllPrimaryKeyAsArrayIndex(int $limit = null, int $offset = null, bool $sharded = false)'; | |
} | |
if ($this->foundMethods['fetchByIdsPrimaryKeyAsArrayIndex'] === false) { | |
$lines['fetchByIdsPrimaryKeyAsArrayIndex'] = ' * @method ' . $activeRecordName . '[] fetchByIdsPrimaryKeyAsArrayIndex(int[]|string[] $ids)'; | |
} | |
if ($this->foundMethods['createFromArray'] === false) { | |
$lines['createFromArray'] = ' * @method ' . $activeRecordName . ' createFromArray(array $data, bool $insert = true)'; | |
} | |
if ($this->foundMethods['fetchFirst'] === false) { | |
$lines['fetchFirst'] = ' * @method null|' . $activeRecordName . ' fetchFirst()'; | |
} | |
if ($this->foundMethods['fetchLast'] === false) { | |
$lines['fetchLast'] = ' * @method null|' . $activeRecordName . ' fetchLast()'; | |
} | |
if ($this->foundMethods['delete'] === false) { | |
$lines['delete'] = ' * @method bool delete(' . $activeRecordName . ' $activeRow)'; | |
} | |
if ($this->foundMethods['insert'] === false) { | |
$lines['insert'] = ' * @method int insert(' . $activeRecordName . ' $activeRow)'; | |
} | |
if ($this->foundMethods['update'] === false) { | |
$lines['update'] = ' * @method bool update(' . $activeRecordName . ' $activeRow)'; | |
} | |
if ($this->foundMethods['replace'] === false) { | |
$lines['replace'] = ' * @method int replace(' . $activeRecordName . ' $activeRow)'; | |
} | |
if ($this->foundMethods['construct'] === false) { | |
$lines['construct'] = ' * @method ' . $activeRecordName . ' construct(array &$row)'; | |
} | |
if ( | |
$this->parentClassName == ManagedTreeFactory::class | |
|| | |
$this->parentClassName == ManagedTreeNetworkFactory::class | |
) { | |
if ($this->foundMethods['fetchRoots'] === false) { | |
$lines['fetchRoots'] = ' * @method ' . $activeRecordName . ' fetchRoots()'; | |
} | |
if ($this->foundMethods['fetchChildrenById'] === false) { | |
$lines['fetchChildrenById'] = ' * @method ' . $activeRecordName . '[] fetchChildrenById($id)'; | |
} | |
if ($this->foundMethods['fetchAllChildrenById'] === false) { | |
$lines['fetchAllChildrenById'] = ' * @method ' . $activeRecordName . '[] fetchAllChildrenById($id, bool $includeRoot = false)'; | |
} | |
if ($this->foundMethods['fetchLeafsById'] === false) { | |
$lines['fetchLeafsById'] = ' * @method ' . $activeRecordName . '[] fetchLeafsById($id)'; | |
} | |
if ($this->foundMethods['fetchLeafsByIdYield'] === false) { | |
$lines['fetchLeafsByIdYield'] = ' * @method Generator|' . $activeRecordName . '[] fetchLeafsByIdYield($id)'; | |
} | |
if ($this->foundMethods['fetchParentsById'] === false) { | |
$lines['fetchParentsById'] = ' * @method ' . $activeRecordName . '[] fetchParentsById($id)'; | |
} | |
if ($this->foundMethods['delete'] === false) { | |
$lines['delete'] = ' * @method bool delete(' . $activeRecordName . ' $activeRow, bool $buildTree = true)'; | |
} | |
if ($this->foundMethods['insert'] === false) { | |
$lines['insert'] = ' * @method int insert(' . $activeRecordName . ' $activeRow, bool $buildTree = true)'; | |
} | |
if ($this->foundMethods['update'] === false) { | |
$lines['update'] = ' * @method bool update(' . $activeRecordName . ' $activeRow, bool $buildTree = true)'; | |
} | |
} | |
return '/** | |
' . implode("\n", $lines) . ' | |
* | |
* // info: description is in the ActiveRecord class | |
* | |
* @see ' . $activeRecordName . ' | |
* | |
* // warning -> do not edit by hand, auto-generated via: | |
* // cd ~/vdmg/ && make apply-php-cs-factory-doc-type-fixer | |
* | |
* @extends ' . $this->parentClassName . '<' . $activeRecordName . '> | |
*/'; | |
} | |
/** | |
* @param Token[]|Tokens $tokens | |
* @param int $indexStart | |
* @param int $indexEnd | |
* | |
* @return int | |
*/ | |
private function getLineBreakCount(Tokens $tokens, $indexStart, $indexEnd): int { | |
$lineCount = 0; | |
for ($i = $indexStart; $i < $indexEnd; ++$i) { | |
$lineCount += \substr_count($tokens[$i]->getContent(), "\n"); | |
} | |
return $lineCount; | |
} | |
/** | |
* @param Token[]|Tokens $tokens | |
* @param int $index | |
* | |
* @return null|string | |
*/ | |
private function getParentClassName(Tokens $tokens, $index) { | |
$parentClassNamePosition = $tokens->getNextMeaningfulToken($index); | |
if ($parentClassNamePosition === null) { | |
return null; | |
} | |
$parentClassNameToken = $tokens[(int)$parentClassNamePosition]; | |
return (string)$parentClassNameToken->getContent(); | |
} | |
/** | |
* @param Token[]|Tokens $tokens | |
* @param int $index | |
*/ | |
private function insertHeader(Tokens $tokens, $index): void { | |
$tokens->insertAt( | |
$index, | |
new Token( | |
[ | |
\T_DOC_COMMENT, | |
$this->getHeaderAsComment(), | |
] | |
) | |
); | |
} | |
/** | |
* @param Token[]|Tokens $tokens | |
* @param int $index | |
* | |
* @return bool | |
*/ | |
private function isFactory(Tokens $tokens, $index): bool { | |
$parentClassName = $this->getParentClassName($tokens, $index); | |
return \strpos($parentClassName, ManagedFactory::class) !== false | |
|| | |
\strpos($parentClassName, ManagedTreeFactory::class) !== false | |
|| | |
\strpos($parentClassName, ManagedTreeNetworkFactory::class) !== false; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment