diff --git a/commands/SearchController.php b/commands/SearchController.php index 47670c0c..91a399d1 100644 --- a/commands/SearchController.php +++ b/commands/SearchController.php @@ -7,6 +7,7 @@ use app\models\Extension; use app\models\News; use app\models\search\SearchActiveRecord; +use app\models\search\SearchApiPrimitive; use app\models\search\SearchApiType; use app\models\search\SearchExtension; use app\models\search\SearchGuideSection; @@ -129,6 +130,7 @@ public function actionRebuild(array $items = ['guide', 'api', 'extension', 'wiki // guide and API objects are expected to not disappear // SearchGuideSection::deleteAll(); SearchApiType::setMappings(); + SearchApiPrimitive::setMappings(); $this->rebuildApiIndex(); break; case 'extension': diff --git a/models/search/SearchActiveRecord.php b/models/search/SearchActiveRecord.php index 5c52811c..be7ffaf5 100644 --- a/models/search/SearchActiveRecord.php +++ b/models/search/SearchActiveRecord.php @@ -78,7 +78,7 @@ public static function search($queryString, $version = null, $language = null, $ if ($type === null) { $types = [ SearchApiType::TYPE, - // SearchApiPrimitive::TYPE, + SearchApiPrimitive::TYPE, SearchGuideSection::TYPE, SearchWiki::TYPE, SearchExtension::TYPE, @@ -87,7 +87,7 @@ public static function search($queryString, $version = null, $language = null, $ } elseif (in_array($type, [self::SEARCH_WIKI, self::SEARCH_EXTENSION, self::SEARCH_NEWS], true)) { $types = [$type]; } elseif ($type === self::SEARCH_API) { - $types = [SearchApiType::TYPE,/* SearchApiPrimitive::TYPE,*/]; + $types = [SearchApiType::TYPE, SearchApiPrimitive::TYPE]; } elseif ($type === self::SEARCH_GUIDE) { // TODO add possibility to search for guide subsections: https://github.com/yiisoft-contrib/yiiframework.com/issues/228 $types = [SearchGuideSection::TYPE]; @@ -238,7 +238,7 @@ public static function searchAsYouType($queryString, $version = null, $language $types = [ SearchApiType::TYPE, - // SearchApiPrimitive::TYPE, + SearchApiPrimitive::TYPE, SearchGuideSection::TYPE, SearchWiki::TYPE, SearchExtension::TYPE, diff --git a/models/search/SearchApiPrimitive.php b/models/search/SearchApiPrimitive.php index bc530bf3..fd8841ff 100644 --- a/models/search/SearchApiPrimitive.php +++ b/models/search/SearchApiPrimitive.php @@ -92,7 +92,7 @@ public static function index() /** * * @param SearchApiType $parent - * @param MethodDoc|PropertyDoc|ConstDoc|EventDoc $primitive + * @param array $primitive array data from API documentation * @param $version */ public static function createRecord($parent, $primitive, $version) @@ -100,70 +100,58 @@ public static function createRecord($parent, $primitive, $version) /** @var SearchApiPrimitive $model */ $model = new static(); $model->version = $version; - $model->name = $primitive->name; + $model->name = $primitive['name'] ?? ''; $model->parentId = $parent->get_id(); - $model->shortDescription = $primitive->shortDescription; - $model->description = $primitive->description; - $model->since = $primitive->since; - $model->deprecatedSince = $primitive->deprecatedSince; - $model->deprecatedReason = $primitive->deprecatedReason; - $model->definedBy = $primitive->definedBy; - - if ($primitive instanceof MethodDoc) { + $model->shortDescription = $primitive['shortDescription'] ?? ''; + $model->description = isset($primitive['description']) ? static::filterHtml($primitive['description']) : ''; + $model->since = $primitive['since'] ?? null; + $model->deprecatedSince = $primitive['deprecatedSince'] ?? null; + $model->deprecatedReason = $primitive['deprecatedReason'] ?? null; + $model->definedBy = $primitive['definedBy'] ?? ($parent->namespace ? $parent->namespace . '\\' . $parent->name : $parent->name); + + // Determine type from the primitive data structure + if (isset($primitive['params']) || isset($primitive['return'])) { $model->type = 'method'; - - $model->visibility = $primitive->visibility; - $model->isStatic = $primitive->isStatic; - $model->isAbstract = $primitive->isAbstract; - $model->isFinal = $primitive->isFinal; - - $params = []; - foreach($primitive->params as $param) { - $params[] = [ - 'name' => $param->name, - 'description' => $param->description, - 'isOptional' => $param->isOptional, - 'defaultValue' => $param->defaultValue, - 'isPassedByReference' => $param->isPassedByReference, - 'typeHint' => $param->typeHint, - 'types' => $param->types, - ]; - } - $model->params = $params; - - $exceptions = []; - foreach($primitive->exceptions as $name => $description) { - $exceptions[] = [ - 'name' => $name, - 'description' => $description, - ]; - } - $model->exceptions = $exceptions; - - $model->return = $primitive->return; - $model->returnTypes = $primitive->returnTypes; - $model->isReturnByReference = $primitive->isReturnByReference; - } elseif ($primitive instanceof PropertyDoc) { + + $model->visibility = $primitive['visibility'] ?? 'public'; + $model->isStatic = $primitive['isStatic'] ?? false; + $model->isAbstract = $primitive['isAbstract'] ?? false; + $model->isFinal = $primitive['isFinal'] ?? false; + + $model->params = $primitive['params'] ?? []; + $model->exceptions = $primitive['exceptions'] ?? []; + $model->return = $primitive['return'] ?? null; + $model->returnTypes = $primitive['returnTypes'] ?? []; + $model->isReturnByReference = $primitive['isReturnByReference'] ?? false; + + } elseif (isset($primitive['types']) || isset($primitive['defaultValue'])) { $model->type = 'property'; - $model->writeOnly = $primitive->isWriteOnly; - $model->readOnly = $primitive->isReadOnly; - $model->types = $primitive->types; - $model->defaultValue = $primitive->defaultValue; - $model->setter = $primitive->setter ? $primitive->setter->name : null; - $model->getter = $primitive->getter ? $primitive->getter->name : null; - - } elseif ($primitive instanceof ConstDoc) { + $model->visibility = $primitive['visibility'] ?? 'public'; + $model->isStatic = $primitive['isStatic'] ?? false; + $model->writeOnly = $primitive['isWriteOnly'] ?? false; + $model->readOnly = $primitive['isReadOnly'] ?? false; + $model->types = $primitive['types'] ?? []; + $model->defaultValue = $primitive['defaultValue'] ?? null; + $model->setter = $primitive['setter'] ?? null; + $model->getter = $primitive['getter'] ?? null; + + } elseif (isset($primitive['value'])) { + // Check if this is an event or constant + if (isset($primitive['trigger']) || strpos($model->name, 'EVENT_') === 0) { + $model->type = 'event'; + } else { + $model->type = 'const'; + } + $model->value = $primitive['value']; + } else { + // Default to const if we can't determine type $model->type = 'const'; - - $model->value = $primitive->value; - - } elseif ($primitive instanceof EventDoc) { - $model->type = 'event'; - - $model->value = $primitive->value; + $model->value = $primitive['value'] ?? null; } - $model->insert(false, null, ['op_type' => 'create', 'parent' => $model->parentId]); + + $model->set_id($parent->get_id() . '::' . $model->name); + $model->insert(false, null, ['op_type' => 'index']); } public static function type() @@ -181,44 +169,55 @@ public static function setMappings() if (empty($mapping)) { $command->setMapping(static::index(), static::type(), [ static::type() => [ - // TODO improve mappings for search - '_parent' => ['type' => 'api-type'], 'properties' => [ - 'version' => ['type' => 'string', 'index' => 'not_analyzed'], - 'type' => ['type' => 'string', 'index' => 'not_analyzed'], - - 'name' => ['type' => 'string'], - 'parentId' => ['type' => 'string', 'index' => 'not_analyzed'], - 'shortDescription' => ['type' => 'string'], - 'description' => ['type' => 'string'], - 'since' => ['type' => 'string', 'index' => 'not_analyzed'], - 'deprecatedSince' => ['type' => 'string', 'index' => 'not_analyzed'], - 'deprecatedReason' => ['type' => 'string'], - - 'definedBy' => ['type' => 'string', 'index' => 'not_analyzed'], + 'version' => ['type' => 'keyword'], + 'type' => ['type' => 'keyword'], + + 'name' => [ + 'type' => 'text', + 'fields' => [ + 'suggest' => [ + 'type' => 'completion', + ], + ], + ], + 'parentId' => ['type' => 'keyword'], + 'shortDescription' => ['type' => 'text'], + 'description' => [ + 'type' => 'text', + 'fields' => [ + 'stemmed' => [ + 'type' => 'text', + 'analyzer' => 'english', + ], + ], + ], + 'since' => ['type' => 'keyword'], + 'deprecatedSince' => ['type' => 'keyword'], + 'deprecatedReason' => ['type' => 'text'], + + 'definedBy' => ['type' => 'keyword'], // methods and properties - 'visibility' => ['type' => 'string', 'index' => 'not_analyzed'], + 'visibility' => ['type' => 'keyword'], 'isStatic' => ['type' => 'boolean'], // properties 'writeOnly' => ['type' => 'boolean'], 'readOnly' => ['type' => 'boolean'], - 'types' => ['type' => 'string', 'index' => 'not_analyzed'], // array - 'defaultValue' => ['type' => 'string', 'index' => 'not_analyzed'], - 'getter' => ['type' => 'string', 'index' => 'not_analyzed'], - 'setter' => ['type' => 'string', 'index' => 'not_analyzed'], + 'types' => ['type' => 'keyword'], // array + 'defaultValue' => ['type' => 'keyword'], + 'getter' => ['type' => 'keyword'], + 'setter' => ['type' => 'keyword'], // const, event - 'value' => ['type' => 'string', 'index' => 'not_analyzed'], + 'value' => ['type' => 'keyword'], // method 'isAbstract' => ['type' => 'boolean'], 'isFinal' => ['type' => 'boolean'], - //'params', // array - //'exceptions', // array - 'return' => ['type' => 'string'], - 'returnTypes' => ['type' => 'string', 'index' => 'not_analyzed'], // array + 'return' => ['type' => 'text'], + 'returnTypes' => ['type' => 'keyword'], // array 'isReturnByReference' => ['type' => 'boolean'], ], @@ -242,11 +241,11 @@ public function getTitle() public function getDescription() { - // TODO: Implement getDescription() method. + return $this->shortDescription ?: $this->description; } public function getType() { - // TODO: Implement getTitle() method. + return $this->getAttribute('type'); } } diff --git a/models/search/SearchApiType.php b/models/search/SearchApiType.php index 77a98749..bc95c507 100644 --- a/models/search/SearchApiType.php +++ b/models/search/SearchApiType.php @@ -76,34 +76,36 @@ public static function createRecord($type, $version) $model->insert(false, null, ['op_type' => 'index']); - /* - if ($type->methods !== null) { - foreach($type->methods as $method) { - if ($method->visibility === 'private') { + // Index methods, properties, constants and events for direct search + if (isset($type['methods']) && is_array($type['methods'])) { + foreach($type['methods'] as $method) { + if (($method['visibility'] ?? 'public') === 'private') { continue; } SearchApiPrimitive::createRecord($model, $method, $version); } } - if ($type->properties !== null) { - foreach($type->properties as $property) { - if ($property->visibility === 'private') { + if (isset($type['properties']) && is_array($type['properties'])) { + foreach($type['properties'] as $property) { + if (($property['visibility'] ?? 'public') === 'private') { continue; } SearchApiPrimitive::createRecord($model, $property, $version); } } - if ($type instanceof ClassDoc) { - foreach($type->constants as $const) { + if (isset($type['constants']) && is_array($type['constants'])) { + foreach($type['constants'] as $const) { SearchApiPrimitive::createRecord($model, $const, $version); } + } - foreach($type->events as $event) { + if (isset($type['events']) && is_array($type['events'])) { + foreach($type['events'] as $event) { SearchApiPrimitive::createRecord($model, $event, $version); } - }*/ + } } public static function type() diff --git a/views/search/partials/_result.php b/views/search/partials/_result.php index cfb36b53..680104fc 100644 --- a/views/search/partials/_result.php +++ b/views/search/partials/_result.php @@ -36,6 +36,16 @@ } else { echo Html::encode(($model->namespace ? $model->namespace . '\\' : '') . $model->name); } + } elseif ($model instanceof SearchApiPrimitive) { + // Show parent class and primitive name + if (isset($highlight['name'])) { + echo Html::encode($model->definedBy) . '::' . $encodeHighlight(implode(' ... ', $highlight['name'])); + } else { + echo Html::encode($model->getTitle()); + } + if ($model->type === 'method') { + echo '()'; + } } elseif ($model instanceof SearchExtension) { if (isset($highlight['name'])) { echo $encodeHighlight(implode(' ... ', $highlight['name'])); @@ -67,7 +77,7 @@ } ?> '; if (isset($highlight['title'])) { echo $encodeHighlight(implode(' ... ', $highlight['title']));