make(\Illuminate\Contracts\Console\Kernel::class)->bootstrap(); echo "=== EXACT MAINSEARCHBAR SEARCH TEST ===" . PHP_EOL . PHP_EOL; $searchTerm = 'event'; $locale = 'en'; $currentTime = now()->toISOString(); // Build exact query from MainSearchBar use ONGR\ElasticsearchDSL\Query\Compound\BoolQuery; use ONGR\ElasticsearchDSL\Query\FullText\MultiMatchQuery; $postsBoolQuery = new BoolQuery(); // Class name filter $postsBoolQuery->add( new \ONGR\ElasticsearchDSL\Query\TermLevel\TermQuery('__class_name', 'App\Models\Post'), BoolQuery::MUST ); // Search fields $postSearchFields = [ 'post_translations.title_' . $locale . '^3', 'post_translations.content_' . $locale . '^1', 'post_translations.excerpt_' . $locale . '^2', ]; $postMultiMatchQuery = new MultiMatchQuery($postSearchFields, $searchTerm); $postMultiMatchQuery->addParameter('boost', 4); $postsBoolQuery->add($postMultiMatchQuery, BoolQuery::MUST); // Publication filters (CORRECTED VERSION) // From date: must exist AND be in the past (null means NOT published) $postsBoolQuery->add( new \ONGR\ElasticsearchDSL\Query\TermLevel\ExistsQuery( "post_translations.from_{$locale}" ), BoolQuery::MUST ); $postsBoolQuery->add( new \ONGR\ElasticsearchDSL\Query\TermLevel\RangeQuery( "post_translations.from_{$locale}", ['lte' => $currentTime] ), BoolQuery::MUST ); // Till date: (NOT exists) OR (exists AND in future) = never expires OR not yet expired $tillFilter = new BoolQuery(); // Option 1: field doesn't exist (null) $tillNotExists = new BoolQuery(); $tillNotExists->add( new \ONGR\ElasticsearchDSL\Query\TermLevel\ExistsQuery( "post_translations.till_{$locale}" ), BoolQuery::MUST_NOT ); $tillFilter->add($tillNotExists, BoolQuery::SHOULD); // Option 2: field exists and is in the future $tillInFuture = new BoolQuery(); $tillInFuture->add( new \ONGR\ElasticsearchDSL\Query\TermLevel\ExistsQuery( "post_translations.till_{$locale}" ), BoolQuery::MUST ); $tillInFuture->add( new \ONGR\ElasticsearchDSL\Query\TermLevel\RangeQuery( "post_translations.till_{$locale}", ['gte' => $currentTime] ), BoolQuery::MUST ); $tillFilter->add($tillInFuture, BoolQuery::SHOULD); $postsBoolQuery->add($tillFilter, BoolQuery::MUST); // Deleted date: (NOT exists) OR (exists AND in future) = not deleted OR scheduled for future $deletionFilter = new BoolQuery(); // Option 1: field doesn't exist (null) $deletionNotExists = new BoolQuery(); $deletionNotExists->add( new \ONGR\ElasticsearchDSL\Query\TermLevel\ExistsQuery( "post_translations.deleted_at_{$locale}" ), BoolQuery::MUST_NOT ); $deletionFilter->add($deletionNotExists, BoolQuery::SHOULD); // Option 2: field exists and is in the future $deletionInFuture = new BoolQuery(); $deletionInFuture->add( new \ONGR\ElasticsearchDSL\Query\TermLevel\ExistsQuery( "post_translations.deleted_at_{$locale}" ), BoolQuery::MUST ); $deletionInFuture->add( new \ONGR\ElasticsearchDSL\Query\TermLevel\RangeQuery( "post_translations.deleted_at_{$locale}", ['gt' => $currentTime] ), BoolQuery::MUST ); $deletionFilter->add($deletionInFuture, BoolQuery::SHOULD); $postsBoolQuery->add($deletionFilter, BoolQuery::MUST); // Category filter $categoryIds = timebank_config('main_search_bar.category_ids_posts'); if (!empty($categoryIds)) { $categoryBoolQuery = new BoolQuery(); foreach ($categoryIds as $categoryId) { $categoryBoolQuery->add( new \ONGR\ElasticsearchDSL\Query\TermLevel\TermQuery('category_id', $categoryId), BoolQuery::SHOULD ); } $postsBoolQuery->add($categoryBoolQuery, BoolQuery::MUST); } // Execute search $client = app(Elastic\Elasticsearch\ClientBuilder::class)->build(); $searchBody = ['query' => $postsBoolQuery->toArray()]; echo "Searching for: '{$searchTerm}'" . PHP_EOL; echo "Locale: {$locale}" . PHP_EOL; echo "Current time: {$currentTime}" . PHP_EOL; echo "Category filter: " . json_encode($categoryIds) . PHP_EOL; echo PHP_EOL; echo "Query structure:" . PHP_EOL; echo json_encode($searchBody, JSON_PRETTY_PRINT) . PHP_EOL; echo PHP_EOL; try { $response = $client->search([ 'index' => 'posts_index', 'body' => $searchBody ])->asArray(); $totalHits = $response['hits']['total']['value'] ?? 0; echo "Total hits: {$totalHits}" . PHP_EOL . PHP_EOL; if (!empty($response['hits']['hits'])) { echo "Results:" . PHP_EOL; echo str_repeat('-', 100) . PHP_EOL; foreach ($response['hits']['hits'] as $hit) { $postId = $hit['_source']['id'] ?? 'N/A'; $categoryId = $hit['_source']['category_id'] ?? 'N/A'; $title = $hit['_source']['post_translations']['title_en'] ?? 'N/A'; $from = $hit['_source']['post_translations']['from_en'] ?? 'NULL'; $till = $hit['_source']['post_translations']['till_en'] ?? 'NULL'; $score = $hit['_score'] ?? 'N/A'; echo "ID: {$postId} | Cat: {$categoryId} | Score: {$score}" . PHP_EOL; echo " Title: " . substr($title, 0, 60) . PHP_EOL; echo " from_en: {$from} | till_en: {$till}" . PHP_EOL; echo PHP_EOL; } } } catch (\Exception $e) { echo "Error: " . $e->getMessage() . PHP_EOL; echo "Stack trace:" . PHP_EOL; echo $e->getTraceAsString() . PHP_EOL; } echo "=== TEST COMPLETE ===" . PHP_EOL;