Skip to content

Commit

Permalink
Add searchindex helper and console command (#82)
Browse files Browse the repository at this point in the history
* add searchindex helper and console command

* add postgres support for searchindex optimization and unit test

* skip searchindex tests depending on db driver
  • Loading branch information
nevinsm authored May 24, 2024
1 parent 4755739 commit fb7bc2c
Show file tree
Hide file tree
Showing 7 changed files with 331 additions and 183 deletions.
364 changes: 182 additions & 182 deletions composer.lock

Large diffs are not rendered by default.

23 changes: 23 additions & 0 deletions docs/helpers.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
layout: default
title: Helpers
nav_order: 6
---

# Helpers

## Search Index
We include a helper for common tasks related to Craft's searchindex table which can become unweildy when large amounts of data are in the system. To access the helper from anywhere in the application you can grab it with `use viget\base\helpers\SearchIndex;`

For example you can optimize that table:
```php
use viget\base\helpers\SearchIndex;

...

try {
SearchIndex::optimize();
} catch (\Exception $e) {
// Handle the error
}
```
2 changes: 1 addition & 1 deletion docs/testing.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
layout: default
title: Testing
nav_order: 6
nav_order: 7
---

# Testing
Expand Down
14 changes: 14 additions & 0 deletions src/Module.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@
use craft\web\View;
use craft\web\twig\variables\CraftVariable;
use craft\helpers\ArrayHelper;
use craft\console\Application as CraftConsoleApplication;
use craft\web\Application as CraftWebApplication;
use viget\base\console\controllers\SearchIndexController;
use viget\base\controllers\PartsKitController;
use viget\base\twigextensions\Extension;
use viget\base\services\CpNav;
Expand All @@ -36,12 +38,24 @@ public function bootstrap($app)
{
Craft::setAlias('@viget/base', __DIR__);




Craft::$app->onInit(function() {
self::setInstance($this);
$this->_loadConfig();
$this->_setComponents();

// manually register console controller paths
if (Craft::$app instanceof CraftConsoleApplication) {
$this->controllerNamespace = 'viget\base\console\controllers';

// Optionally add controller map or configure components
Craft::$app->controllerMap['viget-searchindex'] = [
'class' => SearchIndexController::class,
];
}

// Auto-bootstrapping requires that we
// manually register our controller paths
if (Craft::$app instanceof CraftWebApplication) {
Expand Down
28 changes: 28 additions & 0 deletions src/console/controllers/SearchIndexController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

namespace viget\base\console\controllers;

use craft\console\Controller;
use viget\base\helpers\SearchIndex;
use yii\console\ExitCode;

class SearchIndexController extends Controller
{
/**
* Optimizes Craft's searchindex table (can take a long time)
* @return int
*/
public function actionOptimize(): int
{
$tableName = SearchIndex::$tableName;

try {
SearchIndex::optimize();
$this->stdout("Table {$tableName} optimized successfully.\n");
return ExitCode::OK;
} catch (\Exception $e) {
$this->stderr("Failed to optimize table {$tableName}: {$e->getMessage()}\n");
return ExitCode::UNSPECIFIED_ERROR;
}
}
}
32 changes: 32 additions & 0 deletions src/helpers/SearchIndex.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

namespace viget\base\helpers;

use Craft;
use craft\db\Table;

class SearchIndex
{
public static $tableName = Table::SEARCHINDEX;

/**
* Optimizes Craft's searchindex table (can take a long time)
* @return int number of rows affected by the execution.
* @throws Exception execution failed | unsupported driver
* @see \yii\db\Command::execute()
*/
public static function optimize()
{
$db = Craft::$app->getDb();
$driverName = $db->driverName;
$tableName = self::$tableName;

if ($driverName === 'mysql') {
return $db->createCommand("OPTIMIZE TABLE {$tableName}")->execute();
} elseif ($driverName === 'pgsql') {
return $db->createCommand("VACUUM ANALYZE {$tableName}")->execute();
} else {
throw new \Exception('Unsupported database driver');
}
}
}
51 changes: 51 additions & 0 deletions tests/unit/SearchIndexHelperTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?php

namespace unit\helpers;

use Codeception\Test\Unit;
use Craft;
use craft\db\Table;
use viget\base\helpers\SearchIndex;

class SearchIndexHelperTest extends Unit
{
protected function setUp(): void
{
parent::setUp();
Craft::$app->getDb()->createCommand()->truncateTable(Table::SEARCHINDEX)->execute();
}

public function testOptimizeForMysql()
{
if (Craft::$app->getDb()->driverName !== 'mysql') {
$this->markTestSkipped('Skip MySQL testing when driver is not mysql');
}

$result = SearchIndex::optimize();

// Assert: Verify that the result is an integer (number of rows affected)
$this->assertIsInt($result);
}

public function testOptimizeForPostgres()
{
if (Craft::$app->getDb()->driverName !== 'pgsql') {
$this->markTestSkipped('Skip PostgreSQL testing when driver is not pgsql');
}

$result = SearchIndex::optimize();

// Assert: Verify that the result is an integer (number of rows affected)
$this->assertIsInt($result);
}

public function testUnsupportedDriverThrowsException()
{
Craft::$app->getDb()->driverName = 'unsupported_driver';

// Assert: Expect an exception to be thrown
$this->expectException(\Exception::class);

SearchIndex::optimize();
}
}

0 comments on commit fb7bc2c

Please sign in to comment.