From 02848b104e7c888b351628c5116511f07e86ce73 Mon Sep 17 00:00:00 2001 From: Spitfire Date: Thu, 9 Nov 2023 17:31:08 -0600 Subject: [PATCH 01/15] WIP --- app/Models/Character.php | 12 + composer.json | 3 + composer.lock | 532 +++++++++++++++++++++++++-------------- config/scout.php | 142 +++++++++++ docker-compose.yml | 74 ++++-- phpunit.xml | 1 - 6 files changed, 544 insertions(+), 220 deletions(-) create mode 100644 config/scout.php diff --git a/app/Models/Character.php b/app/Models/Character.php index b1a6a834c3..6b8af7438b 100644 --- a/app/Models/Character.php +++ b/app/Models/Character.php @@ -13,6 +13,7 @@ use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\Factories\HasFactory; +use Laravel\Scout\Searchable; /** * Class Character @@ -46,6 +47,7 @@ class Character extends MiscModel use HasFactory; use SoftDeletes; use SortableTrait; + use Searchable; /** @var string[] */ protected $fillable = [ @@ -494,4 +496,14 @@ public function scopeFilteredCharacters(Builder $query): Builder ->with(['location', 'location.entity', 'families', 'families.entity', 'races', 'races.entity', 'entity', 'entity.tags', 'entity.image']) ->has('entity'); } + + public function toSearchableArray() + { + $array = $this->toArray(); + + return [ + 'id' => $array['id'], + 'name' => $array['name'], + ]; + } } diff --git a/composer.json b/composer.json index 6148f39585..84054b1d88 100644 --- a/composer.json +++ b/composer.json @@ -22,18 +22,21 @@ "dompdf/dompdf": "^2.0", "enshrined/svg-sanitize": "^0.16.0", "guzzlehttp/guzzle": "^7.0.1", + "http-interop/http-factory-guzzle": "^1.2", "ilestis/kanka-dnd5e-monster": "^5.0", "intervention/image": "^2.4", "kalnoy/nestedset": "^6.0", "laravel/cashier": "^14.0", "laravel/framework": "^10.0", "laravel/passport": "^11.0", + "laravel/scout": "^10.5", "laravel/socialite": "^5.0", "laravel/ui": "^4.2.1", "laravelcollective/html": "^6.0", "league/flysystem-aws-s3-v3": "^3.5", "mailerlite/mailerlite-php": "^1.0", "mcamara/laravel-localization": "^1.7", + "meilisearch/meilisearch-php": "^1.4", "orhanerday/open-ai": "^4.7", "owlchester/laravel-translation-manager": "^10.0", "pragmarx/google2fa-laravel": "^2.0", diff --git a/composer.lock b/composer.lock index 9b542fd409..53b91c2ab8 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "008bde0687749391db917fb3bec2e0c5", + "content-hash": "e7168946819b6b3b3ab256a7bc2e7841", "packages": [ { "name": "aws/aws-crt-php", @@ -62,20 +62,20 @@ }, { "name": "aws/aws-sdk-php", - "version": "3.283.10", + "version": "3.285.3", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "ae611a2d1d32bb2d14c1653e3d2c309cfed42883" + "reference": "afa1e722f1b2c95644f375dc1a19072e4daf67be" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/ae611a2d1d32bb2d14c1653e3d2c309cfed42883", - "reference": "ae611a2d1d32bb2d14c1653e3d2c309cfed42883", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/afa1e722f1b2c95644f375dc1a19072e4daf67be", + "reference": "afa1e722f1b2c95644f375dc1a19072e4daf67be", "shasum": "" }, "require": { - "aws/aws-crt-php": "^1.0.4", + "aws/aws-crt-php": "^1.2.3", "ext-json": "*", "ext-pcre": "*", "ext-simplexml": "*", @@ -151,9 +151,9 @@ "support": { "forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80", "issues": "https://github.com/aws/aws-sdk-php/issues", - "source": "https://github.com/aws/aws-sdk-php/tree/3.283.10" + "source": "https://github.com/aws/aws-sdk-php/tree/3.285.3" }, - "time": "2023-10-23T18:08:46+00:00" + "time": "2023-11-09T19:07:19+00:00" }, { "name": "bacon/bacon-qr-code", @@ -2690,16 +2690,16 @@ }, { "name": "laravel/cashier", - "version": "v14.12.9", + "version": "v14.13.1", "source": { "type": "git", "url": "https://github.com/laravel/cashier-stripe.git", - "reference": "1a2ff668277378b4aeeabb8bdf1ef2ce6dabe7d8" + "reference": "39d3f1f2a27c6601edc53d8a14ccc9a333ccfca5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/cashier-stripe/zipball/1a2ff668277378b4aeeabb8bdf1ef2ce6dabe7d8", - "reference": "1a2ff668277378b4aeeabb8bdf1ef2ce6dabe7d8", + "url": "https://api.github.com/repos/laravel/cashier-stripe/zipball/39d3f1f2a27c6601edc53d8a14ccc9a333ccfca5", + "reference": "39d3f1f2a27c6601edc53d8a14ccc9a333ccfca5", "shasum": "" }, "require": { @@ -2773,20 +2773,20 @@ "issues": "https://github.com/laravel/cashier/issues", "source": "https://github.com/laravel/cashier" }, - "time": "2023-10-24T15:33:53+00:00" + "time": "2023-11-08T15:24:23+00:00" }, { "name": "laravel/framework", - "version": "v10.29.0", + "version": "v10.31.0", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "2d002849a16ad131110a50cbea4d64dbb78515a3" + "reference": "507ce9b28bce4b5e4140c28943092ca38e9a52e4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/2d002849a16ad131110a50cbea4d64dbb78515a3", - "reference": "2d002849a16ad131110a50cbea4d64dbb78515a3", + "url": "https://api.github.com/repos/laravel/framework/zipball/507ce9b28bce4b5e4140c28943092ca38e9a52e4", + "reference": "507ce9b28bce4b5e4140c28943092ca38e9a52e4", "shasum": "" }, "require": { @@ -2975,20 +2975,20 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2023-10-24T13:48:53+00:00" + "time": "2023-11-07T13:48:30+00:00" }, { "name": "laravel/passport", - "version": "v11.9.2", + "version": "v11.10.0", "source": { "type": "git", "url": "https://github.com/laravel/passport.git", - "reference": "cece4efda933219002d95f3d5d03509e9ed29a14" + "reference": "966bc8e477d08c86a11dc4c5a86f85fa0abdb89b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/passport/zipball/cece4efda933219002d95f3d5d03509e9ed29a14", - "reference": "cece4efda933219002d95f3d5d03509e9ed29a14", + "url": "https://api.github.com/repos/laravel/passport/zipball/966bc8e477d08c86a11dc4c5a86f85fa0abdb89b", + "reference": "966bc8e477d08c86a11dc4c5a86f85fa0abdb89b", "shasum": "" }, "require": { @@ -3053,20 +3053,20 @@ "issues": "https://github.com/laravel/passport/issues", "source": "https://github.com/laravel/passport" }, - "time": "2023-10-16T20:04:42+00:00" + "time": "2023-11-02T17:16:12+00:00" }, { "name": "laravel/prompts", - "version": "v0.1.12", + "version": "v0.1.13", "source": { "type": "git", "url": "https://github.com/laravel/prompts.git", - "reference": "b35f249028c22016e45e48626e19e5d42fd827ff" + "reference": "e1379d8ead15edd6cc4369c22274345982edc95a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/prompts/zipball/b35f249028c22016e45e48626e19e5d42fd827ff", - "reference": "b35f249028c22016e45e48626e19e5d42fd827ff", + "url": "https://api.github.com/repos/laravel/prompts/zipball/e1379d8ead15edd6cc4369c22274345982edc95a", + "reference": "e1379d8ead15edd6cc4369c22274345982edc95a", "shasum": "" }, "require": { @@ -3108,9 +3108,84 @@ ], "support": { "issues": "https://github.com/laravel/prompts/issues", - "source": "https://github.com/laravel/prompts/tree/v0.1.12" + "source": "https://github.com/laravel/prompts/tree/v0.1.13" }, - "time": "2023-10-18T14:18:57+00:00" + "time": "2023-10-27T13:53:59+00:00" + }, + { + "name": "laravel/scout", + "version": "v10.5.1", + "source": { + "type": "git", + "url": "https://github.com/laravel/scout.git", + "reference": "f3fe30438a4792752d19366d8b2e03c3f77d8754" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/scout/zipball/f3fe30438a4792752d19366d8b2e03c3f77d8754", + "reference": "f3fe30438a4792752d19366d8b2e03c3f77d8754", + "shasum": "" + }, + "require": { + "illuminate/bus": "^9.0|^10.0", + "illuminate/contracts": "^9.0|^10.0", + "illuminate/database": "^9.0|^10.0", + "illuminate/http": "^9.0|^10.0", + "illuminate/pagination": "^9.0|^10.0", + "illuminate/queue": "^9.0|^10.0", + "illuminate/support": "^9.0|^10.0", + "php": "^8.0" + }, + "require-dev": { + "algolia/algoliasearch-client-php": "^3.2", + "meilisearch/meilisearch-php": "^1.0", + "mockery/mockery": "^1.0", + "orchestra/testbench": "^7.31|^8.11", + "php-http/guzzle7-adapter": "^1.0", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "algolia/algoliasearch-client-php": "Required to use the Algolia engine (^3.2).", + "meilisearch/meilisearch-php": "Required to use the Meilisearch engine (^1.0)." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "10.x-dev" + }, + "laravel": { + "providers": [ + "Laravel\\Scout\\ScoutServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Laravel\\Scout\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "Laravel Scout provides a driver based solution to searching your Eloquent models.", + "keywords": [ + "algolia", + "laravel", + "search" + ], + "support": { + "issues": "https://github.com/laravel/scout/issues", + "source": "https://github.com/laravel/scout" + }, + "time": "2023-10-31T15:23:07+00:00" }, { "name": "laravel/serializable-closure", @@ -3174,16 +3249,16 @@ }, { "name": "laravel/socialite", - "version": "v5.9.1", + "version": "v5.10.0", "source": { "type": "git", "url": "https://github.com/laravel/socialite.git", - "reference": "49ecc4c907ed88c1254bae991c6b2948945645c2" + "reference": "f376b6eda9084899e37ac08bafd64a95edf9c6c0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/socialite/zipball/49ecc4c907ed88c1254bae991c6b2948945645c2", - "reference": "49ecc4c907ed88c1254bae991c6b2948945645c2", + "url": "https://api.github.com/repos/laravel/socialite/zipball/f376b6eda9084899e37ac08bafd64a95edf9c6c0", + "reference": "f376b6eda9084899e37ac08bafd64a95edf9c6c0", "shasum": "" }, "require": { @@ -3240,7 +3315,7 @@ "issues": "https://github.com/laravel/socialite/issues", "source": "https://github.com/laravel/socialite" }, - "time": "2023-09-07T16:13:53+00:00" + "time": "2023-10-30T22:09:58+00:00" }, { "name": "laravel/ui", @@ -3443,16 +3518,16 @@ }, { "name": "lcobucci/jwt", - "version": "5.0.0", + "version": "5.1.0", "source": { "type": "git", "url": "https://github.com/lcobucci/jwt.git", - "reference": "47bdb0e0b5d00c2f89ebe33e7e384c77e84e7c34" + "reference": "f0031c07b96db6a0ca649206e7eacddb7e9d5908" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/lcobucci/jwt/zipball/47bdb0e0b5d00c2f89ebe33e7e384c77e84e7c34", - "reference": "47bdb0e0b5d00c2f89ebe33e7e384c77e84e7c34", + "url": "https://api.github.com/repos/lcobucci/jwt/zipball/f0031c07b96db6a0ca649206e7eacddb7e9d5908", + "reference": "f0031c07b96db6a0ca649206e7eacddb7e9d5908", "shasum": "" }, "require": { @@ -3460,20 +3535,20 @@ "ext-json": "*", "ext-openssl": "*", "ext-sodium": "*", - "php": "~8.1.0 || ~8.2.0", + "php": "~8.1.0 || ~8.2.0 || ~8.3.0", "psr/clock": "^1.0" }, "require-dev": { - "infection/infection": "^0.26.19", + "infection/infection": "^0.27.0", "lcobucci/clock": "^3.0", - "lcobucci/coding-standard": "^9.0", - "phpbench/phpbench": "^1.2.8", + "lcobucci/coding-standard": "^11.0", + "phpbench/phpbench": "^1.2.9", "phpstan/extension-installer": "^1.2", - "phpstan/phpstan": "^1.10.3", - "phpstan/phpstan-deprecation-rules": "^1.1.2", - "phpstan/phpstan-phpunit": "^1.3.8", + "phpstan/phpstan": "^1.10.7", + "phpstan/phpstan-deprecation-rules": "^1.1.3", + "phpstan/phpstan-phpunit": "^1.3.10", "phpstan/phpstan-strict-rules": "^1.5.0", - "phpunit/phpunit": "^10.0.12" + "phpunit/phpunit": "^10.2.6" }, "suggest": { "lcobucci/clock": ">= 3.0" @@ -3502,7 +3577,7 @@ ], "support": { "issues": "https://github.com/lcobucci/jwt/issues", - "source": "https://github.com/lcobucci/jwt/tree/5.0.0" + "source": "https://github.com/lcobucci/jwt/tree/5.1.0" }, "funding": [ { @@ -3514,7 +3589,7 @@ "type": "patreon" } ], - "time": "2023-02-25T21:35:16+00:00" + "time": "2023-10-31T06:41:47+00:00" }, { "name": "league/commonmark", @@ -3760,16 +3835,16 @@ }, { "name": "league/flysystem", - "version": "3.18.0", + "version": "3.19.0", "source": { "type": "git", "url": "https://github.com/thephpleague/flysystem.git", - "reference": "015633a05aee22490495159237a5944091d8281e" + "reference": "1b2aa10f2326e0351399b8ce68e287d8e9209a83" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/015633a05aee22490495159237a5944091d8281e", - "reference": "015633a05aee22490495159237a5944091d8281e", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/1b2aa10f2326e0351399b8ce68e287d8e9209a83", + "reference": "1b2aa10f2326e0351399b8ce68e287d8e9209a83", "shasum": "" }, "require": { @@ -3834,7 +3909,7 @@ ], "support": { "issues": "https://github.com/thephpleague/flysystem/issues", - "source": "https://github.com/thephpleague/flysystem/tree/3.18.0" + "source": "https://github.com/thephpleague/flysystem/tree/3.19.0" }, "funding": [ { @@ -3846,20 +3921,20 @@ "type": "github" } ], - "time": "2023-10-20T17:59:40+00:00" + "time": "2023-11-07T09:04:28+00:00" }, { "name": "league/flysystem-aws-s3-v3", - "version": "3.16.0", + "version": "3.19.0", "source": { "type": "git", "url": "https://github.com/thephpleague/flysystem-aws-s3-v3.git", - "reference": "ded9ba346bb01cb9cc4cc7f2743c2c0e14d18e1c" + "reference": "03be643c8ed4dea811d946101be3bc875b5cf214" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem-aws-s3-v3/zipball/ded9ba346bb01cb9cc4cc7f2743c2c0e14d18e1c", - "reference": "ded9ba346bb01cb9cc4cc7f2743c2c0e14d18e1c", + "url": "https://api.github.com/repos/thephpleague/flysystem-aws-s3-v3/zipball/03be643c8ed4dea811d946101be3bc875b5cf214", + "reference": "03be643c8ed4dea811d946101be3bc875b5cf214", "shasum": "" }, "require": { @@ -3900,7 +3975,7 @@ ], "support": { "issues": "https://github.com/thephpleague/flysystem-aws-s3-v3/issues", - "source": "https://github.com/thephpleague/flysystem-aws-s3-v3/tree/3.16.0" + "source": "https://github.com/thephpleague/flysystem-aws-s3-v3/tree/3.19.0" }, "funding": [ { @@ -3912,20 +3987,20 @@ "type": "github" } ], - "time": "2023-08-30T10:14:57+00:00" + "time": "2023-11-06T20:35:28+00:00" }, { "name": "league/flysystem-local", - "version": "3.18.0", + "version": "3.19.0", "source": { "type": "git", "url": "https://github.com/thephpleague/flysystem-local.git", - "reference": "e7381ef7643f658b87efb7dbe98fe538fb1bbf32" + "reference": "8d868217f9eeb4e9a7320db5ccad825e9a7a4076" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem-local/zipball/e7381ef7643f658b87efb7dbe98fe538fb1bbf32", - "reference": "e7381ef7643f658b87efb7dbe98fe538fb1bbf32", + "url": "https://api.github.com/repos/thephpleague/flysystem-local/zipball/8d868217f9eeb4e9a7320db5ccad825e9a7a4076", + "reference": "8d868217f9eeb4e9a7320db5ccad825e9a7a4076", "shasum": "" }, "require": { @@ -3960,7 +4035,7 @@ ], "support": { "issues": "https://github.com/thephpleague/flysystem-local/issues", - "source": "https://github.com/thephpleague/flysystem-local/tree/3.18.0" + "source": "https://github.com/thephpleague/flysystem-local/tree/3.19.0" }, "funding": [ { @@ -3972,7 +4047,7 @@ "type": "github" } ], - "time": "2023-10-19T20:07:13+00:00" + "time": "2023-11-06T20:35:28+00:00" }, { "name": "league/mime-type-detection", @@ -4654,6 +4729,74 @@ ], "time": "2023-02-18T15:43:23+00:00" }, + { + "name": "meilisearch/meilisearch-php", + "version": "v1.4.1", + "source": { + "type": "git", + "url": "https://github.com/meilisearch/meilisearch-php.git", + "reference": "d1cea3b8d62dd31324e78fc8396c4c984a4f78dc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/meilisearch/meilisearch-php/zipball/d1cea3b8d62dd31324e78fc8396c4c984a4f78dc", + "reference": "d1cea3b8d62dd31324e78fc8396c4c984a4f78dc", + "shasum": "" + }, + "require": { + "ext-json": "*", + "php": "^7.4 || ^8.0", + "php-http/client-common": "^2.0", + "php-http/discovery": "^1.7", + "php-http/httplug": "^2.1" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3.0", + "guzzlehttp/guzzle": "^7.1", + "http-interop/http-factory-guzzle": "^1.0", + "phpstan/extension-installer": "^1.1", + "phpstan/phpstan": "1.10.36", + "phpstan/phpstan-deprecation-rules": "^1.0", + "phpstan/phpstan-phpunit": "^1.0", + "phpstan/phpstan-strict-rules": "^1.1", + "phpunit/phpunit": "^9.5 || ^10.1" + }, + "suggest": { + "guzzlehttp/guzzle": "Use Guzzle ^7 as HTTP client", + "http-interop/http-factory-guzzle": "Factory for guzzlehttp/guzzle" + }, + "type": "library", + "autoload": { + "psr-4": { + "MeiliSearch\\": "src/", + "Meilisearch\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Clementine Urquizar", + "email": "clementine@meilisearch.com" + } + ], + "description": "PHP wrapper for the Meilisearch API", + "keywords": [ + "api", + "client", + "instant", + "meilisearch", + "php", + "search" + ], + "support": { + "issues": "https://github.com/meilisearch/meilisearch-php/issues", + "source": "https://github.com/meilisearch/meilisearch-php/tree/v1.4.1" + }, + "time": "2023-10-25T09:28:44+00:00" + }, { "name": "moneyphp/money", "version": "v4.2.0", @@ -4745,16 +4888,16 @@ }, { "name": "monolog/monolog", - "version": "3.4.0", + "version": "3.5.0", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", - "reference": "e2392369686d420ca32df3803de28b5d6f76867d" + "reference": "c915e2634718dbc8a4a15c61b0e62e7a44e14448" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/e2392369686d420ca32df3803de28b5d6f76867d", - "reference": "e2392369686d420ca32df3803de28b5d6f76867d", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/c915e2634718dbc8a4a15c61b0e62e7a44e14448", + "reference": "c915e2634718dbc8a4a15c61b0e62e7a44e14448", "shasum": "" }, "require": { @@ -4830,7 +4973,7 @@ ], "support": { "issues": "https://github.com/Seldaek/monolog/issues", - "source": "https://github.com/Seldaek/monolog/tree/3.4.0" + "source": "https://github.com/Seldaek/monolog/tree/3.5.0" }, "funding": [ { @@ -4842,7 +4985,7 @@ "type": "tidelift" } ], - "time": "2023-06-21T08:46:11+00:00" + "time": "2023-10-27T15:32:31+00:00" }, { "name": "mtdowling/jmespath.php", @@ -5143,16 +5286,16 @@ }, { "name": "nette/utils", - "version": "v4.0.2", + "version": "v4.0.3", "source": { "type": "git", "url": "https://github.com/nette/utils.git", - "reference": "cead6637226456b35e1175cc53797dd585d85545" + "reference": "a9d127dd6a203ce6d255b2e2db49759f7506e015" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nette/utils/zipball/cead6637226456b35e1175cc53797dd585d85545", - "reference": "cead6637226456b35e1175cc53797dd585d85545", + "url": "https://api.github.com/repos/nette/utils/zipball/a9d127dd6a203ce6d255b2e2db49759f7506e015", + "reference": "a9d127dd6a203ce6d255b2e2db49759f7506e015", "shasum": "" }, "require": { @@ -5223,9 +5366,9 @@ ], "support": { "issues": "https://github.com/nette/utils/issues", - "source": "https://github.com/nette/utils/tree/v4.0.2" + "source": "https://github.com/nette/utils/tree/v4.0.3" }, - "time": "2023-09-19T11:58:07+00:00" + "time": "2023-10-29T21:02:13+00:00" }, { "name": "nunomaduro/termwind", @@ -5393,16 +5536,16 @@ }, { "name": "orhanerday/open-ai", - "version": "4.8", + "version": "4.9", "source": { "type": "git", "url": "https://github.com/orhanerday/open-ai.git", - "reference": "896665e293689d68de4b1e9813a2e0b00a06f5ef" + "reference": "14ba8185120d6366756fcf7c5b403c63f3efd852" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/orhanerday/open-ai/zipball/896665e293689d68de4b1e9813a2e0b00a06f5ef", - "reference": "896665e293689d68de4b1e9813a2e0b00a06f5ef", + "url": "https://api.github.com/repos/orhanerday/open-ai/zipball/14ba8185120d6366756fcf7c5b403c63f3efd852", + "reference": "14ba8185120d6366756fcf7c5b403c63f3efd852", "shasum": "" }, "require": { @@ -5440,7 +5583,7 @@ ], "support": { "issues": "https://github.com/orhanerday/open-ai/issues", - "source": "https://github.com/orhanerday/open-ai/tree/4.8" + "source": "https://github.com/orhanerday/open-ai/tree/4.9" }, "funding": [ { @@ -5448,7 +5591,7 @@ "type": "github" } ], - "time": "2023-06-11T09:25:47+00:00" + "time": "2023-10-28T17:36:07+00:00" }, { "name": "owlchester/laravel-translation-manager", @@ -6050,16 +6193,16 @@ }, { "name": "php-http/promise", - "version": "1.2.0", + "version": "1.2.1", "source": { "type": "git", "url": "https://github.com/php-http/promise.git", - "reference": "ef4905bfb492ff389eb7f12e26925a0f20073050" + "reference": "44a67cb59f708f826f3bec35f22030b3edb90119" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-http/promise/zipball/ef4905bfb492ff389eb7f12e26925a0f20073050", - "reference": "ef4905bfb492ff389eb7f12e26925a0f20073050", + "url": "https://api.github.com/repos/php-http/promise/zipball/44a67cb59f708f826f3bec35f22030b3edb90119", + "reference": "44a67cb59f708f826f3bec35f22030b3edb90119", "shasum": "" }, "require": { @@ -6096,9 +6239,9 @@ ], "support": { "issues": "https://github.com/php-http/promise/issues", - "source": "https://github.com/php-http/promise/tree/1.2.0" + "source": "https://github.com/php-http/promise/tree/1.2.1" }, - "time": "2023-10-24T09:20:26+00:00" + "time": "2023-11-08T12:57:08+00:00" }, { "name": "phpoption/phpoption", @@ -7142,16 +7285,16 @@ }, { "name": "ramsey/uuid", - "version": "4.7.4", + "version": "4.7.5", "source": { "type": "git", "url": "https://github.com/ramsey/uuid.git", - "reference": "60a4c63ab724854332900504274f6150ff26d286" + "reference": "5f0df49ae5ad6efb7afa69e6bfab4e5b1e080d8e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ramsey/uuid/zipball/60a4c63ab724854332900504274f6150ff26d286", - "reference": "60a4c63ab724854332900504274f6150ff26d286", + "url": "https://api.github.com/repos/ramsey/uuid/zipball/5f0df49ae5ad6efb7afa69e6bfab4e5b1e080d8e", + "reference": "5f0df49ae5ad6efb7afa69e6bfab4e5b1e080d8e", "shasum": "" }, "require": { @@ -7218,7 +7361,7 @@ ], "support": { "issues": "https://github.com/ramsey/uuid/issues", - "source": "https://github.com/ramsey/uuid/tree/4.7.4" + "source": "https://github.com/ramsey/uuid/tree/4.7.5" }, "funding": [ { @@ -7230,7 +7373,7 @@ "type": "tidelift" } ], - "time": "2023-04-15T23:01:58+00:00" + "time": "2023-11-08T05:53:05+00:00" }, { "name": "richan-fongdasen/eloquent-blameable", @@ -8020,16 +8163,16 @@ }, { "name": "srmklive/paypal", - "version": "3.0.26", + "version": "3.0.27", "source": { "type": "git", "url": "https://github.com/srmklive/laravel-paypal.git", - "reference": "9f0768d1b827b938ef66385f2ac41136d65701de" + "reference": "79560c59d8efd3bfab4dcdc141f7f1477c2f95eb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/srmklive/laravel-paypal/zipball/9f0768d1b827b938ef66385f2ac41136d65701de", - "reference": "9f0768d1b827b938ef66385f2ac41136d65701de", + "url": "https://api.github.com/repos/srmklive/laravel-paypal/zipball/79560c59d8efd3bfab4dcdc141f7f1477c2f95eb", + "reference": "79560c59d8efd3bfab4dcdc141f7f1477c2f95eb", "shasum": "" }, "require": { @@ -8080,9 +8223,9 @@ ], "support": { "issues": "https://github.com/srmklive/laravel-paypal/issues", - "source": "https://github.com/srmklive/laravel-paypal/tree/3.0.26" + "source": "https://github.com/srmklive/laravel-paypal/tree/3.0.27" }, - "time": "2023-09-27T09:16:07+00:00" + "time": "2023-11-09T22:02:55+00:00" }, { "name": "stechstudio/laravel-zipstream", @@ -8858,16 +9001,16 @@ }, { "name": "symfony/http-client", - "version": "v6.3.6", + "version": "v6.3.7", "source": { "type": "git", "url": "https://github.com/symfony/http-client.git", - "reference": "ab8446f997efb9913627e9da10fa784d2182fe92" + "reference": "cd67fcaf4524ec6ae5d9b2d9497682d7ad3ce57d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client/zipball/ab8446f997efb9913627e9da10fa784d2182fe92", - "reference": "ab8446f997efb9913627e9da10fa784d2182fe92", + "url": "https://api.github.com/repos/symfony/http-client/zipball/cd67fcaf4524ec6ae5d9b2d9497682d7ad3ce57d", + "reference": "cd67fcaf4524ec6ae5d9b2d9497682d7ad3ce57d", "shasum": "" }, "require": { @@ -8930,7 +9073,7 @@ "http" ], "support": { - "source": "https://github.com/symfony/http-client/tree/v6.3.6" + "source": "https://github.com/symfony/http-client/tree/v6.3.7" }, "funding": [ { @@ -8946,7 +9089,7 @@ "type": "tidelift" } ], - "time": "2023-10-06T10:08:56+00:00" + "time": "2023-10-29T12:41:36+00:00" }, { "name": "symfony/http-client-contracts", @@ -9028,16 +9171,16 @@ }, { "name": "symfony/http-foundation", - "version": "v6.3.6", + "version": "v6.3.7", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "c186627f52febe09c6d5270b04f8462687a250a6" + "reference": "59d1837d5d992d16c2628cd0d6b76acf8d69b33e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/c186627f52febe09c6d5270b04f8462687a250a6", - "reference": "c186627f52febe09c6d5270b04f8462687a250a6", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/59d1837d5d992d16c2628cd0d6b76acf8d69b33e", + "reference": "59d1837d5d992d16c2628cd0d6b76acf8d69b33e", "shasum": "" }, "require": { @@ -9085,7 +9228,7 @@ "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v6.3.6" + "source": "https://github.com/symfony/http-foundation/tree/v6.3.7" }, "funding": [ { @@ -9101,20 +9244,20 @@ "type": "tidelift" } ], - "time": "2023-10-17T11:32:53+00:00" + "time": "2023-10-28T23:55:27+00:00" }, { "name": "symfony/http-kernel", - "version": "v6.3.6", + "version": "v6.3.7", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "4945f5001b06ff9080cd3d8f1f9f069094c0d156" + "reference": "6d4098095f93279d9536a0e9124439560cc764d0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/4945f5001b06ff9080cd3d8f1f9f069094c0d156", - "reference": "4945f5001b06ff9080cd3d8f1f9f069094c0d156", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/6d4098095f93279d9536a0e9124439560cc764d0", + "reference": "6d4098095f93279d9536a0e9124439560cc764d0", "shasum": "" }, "require": { @@ -9198,7 +9341,7 @@ "description": "Provides a structured process for converting a Request into a Response", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-kernel/tree/v6.3.6" + "source": "https://github.com/symfony/http-kernel/tree/v6.3.7" }, "funding": [ { @@ -9214,7 +9357,7 @@ "type": "tidelift" } ], - "time": "2023-10-21T13:12:51+00:00" + "time": "2023-10-29T14:31:45+00:00" }, { "name": "symfony/mailer", @@ -10744,16 +10887,16 @@ }, { "name": "symfony/translation", - "version": "v6.3.6", + "version": "v6.3.7", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "869b26c7a9d4b8a48afdd77ab36031909c87e3a2" + "reference": "30212e7c87dcb79c83f6362b00bde0e0b1213499" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/869b26c7a9d4b8a48afdd77ab36031909c87e3a2", - "reference": "869b26c7a9d4b8a48afdd77ab36031909c87e3a2", + "url": "https://api.github.com/repos/symfony/translation/zipball/30212e7c87dcb79c83f6362b00bde0e0b1213499", + "reference": "30212e7c87dcb79c83f6362b00bde0e0b1213499", "shasum": "" }, "require": { @@ -10819,7 +10962,7 @@ "description": "Provides tools to internationalize your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/translation/tree/v6.3.6" + "source": "https://github.com/symfony/translation/tree/v6.3.7" }, "funding": [ { @@ -10835,7 +10978,7 @@ "type": "tidelift" } ], - "time": "2023-10-17T11:32:53+00:00" + "time": "2023-10-28T23:11:45+00:00" }, { "name": "symfony/translation-contracts", @@ -11576,16 +11719,16 @@ }, { "name": "brianium/paratest", - "version": "v7.3.0", + "version": "v7.3.1", "source": { "type": "git", "url": "https://github.com/paratestphp/paratest.git", - "reference": "2951d3f773ea91451c7440f48122287778634b0d" + "reference": "551f46f52a93177d873f3be08a1649ae886b4a30" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/paratestphp/paratest/zipball/2951d3f773ea91451c7440f48122287778634b0d", - "reference": "2951d3f773ea91451c7440f48122287778634b0d", + "url": "https://api.github.com/repos/paratestphp/paratest/zipball/551f46f52a93177d873f3be08a1649ae886b4a30", + "reference": "551f46f52a93177d873f3be08a1649ae886b4a30", "shasum": "" }, "require": { @@ -11593,13 +11736,13 @@ "ext-pcre": "*", "ext-reflection": "*", "ext-simplexml": "*", - "fidry/cpu-core-counter": "^0.5.1", + "fidry/cpu-core-counter": "^0.5.1 || ^1.0.0", "jean85/pretty-package-versions": "^2.0.5", "php": "~8.1.0 || ~8.2.0 || ~8.3.0", "phpunit/php-code-coverage": "^10.1.7", "phpunit/php-file-iterator": "^4.1.0", "phpunit/php-timer": "^6.0", - "phpunit/phpunit": "^10.4.1", + "phpunit/phpunit": "^10.4.2", "sebastian/environment": "^6.0.1", "symfony/console": "^6.3.4 || ^7.0.0", "symfony/process": "^6.3.4 || ^7.0.0" @@ -11608,11 +11751,11 @@ "doctrine/coding-standard": "^12.0.0", "ext-pcov": "*", "ext-posix": "*", - "infection/infection": "^0.27.4", - "phpstan/phpstan": "^1.10.38", + "infection/infection": "^0.27.6", + "phpstan/phpstan": "^1.10.40", "phpstan/phpstan-deprecation-rules": "^1.1.4", "phpstan/phpstan-phpunit": "^1.3.15", - "phpstan/phpstan-strict-rules": "^1.5.1", + "phpstan/phpstan-strict-rules": "^1.5.2", "squizlabs/php_codesniffer": "^3.7.2", "symfony/filesystem": "^6.3.1 || ^7.0.0" }, @@ -11655,7 +11798,7 @@ ], "support": { "issues": "https://github.com/paratestphp/paratest/issues", - "source": "https://github.com/paratestphp/paratest/tree/v7.3.0" + "source": "https://github.com/paratestphp/paratest/tree/v7.3.1" }, "funding": [ { @@ -11667,7 +11810,7 @@ "type": "paypal" } ], - "time": "2023-10-10T15:11:25+00:00" + "time": "2023-10-31T09:24:17+00:00" }, { "name": "composer/class-map-generator", @@ -11949,16 +12092,16 @@ }, { "name": "fidry/cpu-core-counter", - "version": "0.5.1", + "version": "1.0.0", "source": { "type": "git", "url": "https://github.com/theofidry/cpu-core-counter.git", - "reference": "b58e5a3933e541dc286cc91fc4f3898bbc6f1623" + "reference": "85193c0b0cb5c47894b5eaec906e946f054e7077" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theofidry/cpu-core-counter/zipball/b58e5a3933e541dc286cc91fc4f3898bbc6f1623", - "reference": "b58e5a3933e541dc286cc91fc4f3898bbc6f1623", + "url": "https://api.github.com/repos/theofidry/cpu-core-counter/zipball/85193c0b0cb5c47894b5eaec906e946f054e7077", + "reference": "85193c0b0cb5c47894b5eaec906e946f054e7077", "shasum": "" }, "require": { @@ -11966,13 +12109,13 @@ }, "require-dev": { "fidry/makefile": "^0.2.0", + "fidry/php-cs-fixer-config": "^1.1.2", "phpstan/extension-installer": "^1.2.0", "phpstan/phpstan": "^1.9.2", "phpstan/phpstan-deprecation-rules": "^1.0.0", "phpstan/phpstan-phpunit": "^1.2.2", "phpstan/phpstan-strict-rules": "^1.4.4", - "phpunit/phpunit": "^9.5.26 || ^8.5.31", - "theofidry/php-cs-fixer-config": "^1.0", + "phpunit/phpunit": "^8.5.31 || ^9.5.26", "webmozarts/strict-phpunit": "^7.5" }, "type": "library", @@ -11998,7 +12141,7 @@ ], "support": { "issues": "https://github.com/theofidry/cpu-core-counter/issues", - "source": "https://github.com/theofidry/cpu-core-counter/tree/0.5.1" + "source": "https://github.com/theofidry/cpu-core-counter/tree/1.0.0" }, "funding": [ { @@ -12006,20 +12149,20 @@ "type": "github" } ], - "time": "2022-12-24T12:35:10+00:00" + "time": "2023-09-17T21:38:23+00:00" }, { "name": "filp/whoops", - "version": "2.15.3", + "version": "2.15.4", "source": { "type": "git", "url": "https://github.com/filp/whoops.git", - "reference": "c83e88a30524f9360b11f585f71e6b17313b7187" + "reference": "a139776fa3f5985a50b509f2a02ff0f709d2a546" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filp/whoops/zipball/c83e88a30524f9360b11f585f71e6b17313b7187", - "reference": "c83e88a30524f9360b11f585f71e6b17313b7187", + "url": "https://api.github.com/repos/filp/whoops/zipball/a139776fa3f5985a50b509f2a02ff0f709d2a546", + "reference": "a139776fa3f5985a50b509f2a02ff0f709d2a546", "shasum": "" }, "require": { @@ -12069,7 +12212,7 @@ ], "support": { "issues": "https://github.com/filp/whoops/issues", - "source": "https://github.com/filp/whoops/tree/2.15.3" + "source": "https://github.com/filp/whoops/tree/2.15.4" }, "funding": [ { @@ -12077,7 +12220,7 @@ "type": "github" } ], - "time": "2023-07-13T12:00:00+00:00" + "time": "2023-11-03T12:00:00+00:00" }, { "name": "hamcrest/hamcrest-php", @@ -12132,16 +12275,16 @@ }, { "name": "laravel/pint", - "version": "v1.13.4", + "version": "v1.13.6", "source": { "type": "git", "url": "https://github.com/laravel/pint.git", - "reference": "428c1eae1be4d2994c88234ffe3fea6800532e0d" + "reference": "3e3d2ab01c7d8b484c18e6100ecf53639c744fa7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/pint/zipball/428c1eae1be4d2994c88234ffe3fea6800532e0d", - "reference": "428c1eae1be4d2994c88234ffe3fea6800532e0d", + "url": "https://api.github.com/repos/laravel/pint/zipball/3e3d2ab01c7d8b484c18e6100ecf53639c744fa7", + "reference": "3e3d2ab01c7d8b484c18e6100ecf53639c744fa7", "shasum": "" }, "require": { @@ -12152,13 +12295,13 @@ "php": "^8.1.0" }, "require-dev": { - "friendsofphp/php-cs-fixer": "^3.34.1", - "illuminate/view": "^10.26.2", - "laravel-zero/framework": "^10.1.2", + "friendsofphp/php-cs-fixer": "^3.38.0", + "illuminate/view": "^10.30.1", + "laravel-zero/framework": "^10.3.0", "mockery/mockery": "^1.6.6", "nunomaduro/larastan": "^2.6.4", "nunomaduro/termwind": "^1.15.1", - "pestphp/pest": "^2.20.0" + "pestphp/pest": "^2.24.2" }, "bin": [ "builds/pint" @@ -12194,7 +12337,7 @@ "issues": "https://github.com/laravel/pint/issues", "source": "https://github.com/laravel/pint" }, - "time": "2023-10-24T15:44:13+00:00" + "time": "2023-11-07T17:59:57+00:00" }, { "name": "laravel/sail", @@ -12263,16 +12406,16 @@ }, { "name": "laravel/telescope", - "version": "v4.16.4", + "version": "v4.17.2", "source": { "type": "git", "url": "https://github.com/laravel/telescope.git", - "reference": "5cb73363ef6d57e4087ccc380964c5120d34ec3c" + "reference": "64da53ee46b99ef328458eaed32202b51e325a11" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/telescope/zipball/5cb73363ef6d57e4087ccc380964c5120d34ec3c", - "reference": "5cb73363ef6d57e4087ccc380964c5120d34ec3c", + "url": "https://api.github.com/repos/laravel/telescope/zipball/64da53ee46b99ef328458eaed32202b51e325a11", + "reference": "64da53ee46b99ef328458eaed32202b51e325a11", "shasum": "" }, "require": { @@ -12328,9 +12471,9 @@ ], "support": { "issues": "https://github.com/laravel/telescope/issues", - "source": "https://github.com/laravel/telescope/tree/v4.16.4" + "source": "https://github.com/laravel/telescope/tree/v4.17.2" }, - "time": "2023-09-25T13:48:25+00:00" + "time": "2023-11-01T14:01:06+00:00" }, { "name": "maximebf/debugbar", @@ -12855,29 +12998,29 @@ }, { "name": "pestphp/pest", - "version": "v2.24.0", + "version": "v2.24.3", "source": { "type": "git", "url": "https://github.com/pestphp/pest.git", - "reference": "811ef27ee4741661f70f629a10e31269d2e2895a" + "reference": "f235d84d95aca83425d83e64792352a7424a89d5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pestphp/pest/zipball/811ef27ee4741661f70f629a10e31269d2e2895a", - "reference": "811ef27ee4741661f70f629a10e31269d2e2895a", + "url": "https://api.github.com/repos/pestphp/pest/zipball/f235d84d95aca83425d83e64792352a7424a89d5", + "reference": "f235d84d95aca83425d83e64792352a7424a89d5", "shasum": "" }, "require": { - "brianium/paratest": "^7.3.0", + "brianium/paratest": "^7.3.1", "nunomaduro/collision": "^7.10.0|^8.0.0", "nunomaduro/termwind": "^1.15.1|^2.0.0", "pestphp/pest-plugin": "^2.1.1", "pestphp/pest-plugin-arch": "^2.4.1", "php": "^8.1.0", - "phpunit/phpunit": "^10.4.1" + "phpunit/phpunit": "^10.4.2" }, "conflict": { - "phpunit/phpunit": ">10.4.1", + "phpunit/phpunit": ">10.4.2", "sebastian/exporter": "<5.1.0", "webmozart/assert": "<1.11.0" }, @@ -12910,6 +13053,11 @@ "Pest\\Plugins\\Version", "Pest\\Plugins\\Parallel" ] + }, + "phpstan": { + "includes": [ + "extension.neon" + ] } }, "autoload": { @@ -12942,7 +13090,7 @@ ], "support": { "issues": "https://github.com/pestphp/pest/issues", - "source": "https://github.com/pestphp/pest/tree/v2.24.0" + "source": "https://github.com/pestphp/pest/tree/v2.24.3" }, "funding": [ { @@ -12954,7 +13102,7 @@ "type": "github" } ], - "time": "2023-10-17T09:07:18+00:00" + "time": "2023-11-08T09:47:14+00:00" }, { "name": "pestphp/pest-plugin", @@ -13658,16 +13806,16 @@ }, { "name": "phpstan/phpstan", - "version": "1.10.39", + "version": "1.10.41", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "d9dedb0413f678b4d03cbc2279a48f91592c97c4" + "reference": "c6174523c2a69231df55bdc65b61655e72876d76" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/d9dedb0413f678b4d03cbc2279a48f91592c97c4", - "reference": "d9dedb0413f678b4d03cbc2279a48f91592c97c4", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/c6174523c2a69231df55bdc65b61655e72876d76", + "reference": "c6174523c2a69231df55bdc65b61655e72876d76", "shasum": "" }, "require": { @@ -13716,7 +13864,7 @@ "type": "tidelift" } ], - "time": "2023-10-17T15:46:26+00:00" + "time": "2023-11-05T12:57:57+00:00" }, { "name": "phpunit/php-code-coverage", @@ -14041,16 +14189,16 @@ }, { "name": "phpunit/phpunit", - "version": "10.4.1", + "version": "10.4.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "62bd7af13d282deeb95650077d28ba3600ca321c" + "reference": "cacd8b9dd224efa8eb28beb69004126c7ca1a1a1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/62bd7af13d282deeb95650077d28ba3600ca321c", - "reference": "62bd7af13d282deeb95650077d28ba3600ca321c", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/cacd8b9dd224efa8eb28beb69004126c7ca1a1a1", + "reference": "cacd8b9dd224efa8eb28beb69004126c7ca1a1a1", "shasum": "" }, "require": { @@ -14122,7 +14270,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/10.4.1" + "source": "https://github.com/sebastianbergmann/phpunit/tree/10.4.2" }, "funding": [ { @@ -14138,7 +14286,7 @@ "type": "tidelift" } ], - "time": "2023-10-08T05:01:11+00:00" + "time": "2023-10-26T07:21:45+00:00" }, { "name": "sebastian/cli-parser", @@ -15714,16 +15862,16 @@ }, { "name": "symfony/yaml", - "version": "v6.3.3", + "version": "v6.3.7", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "e23292e8c07c85b971b44c1c4b87af52133e2add" + "reference": "9758b6c69d179936435d0ffb577c3708d57e38a8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/e23292e8c07c85b971b44c1c4b87af52133e2add", - "reference": "e23292e8c07c85b971b44c1c4b87af52133e2add", + "url": "https://api.github.com/repos/symfony/yaml/zipball/9758b6c69d179936435d0ffb577c3708d57e38a8", + "reference": "9758b6c69d179936435d0ffb577c3708d57e38a8", "shasum": "" }, "require": { @@ -15766,7 +15914,7 @@ "description": "Loads and dumps YAML files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/yaml/tree/v6.3.3" + "source": "https://github.com/symfony/yaml/tree/v6.3.7" }, "funding": [ { @@ -15782,7 +15930,7 @@ "type": "tidelift" } ], - "time": "2023-07-31T07:08:24+00:00" + "time": "2023-10-28T23:31:00+00:00" }, { "name": "ta-tikoma/phpunit-architecture-test", diff --git a/config/scout.php b/config/scout.php new file mode 100644 index 0000000000..481d9c3eeb --- /dev/null +++ b/config/scout.php @@ -0,0 +1,142 @@ + env('SCOUT_DRIVER', 'algolia'), + + /* + |-------------------------------------------------------------------------- + | Index Prefix + |-------------------------------------------------------------------------- + | + | Here you may specify a prefix that will be applied to all search index + | names used by Scout. This prefix may be useful if you have multiple + | "tenants" or applications sharing the same search infrastructure. + | + */ + + 'prefix' => env('SCOUT_PREFIX', ''), + + /* + |-------------------------------------------------------------------------- + | Queue Data Syncing + |-------------------------------------------------------------------------- + | + | This option allows you to control if the operations that sync your data + | with your search engines are queued. When this is set to "true" then + | all automatic data syncing will get queued for better performance. + | + */ + + 'queue' => env('SCOUT_QUEUE', false), + + /* + |-------------------------------------------------------------------------- + | Database Transactions + |-------------------------------------------------------------------------- + | + | This configuration option determines if your data will only be synced + | with your search indexes after every open database transaction has + | been committed, thus preventing any discarded data from syncing. + | + */ + + 'after_commit' => false, + + /* + |-------------------------------------------------------------------------- + | Chunk Sizes + |-------------------------------------------------------------------------- + | + | These options allow you to control the maximum chunk size when you are + | mass importing data into the search engine. This allows you to fine + | tune each of these chunk sizes based on the power of the servers. + | + */ + + 'chunk' => [ + 'searchable' => 500, + 'unsearchable' => 500, + ], + + /* + |-------------------------------------------------------------------------- + | Soft Deletes + |-------------------------------------------------------------------------- + | + | This option allows to control whether to keep soft deleted records in + | the search indexes. Maintaining soft deleted records can be useful + | if your application still needs to search for the records later. + | + */ + + 'soft_delete' => false, + + /* + |-------------------------------------------------------------------------- + | Identify User + |-------------------------------------------------------------------------- + | + | This option allows you to control whether to notify the search engine + | of the user performing the search. This is sometimes useful if the + | engine supports any analytics based on this application's users. + | + | Supported engines: "algolia" + | + */ + + 'identify' => env('SCOUT_IDENTIFY', false), + + /* + |-------------------------------------------------------------------------- + | Algolia Configuration + |-------------------------------------------------------------------------- + | + | Here you may configure your Algolia settings. Algolia is a cloud hosted + | search engine which works great with Scout out of the box. Just plug + | in your application ID and admin API key to get started searching. + | + */ + + 'algolia' => [ + 'id' => env('ALGOLIA_APP_ID', ''), + 'secret' => env('ALGOLIA_SECRET', ''), + ], + + /* + |-------------------------------------------------------------------------- + | Meilisearch Configuration + |-------------------------------------------------------------------------- + | + | Here you may configure your Meilisearch settings. Meilisearch is an open + | source search engine with minimal configuration. Below, you can state + | the host and key information for your own Meilisearch installation. + | + | See: https://www.meilisearch.com/docs/learn/configuration/instance_options#all-instance-options + | + */ + + 'meilisearch' => [ + 'host' => env('MEILISEARCH_HOST', 'http://localhost:7700'), + 'key' => env('MEILISEARCH_KEY'), + 'index-settings' => [ + // 'users' => [ + // 'filterableAttributes'=> ['id', 'name', 'email'], + // ], + ], + ], + +]; diff --git a/docker-compose.yml b/docker-compose.yml index f5b532abeb..9969df1cdc 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -27,27 +27,30 @@ services: - mariadb - redis - minio + - meilisearch mariadb: image: 'mariadb:10' ports: - '${FORWARD_DB_PORT:-3306}:3306' environment: MYSQL_ROOT_PASSWORD: '${DB_PASSWORD}' - MYSQL_ROOT_HOST: "%" + MYSQL_ROOT_HOST: '%' MYSQL_DATABASE: '${DB_DATABASE}' MYSQL_USER: '${DB_USERNAME}' MYSQL_PASSWORD: '${DB_PASSWORD}' MYSQL_ALLOW_EMPTY_PASSWORD: 'yes' volumes: - #- './.sail/logs/slow-queries.log:/var/lib/mysql/mysql-slow.log:rw' - 'sail-mariadb:/var/lib/mysql' - #- './.sail/mariadb/my.cnf:/etc/mysql/my.cnf:ro' - './.mariadb/10-create-logs-database.sh:/docker-entrypoint-initdb.d/10-create-logs-database.sh' - './docker/mysql/create-testing-database.sh:/docker-entrypoint-initdb.d/10-create-testing-database.sh' networks: - sail healthcheck: - test: ["CMD", "mysqladmin", "ping", "-p${DB_PASSWORD}"] + test: + - CMD + - mysqladmin + - ping + - '-p${DB_PASSWORD}' retries: 3 timeout: 5s redis: @@ -59,7 +62,10 @@ services: networks: - sail healthcheck: - test: ["CMD", "redis-cli", "ping"] + test: + - CMD + - redis-cli + - ping retries: 3 timeout: 5s minio: @@ -68,15 +74,19 @@ services: - '${FORWARD_MINIO_PORT:-9000}:9000' - '${FORWARD_MINIO_CONSOLE_PORT:-8900}:8900' environment: - MINIO_ROOT_USER: 'sail' - MINIO_ROOT_PASSWORD: 'password' + MINIO_ROOT_USER: sail + MINIO_ROOT_PASSWORD: password volumes: - 'sail-minio:/data/minio' networks: - sail - command: minio server /data/minio --console-address ":8900" + command: 'minio server /data/minio --console-address ":8900"' healthcheck: - test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"] + test: + - CMD + - curl + - '-f' + - 'http://localhost:9000/minio/health/live' retries: 3 timeout: 5s thumbor: @@ -90,53 +100,61 @@ services: - sail environment: - LOG_LEVEL=info - #- SECURITY_KEY=kanka - - LOADER=thumbor_aws.loader - AWS_LOADER_REGION_NAME=local - AWS_LOADER_BUCKET_NAME=kanka - AWS_LOADER_S3_ACCESS_KEY_ID=sail - AWS_LOADER_S3_SECRET_ACCESS_KEY=password - - AWS_LOADER_S3_ENDPOINT_URL=http://minio:9000/ - + - 'AWS_LOADER_S3_ENDPOINT_URL=http://minio:9000/' - RESULT_STORAGE=thumbor_aws.result_storage - AWS_RESULT_STORAGE_BUCKET_NAME=thumbnails - AWS_RESULT_STORAGE_S3_ACCESS_KEY_ID=sail - AWS_RESULT_STORAGE_S3_SECRET_ACCESS_KEY=password - - AWS_RESULT_STORAGE_S3_ENDPOINT_URL=http://minio:9000/ - - # Result Storage prefix path + - 'AWS_RESULT_STORAGE_S3_ENDPOINT_URL=http://minio:9000/' - AWS_RESULT_STORAGE_ROOT_PATH=rs - - RESULT_STORAGE_STORES_UNSAFE=True - ALLOW_UNSAFE_URL=True - - # Expiration in seconds of generated images in the result storage. (2629746 is a month is seconds) - - 'RESULT_STORAGE_EXPIRATION_SECONDS=2629746' - - 'QUALITY=80' - + - RESULT_STORAGE_EXPIRATION_SECONDS=2629746 + - QUALITY=80 - AUTO_WEBP=True - RESPECT_ORIENTATION=True - MAX_AGE=86400 - HTTP_LOADER_VALIDATE_CERTS=False - - # The image we use doesn't come with numpy, so no face_detector possible - #- DETECTORS=['thumbor.detectors.face_detector'] depends_on: - minio thumbor-nginx: image: 'nginx:1.23' tty: true volumes: - - ./.nginx:/etc/nginx/conf.d/ + - './.nginx:/etc/nginx/conf.d/' ports: - - "8889:80" + - '8889:80' environment: - NGINX_PORT=8889 networks: - sail depends_on: - thumbor + meilisearch: + image: 'getmeili/meilisearch:latest' + ports: + - '${FORWARD_MEILISEARCH_PORT:-7700}:7700' + environment: + MEILI_NO_ANALYTICS: '${MEILISEARCH_NO_ANALYTICS:-false}' + MEILI_MASTER_KEY: '${MEILISEARCH_KEY}' + volumes: + - 'sail-meilisearch:/meili_data' + networks: + - sail + healthcheck: + test: + - CMD + - wget + - '--no-verbose' + - '--spider' + - 'http://meilisearch:7700/health' + retries: 3 + timeout: 5s networks: sail: name: sail @@ -152,3 +170,5 @@ volumes: driver: local sail-thumbor-nginx: driver: local + sail-meilisearch: + driver: local diff --git a/phpunit.xml b/phpunit.xml index 3bc069f8a8..393f2d1120 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -22,7 +22,6 @@ - From c26a577d50586252f2c25e3bf4f1b7aa7230f696 Mon Sep 17 00:00:00 2001 From: ilestis Date: Thu, 9 Nov 2023 23:33:01 +0000 Subject: [PATCH 02/15] Fix styling --- app/Http/Controllers/CrudController.php | 2 +- app/Models/Attribute.php | 2 +- app/Models/Character.php | 2 +- app/Models/Concerns/Nested.php | 28 +++++++++---------- app/Models/Map.php | 2 +- app/Models/PluginVersion.php | 2 +- app/Models/Scopes/AclScope.php | 2 +- app/Observers/CampaignObserver.php | 2 +- app/Renderers/DatagridRenderer.php | 2 +- app/Renderers/DatagridRenderer2.php | 2 +- app/Rules/EntityFileRule.php | 4 +-- app/Services/AttributeMentionService.php | 2 +- app/Services/Users/PurgeService.php | 6 ++-- ...034812_rollback_entities_deleted_index.php | 5 ++-- 14 files changed, 31 insertions(+), 32 deletions(-) diff --git a/app/Http/Controllers/CrudController.php b/app/Http/Controllers/CrudController.php index 5dbef81eae..d018dce213 100644 --- a/app/Http/Controllers/CrudController.php +++ b/app/Http/Controllers/CrudController.php @@ -160,7 +160,7 @@ public function crudIndex(Request $request) // Don't use total as it won't use the distinct() filters (typically when doing // left join on the entities table) $filteredCount = $models->total(); - //$filteredCount = count($models); //->total() + //$filteredCount = count($models); //->total() } else { /** @var Paginator $models */ $models = $base->paginate(); diff --git a/app/Models/Attribute.php b/app/Models/Attribute.php index 1a722c6649..91d164b36b 100644 --- a/app/Models/Attribute.php +++ b/app/Models/Attribute.php @@ -353,7 +353,7 @@ protected function calculateListConstraints(): self */ public function listRange(): array { - if (! is_array($this->listRange)) { + if (!is_array($this->listRange)) { return []; } return $this->listRange; diff --git a/app/Models/Character.php b/app/Models/Character.php index 6b8af7438b..222d61904a 100644 --- a/app/Models/Character.php +++ b/app/Models/Character.php @@ -45,9 +45,9 @@ class Character extends MiscModel use CampaignTrait; use ExportableTrait; use HasFactory; + use Searchable; use SoftDeletes; use SortableTrait; - use Searchable; /** @var string[] */ protected $fillable = [ diff --git a/app/Models/Concerns/Nested.php b/app/Models/Concerns/Nested.php index d9de27cd0b..7f88ad080e 100644 --- a/app/Models/Concerns/Nested.php +++ b/app/Models/Concerns/Nested.php @@ -112,11 +112,11 @@ protected function callPendingAction() { $this->moved = false; - if (! $this->pending && ! $this->exists) { + if (!$this->pending && !$this->exists) { $this->makeRoot(); } - if (! $this->pending) { + if (!$this->pending) { return; } @@ -189,7 +189,7 @@ protected function actionRaw() protected function actionRoot() { // Simplest case that do not affect other nodes. - if (! $this->exists) { + if (!$this->exists) { $cut = $this->getLowerBound() + 1; $this->setLft($cut); @@ -228,7 +228,7 @@ protected function actionAppendOrPrepend(self $parent, $prepend = false) $cut = $prepend ? $parent->getLft() + 1 : $parent->getRgt(); - if (! $this->insertAt($cut)) { + if (!$this->insertAt($cut)) { return false; } @@ -271,7 +271,7 @@ protected function actionBeforeOrAfter(self $node, $after = false) */ public function refreshNode() { - if (! $this->exists || static::$actionsPerformed === 0) { + if (!$this->exists || static::$actionsPerformed === 0) { return; } @@ -523,7 +523,7 @@ public function beforeOrAfterNode(self $node, $after = false) ->assertNotDescendant($node) ->assertSameScope($node); - if (! $this->isSiblingOf($node)) { + if (!$this->isSiblingOf($node)) { $this->setParent($node->getRelationValue('parent')); } @@ -551,7 +551,7 @@ public function insertAfterNode(self $node) */ public function insertBeforeNode(self $node) { - if (! $this->beforeNode($node)->save()) { + if (!$this->beforeNode($node)->save()) { return false; } @@ -587,7 +587,7 @@ public function up($amount = 1) ->skip($amount - 1) ->first(); - if (! $sibling) { + if (!$sibling) { return false; } @@ -609,7 +609,7 @@ public function down($amount = 1) ->skip($amount - 1) ->first(); - if (! $sibling) { + if (!$sibling) { return false; } @@ -752,12 +752,12 @@ public function newScopedQuery(string $table = null) public function applyNestedSetScope($query, $table = null) { // @phpstan-ignore-next-line - if (! $scoped = $this->getScopeAttributes()) { + if (!$scoped = $this->getScopeAttributes()) { return $query; } // @phpstan-ignore-next-line - if (! $table) { + if (!$table) { $table = $this->getTable(); } @@ -839,7 +839,7 @@ public static function create(array $attributes = [], self $parent = null) */ public function getNodeHeight() { - if (! $this->exists) { + if (!$this->exists) { return 2; } @@ -1138,7 +1138,7 @@ protected function getArrayableRelations() */ protected function hardDeleting() { - return ! $this->usesSoftDelete() || $this->forceDeleting; + return !$this->usesSoftDelete() || $this->forceDeleting; } /** @@ -1217,7 +1217,7 @@ protected function assertNotDescendant(self $node) */ protected function assertNodeExists(self $node) { - if (! $node->getLft() || ! $node->getRgt()) { + if (!$node->getLft() || !$node->getRgt()) { $field = $node->getParentIdName(); $error = \Illuminate\Validation\ValidationException::withMessages([ $field => [__('crud.errors.invalid_node')] diff --git a/app/Models/Map.php b/app/Models/Map.php index 32d04c2d52..fb05d62dc2 100644 --- a/app/Models/Map.php +++ b/app/Models/Map.php @@ -622,7 +622,7 @@ public function explorable(): bool if (empty($this->entity->image_path) && !$this->isReal()) { return false; } - return ! ($this->isChunked() && ($this->chunkingError() || $this->chunkingRunning())); + return !($this->isChunked() && ($this->chunkingError() || $this->chunkingRunning())); } /** diff --git a/app/Models/PluginVersion.php b/app/Models/PluginVersion.php index eee0967a75..a97428f94f 100644 --- a/app/Models/PluginVersion.php +++ b/app/Models/PluginVersion.php @@ -367,7 +367,7 @@ protected function emptyBlock(array $matches) if (Str::contains($condition, '')) { return false; } - return ! (empty($condition)); + return !(empty($condition)); } /** diff --git a/app/Models/Scopes/AclScope.php b/app/Models/Scopes/AclScope.php index 994508178e..334fbf72cf 100644 --- a/app/Models/Scopes/AclScope.php +++ b/app/Models/Scopes/AclScope.php @@ -45,7 +45,7 @@ public function extend(Builder $builder) protected function addWithInvisible(Builder $builder) { $builder->macro('withInvisible', function (Builder $builder, $withInvisible = true) { - if (! $withInvisible) { + if (!$withInvisible) { // Sends the default scope return $builder; } diff --git a/app/Observers/CampaignObserver.php b/app/Observers/CampaignObserver.php index f050b1826e..f8cf990fc6 100644 --- a/app/Observers/CampaignObserver.php +++ b/app/Observers/CampaignObserver.php @@ -55,7 +55,7 @@ public function saving(Campaign $campaign) $isPublic = request()->get('is_public', null); if (!empty($isPublic) && $previousVisibility == Campaign::VISIBILITY_PRIVATE) { $campaign->visibility_id = Campaign::VISIBILITY_PUBLIC; - // Default to public for now. Later will have REVIEW mode. + // Default to public for now. Later will have REVIEW mode. } elseif (empty($isPublic) && $previousVisibility != Campaign::VISIBILITY_PRIVATE) { $campaign->visibility_id = Campaign::VISIBILITY_PRIVATE; } diff --git a/app/Renderers/DatagridRenderer.php b/app/Renderers/DatagridRenderer.php index 642bb347a0..793adc9fcd 100644 --- a/app/Renderers/DatagridRenderer.php +++ b/app/Renderers/DatagridRenderer.php @@ -153,7 +153,7 @@ private function renderHeadColumn($column) $class = $column['type']; if ($type == 'avatar') { $class = (!empty($column['parent']) ? $this->hidden : $class) . ' w-14'; - //$html = null; + //$html = null; } elseif ($type == 'location') { $class .= ' ' . $this->hidden; $label = Arr::get($column, 'label', Module::singular(config('entities.ids.location'), __('entities.location'))); diff --git a/app/Renderers/DatagridRenderer2.php b/app/Renderers/DatagridRenderer2.php index 9346281146..966e79d1d2 100644 --- a/app/Renderers/DatagridRenderer2.php +++ b/app/Renderers/DatagridRenderer2.php @@ -168,7 +168,7 @@ public function bulks(): array } continue; } - // More specific use cases? + // More specific use cases? } elseif ($bulk === Layout::ACTION_DELETE) { if (auth()->check() && auth()->user()->isAdmin()) { $this->bulks[] = $bulk; diff --git a/app/Rules/EntityFileRule.php b/app/Rules/EntityFileRule.php index fd55105f65..c50cc33b46 100644 --- a/app/Rules/EntityFileRule.php +++ b/app/Rules/EntityFileRule.php @@ -25,7 +25,7 @@ public function __construct() public function passes($attribute, $value) { // Not a valid file, don't go further - if ($value instanceof UploadedFile && ! $value->isValid()) { + if ($value instanceof UploadedFile && !$value->isValid()) { return false; } @@ -48,7 +48,7 @@ public function passes($attribute, $value) return false; } - return ! (!in_array($value->getClientOriginalExtension(), ['mp3', 'ogg', 'json'])) + return !(!in_array($value->getClientOriginalExtension(), ['mp3', 'ogg', 'json'])) diff --git a/app/Services/AttributeMentionService.php b/app/Services/AttributeMentionService.php index 85d1548bb7..05bd94b3b6 100644 --- a/app/Services/AttributeMentionService.php +++ b/app/Services/AttributeMentionService.php @@ -76,7 +76,7 @@ protected function validField(string $value = null): bool if (!Str::contains($value, ['{', '}'])) { return false; } - return ! (Str::contains($value, ['<', '>'])); + return !(Str::contains($value, ['<', '>'])); } /** * Load all the entity attributes and pre-calculate the values diff --git a/app/Services/Users/PurgeService.php b/app/Services/Users/PurgeService.php index bdb657c3a2..1ed0d4d41f 100644 --- a/app/Services/Users/PurgeService.php +++ b/app/Services/Users/PurgeService.php @@ -188,7 +188,7 @@ public function firstWarning(): int FirstWarningJob::dispatch($user->id); } - $this->count ++; + $this->count++; } }, 'users.id', 'id'); return $this->count; @@ -245,7 +245,7 @@ public function secondWarning(): int SecondWarningJob::dispatch($user->id); } - $this->count ++; + $this->count++; } }, 'users.id', 'id'); return $this->count; @@ -292,7 +292,7 @@ public function purge(): int DeleteUser::dispatch($user); } - $this->count ++; + $this->count++; } }); return $this->count; diff --git a/database/migrations/2023_11_07_034812_rollback_entities_deleted_index.php b/database/migrations/2023_11_07_034812_rollback_entities_deleted_index.php index 262854fdde..cfada89bf7 100644 --- a/database/migrations/2023_11_07_034812_rollback_entities_deleted_index.php +++ b/database/migrations/2023_11_07_034812_rollback_entities_deleted_index.php @@ -4,8 +4,7 @@ use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; -return new class extends Migration -{ +return new class () extends Migration { /** * Run the migrations. */ @@ -22,7 +21,7 @@ public function up(): void public function down(): void { Schema::table('entities', function (Blueprint $table) { - // + }); } }; From 176d6ec188ab6b2d24c0bee85fbb654736cd098c Mon Sep 17 00:00:00 2001 From: Spitfire Date: Thu, 9 Nov 2023 17:34:44 -0600 Subject: [PATCH 03/15] Gitignore --- .gitignore | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/.gitignore b/.gitignore index a30f4ce6a3..a0319d8924 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,21 @@ yarn-error.log *.sql package-lock.json +meilisearch +data.ms/instance-uid +data.ms/VERSION +.gitignore +data.ms/auth/data.mdb +.gitignore +data.ms/auth/lock.mdb +data.ms/tasks/data.mdb +data.ms/tasks/lock.mdb +meili_data/data.ms/instance-uid +.gitignore +meili_data/data.ms/VERSION +meili_data/data.ms/auth/data.mdb +.gitignore +meili_data/data.ms/tasks/data.mdb +meili_data/data.ms/auth/lock.mdb +.gitignore +meili_data/data.ms/tasks/lock.mdb From a1cb8de72b4f7a74ad0eb051b3a1039d7e053b4a Mon Sep 17 00:00:00 2001 From: Spitfire Date: Tue, 14 Nov 2023 17:17:31 -0600 Subject: [PATCH 04/15] Meilisearch Test --- .../Api/v1/FullTextSearchApiController.php | 36 ++++++++ app/Models/Attribute.php | 41 +++++++++ app/Models/AttributeTemplate.php | 13 +++ app/Models/Character.php | 12 --- app/Models/MiscModel.php | 46 ++++++++++ app/Models/Post.php | 44 ++++++++++ app/Models/QuestElement.php | 47 ++++++++++ app/Models/TimelineElement.php | 45 ++++++++++ app/Services/Search/EntitySearchService.php | 86 +++++++++++++++++++ config/scout.php | 7 +- routes/api.v1.php | 2 + 11 files changed, 364 insertions(+), 15 deletions(-) create mode 100644 app/Http/Controllers/Api/v1/FullTextSearchApiController.php create mode 100644 app/Services/Search/EntitySearchService.php diff --git a/app/Http/Controllers/Api/v1/FullTextSearchApiController.php b/app/Http/Controllers/Api/v1/FullTextSearchApiController.php new file mode 100644 index 0000000000..df7102566d --- /dev/null +++ b/app/Http/Controllers/Api/v1/FullTextSearchApiController.php @@ -0,0 +1,36 @@ +service = $service; + } + + /** + * return \Illuminate\Http\Resources\Json\AnonymousResourceCollection + * @throws \Illuminate\Auth\Access\AuthorizationException + */ + public function index(Campaign $campaign) + { + $this->authorize('access', $campaign); + + $results = $this->service->campaign($campaign)->search(request()->term); + //dd($results); + return $results; + + return Resource::collection($campaign->entities()->whereIn('id', $results) + ->paginate() + ->appends(request()->except(['page', 'lastSync']))); + + } +} diff --git a/app/Models/Attribute.php b/app/Models/Attribute.php index 91d164b36b..5a8af8fbdf 100644 --- a/app/Models/Attribute.php +++ b/app/Models/Attribute.php @@ -12,6 +12,7 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Support\Str; +use Laravel\Scout\Searchable; /** * Class Attribute @@ -37,6 +38,7 @@ class Attribute extends Model use Paginatable; use Pinnable; use Privatable; + use Searchable; public const TYPE_CHECKBOX = 'checkbox'; public const TYPE_SECTION = 'section'; @@ -365,4 +367,43 @@ public function listRangeText(): string { return implode(', ', $this->listRange); } + + /** + * Get the value used to index the model. + * + * @return mixed + */ + public function getScoutKey() + { + return $this->getTable() . '_' . $this->id; + } + + /** + * Get the name of the index associated with the model. + */ + public function searchableAs(): string + { + return 'entities'; + } + + protected function makeAllSearchableUsing($query) + { + return $query + ->leftJoin('entities', 'attributes.entity_id', '=', 'entities.id'); + } + + public function toSearchableArray() + { + $array = $this->toArray(); + $entity = $this->entity->toArray(); + + return [ + 'campaign_id' => $entity['campaign_id'], + 'entity_id' => $entity['id'], + 'entity_name' => $entity['name'], + 'name' => $array['name'], + 'type' => 'attribute', + 'value' => $array['value'], + ]; + } } diff --git a/app/Models/AttributeTemplate.php b/app/Models/AttributeTemplate.php index 1f89e39559..f716277252 100644 --- a/app/Models/AttributeTemplate.php +++ b/app/Models/AttributeTemplate.php @@ -276,4 +276,17 @@ public function datagridSortableColumns(): array } return $columns; } + + public function toSearchableArray() + { + $array = $this->toArray(); + $entity = $this->entity->toArray(); + + return [ + 'campaign_id' => $entity['campaign_id'], + 'entity_id' => $entity['id'], + 'entity_name' => $entity['name'], + 'name' => $array['name'], + ]; + } } diff --git a/app/Models/Character.php b/app/Models/Character.php index 222d61904a..b1a6a834c3 100644 --- a/app/Models/Character.php +++ b/app/Models/Character.php @@ -13,7 +13,6 @@ use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\Factories\HasFactory; -use Laravel\Scout\Searchable; /** * Class Character @@ -45,7 +44,6 @@ class Character extends MiscModel use CampaignTrait; use ExportableTrait; use HasFactory; - use Searchable; use SoftDeletes; use SortableTrait; @@ -496,14 +494,4 @@ public function scopeFilteredCharacters(Builder $query): Builder ->with(['location', 'location.entity', 'families', 'families.entity', 'races', 'races.entity', 'entity', 'entity.tags', 'entity.image']) ->has('entity'); } - - public function toSearchableArray() - { - $array = $this->toArray(); - - return [ - 'id' => $array['id'], - 'name' => $array['name'], - ]; - } } diff --git a/app/Models/MiscModel.php b/app/Models/MiscModel.php index 34018ef98c..01568f31b1 100644 --- a/app/Models/MiscModel.php +++ b/app/Models/MiscModel.php @@ -21,6 +21,7 @@ use Illuminate\Support\Facades\DB; use Exception; use Illuminate\Support\Str; +use Laravel\Scout\Searchable as Scout; /** * Class MiscModel @@ -55,6 +56,8 @@ abstract class MiscModel extends Model use Sortable; use SourceCopiable; use SubEntityScopes; + use Scout; + /** @var Entity Performance based entity */ protected Entity $cachedEntity; @@ -628,4 +631,47 @@ public function datagridSortableColumns(): array } return $columns; } + + /** + * Get the value used to index the model. + * + * @return mixed + */ + public function getScoutKey() + { + return $this->getTable() . '_' . $this->id; + } + + /** + * Get the name of the index associated with the model. + */ + public function searchableAs(): string + { + return 'entities'; + } + + protected function makeAllSearchableUsing($query) + { + return $query + ->select([$this->getTable() . '.*', 'entities.id as entity_id']) + ->leftJoin('entities', function ($join) { + $join->on('entities.entity_id', $this->getTable() . '.id') + ->where('entities.type_id', $this->entityTypeId()); + }); + } + + public function toSearchableArray() + { + $array = $this->toArray(); + $entity = $this->entity->toArray(); + + return [ + 'campaign_id' => $array['campaign_id'], + 'entity_id' => $entity['id'], + 'entity_name' => $entity['name'], + 'name' => $array['name'], + 'type' => $array['type'], + 'entry' => $array['entry'], + ]; + } } diff --git a/app/Models/Post.php b/app/Models/Post.php index 68694abd4a..359fe60945 100644 --- a/app/Models/Post.php +++ b/app/Models/Post.php @@ -13,6 +13,7 @@ use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Support\Arr; use Illuminate\Support\Collection; +use Laravel\Scout\Searchable; /** * Class Attribute @@ -48,6 +49,7 @@ class Post extends Model use HasFactory; use Paginatable; use VisibilityIDTrait; + use Searchable; /** @var string[] */ protected $fillable = [ @@ -188,4 +190,46 @@ public function editingUsers() ->using(EntityUser::class) ->withPivot('type_id'); } + + /** + * Get the value used to index the model. + * + * @return mixed + */ + public function getScoutKey() + { + return $this->getTable() . '_' . $this->id; + } + + /** + * Get the name of the index associated with the model. + */ + public function searchableAs(): string + { + return 'entities'; + } + + protected function makeAllSearchableUsing($query) + { + return $query + ->select([$this->getTable() . '.*', 'entities.id as entity_id']) + ->leftJoin('entities', function ($join) { + $join->on('entities.entity_id', $this->getTable() . '.id'); + }); + } + + public function toSearchableArray() + { + $array = $this->toArray(); + $entity = $this->entity->toArray(); + + return [ + 'campaign_id' => $entity['campaign_id'], + 'entity_id' => $entity['id'], + 'entity_name' => $entity['name'], + 'name' => $array['name'], + 'type' => 'post', + 'entry' => $array['entry'], + ]; + } } diff --git a/app/Models/QuestElement.php b/app/Models/QuestElement.php index 600d4c0fc1..aff5c8ed25 100644 --- a/app/Models/QuestElement.php +++ b/app/Models/QuestElement.php @@ -9,6 +9,7 @@ use App\Traits\VisibilityIDTrait; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; +use Laravel\Scout\Searchable; /** * Class QuestCharacter @@ -32,6 +33,7 @@ class QuestElement extends Model */ use SimpleSortableTrait; use VisibilityIDTrait; + use Searchable; /** @var string[] */ protected $fillable = [ @@ -122,4 +124,49 @@ public function editingUsers() ->using(EntityUser::class) ->withPivot('type_id'); } + + /** + * Get the value used to index the model. + * + * @return mixed + */ + public function getScoutKey() + { + return $this->getTable() . '_' . $this->id; + } + + /** + * Get the name of the index associated with the model. + */ + public function searchableAs(): string + { + return 'entities'; + } + + protected function makeAllSearchableUsing($query) + { + + return $query + ->leftJoin('quests', 'quests.id', '=', 'quest_elements.quest_id') + ->select([$this->getTable() . '.*', 'entities.id as entity_id']) + ->leftJoin('entities', function ($join) { + $join->on('entities.entity_id', $this->getTable() . '.id'); + //->where('entities.type_id', $this->entityTypeId()); + }); + } + + public function toSearchableArray() + { + $array = $this->toArray(); + $entity = $this->quest->entity->toArray(); + + return [ + 'campaign_id' => $entity['campaign_id'], + 'entity_id' => $entity['id'], + 'entity_name' => $entity['name'], + 'name' => $array['name'], + 'type' => 'quest_element', + 'entry' => $array['description'], + ]; + } } diff --git a/app/Models/TimelineElement.php b/app/Models/TimelineElement.php index e8a4b946bc..bc00ea9125 100644 --- a/app/Models/TimelineElement.php +++ b/app/Models/TimelineElement.php @@ -10,6 +10,7 @@ use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Support\Str; +use Laravel\Scout\Searchable; /** * Class TimelineElement @@ -40,6 +41,7 @@ class TimelineElement extends Model use Blameable; use HasFactory; use VisibilityIDTrait; + use Searchable; /** @var string[] */ protected $fillable = [ @@ -202,4 +204,47 @@ public function visible(): bool } return !empty($this->entity->child); } + + /** + * Get the value used to index the model. + * + * @return mixed + */ + public function getScoutKey() + { + return $this->getTable() . '_' . $this->id; + } + + /** + * Get the name of the index associated with the model. + */ + public function searchableAs(): string + { + return 'entities'; + } + + protected function makeAllSearchableUsing($query) + { + return $query + ->leftJoin('timelines', 'timelines.id', '=', 'timeline_elements.timeline_id') + ->select([$this->getTable() . '.*', 'entities.id as entity_id']) + ->leftJoin('entities', function ($join) { + $join->on('entities.entity_id', $this->getTable() . '.id'); + }); + } + + public function toSearchableArray() + { + $array = $this->toArray(); + $entity = $this->timeline->entity->toArray(); + + return [ + 'campaign_id' => $entity['campaign_id'], + 'entity_id' => $entity['id'], + 'entity_name' => $entity['name'], + 'name' => $array['name'], + 'type' => 'timeline_element', + 'entry' => $array['entry'], + ]; + } } diff --git a/app/Services/Search/EntitySearchService.php b/app/Services/Search/EntitySearchService.php new file mode 100644 index 0000000000..c49438c2ce --- /dev/null +++ b/app/Services/Search/EntitySearchService.php @@ -0,0 +1,86 @@ +getKeys(); + $ids = []; + $results = $client->index('entities')->search($term, ['filter' => 'campaign_id = ' . $this->campaign->id, 'attributesToRetrieve' => ['id', 'entity_id', 'type'], 'limit' => 20])->getHits(); + $attributeIds = []; + $timelineElementIds = []; + $postIds = []; + $questElementIds = []; + + foreach ($results as $result) { + if ($result['type'] == 'quest_element') { + $id = substr($result['id'], -1, strrpos($result['id'], '_')); + $questElementIds[$result['entity_id']] = $id; + //dd($result); + } elseif ($result['type'] == 'timeline_element') { + $id = substr($result['id'], -1, strrpos($result['id'], '_')); + $timelineElementIds[$result['entity_id']] = $id; + //dd($result); + } elseif ($result['type'] == 'post') { + $id = substr($result['id'], -1, strrpos($result['id'], '_')); + $postIds[$result['entity_id']] = $id; + //dd($result); + } elseif ($result['type'] == 'attribute') { + $id = substr($result['id'], -1, strrpos($result['id'], '_')); + $attributeIds[$result['entity_id']] = $id; + //dd($result); + } else { + $ids[$result['entity_id']] = $result['entity_id']; + } + } + //If the search also threw the entity as a possible result dont bother loading the other models + $attributeIds = array_diff_key($attributeIds, $ids); + $timelineElementIds = array_diff_key($timelineElementIds, $ids); + $questElementIds = array_diff_key($questElementIds, $ids); + $postIds = array_diff_key($postIds, $ids); + + $posts = Post::whereIn('id', $postIds)->get(); + $attributes = Attribute::with('entity')->has('entity')->whereIn('id', $attributeIds)->get(); + $questElements = QuestElement::with(['quest', 'quest.entity'])->has('quest')->has('quest')->whereIn('id', $questElementIds)->get(); + $timelineElements = TimelineElement::with(['timeline', 'timeline.entity'])->has('timeline')->whereIn('id', $timelineElementIds)->get(); + + $entities = Entity::whereIn('id', $ids)->get(); + foreach ($entities as $entity) { + $output[$entity->id] = ['id' => $entity->id, 'entity' => $entity->name, 'url' => $entity->url()]; + } + foreach ($attributes as $attribute) { + $output[$attribute->entity->id] = ['id' => $attribute->entity->id, 'entity' => $attribute->entity->name, 'url' => $attribute->entity->url()]; + } + foreach ($posts as $post) { + $output[$post->entity->id] = ['id' => $post->entity->id, 'entity' => $post->entity->name, 'url' => $post->url()]; + } + foreach ($questElements as $questElement) { + $output[$questElement->quest->entity->id] = ['id' => $questElement->quest->entity->id, 'entity' => $questElement->quest->name, 'url' => $questElement->quest->entity->url()]; + } + foreach ($timelineElements as $timelineElement) { + $output[$timelineElement->timeline->entity->id] = ['id' => $timelineElement->timeline->entity->id, 'entity' => $$timelineElement->timeline->entity->name, 'url' => $timelineElement->timeline->entity->url()]; + } + + return $output; + } + +} diff --git a/config/scout.php b/config/scout.php index 481d9c3eeb..6dce0deed6 100644 --- a/config/scout.php +++ b/config/scout.php @@ -41,6 +41,7 @@ | */ + //SET TO TRUE TO USE QUEUE 'queue' => env('SCOUT_QUEUE', false), /* @@ -133,9 +134,9 @@ 'host' => env('MEILISEARCH_HOST', 'http://localhost:7700'), 'key' => env('MEILISEARCH_KEY'), 'index-settings' => [ - // 'users' => [ - // 'filterableAttributes'=> ['id', 'name', 'email'], - // ], + 'entities' => [ + 'filterableAttributes'=> ['id', 'campaign_id'], + ], ], ], diff --git a/routes/api.v1.php b/routes/api.v1.php index 3dff8e54d2..df08dd304b 100644 --- a/routes/api.v1.php +++ b/routes/api.v1.php @@ -108,6 +108,8 @@ Route::post('campaigns/{campaign}/default-thumbnails', [\App\Http\Controllers\Api\v1\DefaultThumbnailApiController::class, 'upload']); Route::delete('campaigns/{campaign}/default-thumbnails', [\App\Http\Controllers\Api\v1\DefaultThumbnailApiController::class, 'delete']); +Route::get('campaigns/{campaign}/fulltext-search', [\App\Http\Controllers\Api\v1\FullTextSearchApiController::class, 'index']); + Route::get('profile', [\App\Http\Controllers\Api\v1\ProfileApiController::class, 'index']); Route::get('version', function () { return config('app.version'); From 8758f0c5340171dbd9d766aba19780c947a5a127 Mon Sep 17 00:00:00 2001 From: spitfire305 Date: Tue, 14 Nov 2023 23:18:34 +0000 Subject: [PATCH 05/15] Fix styling --- .../Api/v1/FullTextSearchApiController.php | 1 - app/Models/Attribute.php | 3 +-- app/Models/MiscModel.php | 13 ++++++------- app/Models/Post.php | 11 +++++------ app/Models/QuestElement.php | 15 +++++++-------- app/Models/TimelineElement.php | 13 ++++++------- app/Services/Search/EntitySearchService.php | 18 ++++++++---------- config/scout.php | 2 +- 8 files changed, 34 insertions(+), 42 deletions(-) diff --git a/app/Http/Controllers/Api/v1/FullTextSearchApiController.php b/app/Http/Controllers/Api/v1/FullTextSearchApiController.php index df7102566d..4b974a6e6a 100644 --- a/app/Http/Controllers/Api/v1/FullTextSearchApiController.php +++ b/app/Http/Controllers/Api/v1/FullTextSearchApiController.php @@ -3,7 +3,6 @@ namespace App\Http\Controllers\Api\v1; use App\Models\Campaign; -use App\Models\Entity; use App\Http\Resources\EntityResource as Resource; use App\Services\Search\EntitySearchService; diff --git a/app/Models/Attribute.php b/app/Models/Attribute.php index 5a8af8fbdf..b345dbf7eb 100644 --- a/app/Models/Attribute.php +++ b/app/Models/Attribute.php @@ -371,7 +371,6 @@ public function listRangeText(): string /** * Get the value used to index the model. * - * @return mixed */ public function getScoutKey() { @@ -389,7 +388,7 @@ public function searchableAs(): string protected function makeAllSearchableUsing($query) { return $query - ->leftJoin('entities', 'attributes.entity_id', '=', 'entities.id'); + ->leftJoin('entities', 'attributes.entity_id', '=', 'entities.id'); } public function toSearchableArray() diff --git a/app/Models/MiscModel.php b/app/Models/MiscModel.php index 01568f31b1..301143ddc8 100644 --- a/app/Models/MiscModel.php +++ b/app/Models/MiscModel.php @@ -51,12 +51,12 @@ abstract class MiscModel extends Model use LastSync; use Orderable; use Paginatable; + use Scout; use Searchable; //Tooltip, use Sortable; use SourceCopiable; use SubEntityScopes; - use Scout; /** @var Entity Performance based entity */ @@ -635,7 +635,6 @@ public function datagridSortableColumns(): array /** * Get the value used to index the model. * - * @return mixed */ public function getScoutKey() { @@ -653,11 +652,11 @@ public function searchableAs(): string protected function makeAllSearchableUsing($query) { return $query - ->select([$this->getTable() . '.*', 'entities.id as entity_id']) - ->leftJoin('entities', function ($join) { - $join->on('entities.entity_id', $this->getTable() . '.id') - ->where('entities.type_id', $this->entityTypeId()); - }); + ->select([$this->getTable() . '.*', 'entities.id as entity_id']) + ->leftJoin('entities', function ($join) { + $join->on('entities.entity_id', $this->getTable() . '.id') + ->where('entities.type_id', $this->entityTypeId()); + }); } public function toSearchableArray() diff --git a/app/Models/Post.php b/app/Models/Post.php index 359fe60945..3b0ed00acf 100644 --- a/app/Models/Post.php +++ b/app/Models/Post.php @@ -48,8 +48,8 @@ class Post extends Model use Blameable; use HasFactory; use Paginatable; - use VisibilityIDTrait; use Searchable; + use VisibilityIDTrait; /** @var string[] */ protected $fillable = [ @@ -194,7 +194,6 @@ public function editingUsers() /** * Get the value used to index the model. * - * @return mixed */ public function getScoutKey() { @@ -212,10 +211,10 @@ public function searchableAs(): string protected function makeAllSearchableUsing($query) { return $query - ->select([$this->getTable() . '.*', 'entities.id as entity_id']) - ->leftJoin('entities', function ($join) { - $join->on('entities.entity_id', $this->getTable() . '.id'); - }); + ->select([$this->getTable() . '.*', 'entities.id as entity_id']) + ->leftJoin('entities', function ($join) { + $join->on('entities.entity_id', $this->getTable() . '.id'); + }); } public function toSearchableArray() diff --git a/app/Models/QuestElement.php b/app/Models/QuestElement.php index aff5c8ed25..b5fbcd309e 100644 --- a/app/Models/QuestElement.php +++ b/app/Models/QuestElement.php @@ -28,12 +28,12 @@ class QuestElement extends Model { use Blameable; use HasFactory; + use Searchable; /** * Traits */ use SimpleSortableTrait; use VisibilityIDTrait; - use Searchable; /** @var string[] */ protected $fillable = [ @@ -128,7 +128,6 @@ public function editingUsers() /** * Get the value used to index the model. * - * @return mixed */ public function getScoutKey() { @@ -147,12 +146,12 @@ protected function makeAllSearchableUsing($query) { return $query - ->leftJoin('quests', 'quests.id', '=', 'quest_elements.quest_id') - ->select([$this->getTable() . '.*', 'entities.id as entity_id']) - ->leftJoin('entities', function ($join) { - $join->on('entities.entity_id', $this->getTable() . '.id'); - //->where('entities.type_id', $this->entityTypeId()); - }); + ->leftJoin('quests', 'quests.id', '=', 'quest_elements.quest_id') + ->select([$this->getTable() . '.*', 'entities.id as entity_id']) + ->leftJoin('entities', function ($join) { + $join->on('entities.entity_id', $this->getTable() . '.id'); + //->where('entities.type_id', $this->entityTypeId()); + }); } public function toSearchableArray() diff --git a/app/Models/TimelineElement.php b/app/Models/TimelineElement.php index bc00ea9125..1a3a066b72 100644 --- a/app/Models/TimelineElement.php +++ b/app/Models/TimelineElement.php @@ -40,8 +40,8 @@ class TimelineElement extends Model { use Blameable; use HasFactory; - use VisibilityIDTrait; use Searchable; + use VisibilityIDTrait; /** @var string[] */ protected $fillable = [ @@ -208,7 +208,6 @@ public function visible(): bool /** * Get the value used to index the model. * - * @return mixed */ public function getScoutKey() { @@ -226,11 +225,11 @@ public function searchableAs(): string protected function makeAllSearchableUsing($query) { return $query - ->leftJoin('timelines', 'timelines.id', '=', 'timeline_elements.timeline_id') - ->select([$this->getTable() . '.*', 'entities.id as entity_id']) - ->leftJoin('entities', function ($join) { - $join->on('entities.entity_id', $this->getTable() . '.id'); - }); + ->leftJoin('timelines', 'timelines.id', '=', 'timeline_elements.timeline_id') + ->select([$this->getTable() . '.*', 'entities.id as entity_id']) + ->leftJoin('entities', function ($join) { + $join->on('entities.entity_id', $this->getTable() . '.id'); + }); } public function toSearchableArray() diff --git a/app/Services/Search/EntitySearchService.php b/app/Services/Search/EntitySearchService.php index c49438c2ce..cf1d542ad4 100644 --- a/app/Services/Search/EntitySearchService.php +++ b/app/Services/Search/EntitySearchService.php @@ -10,7 +10,6 @@ use App\Traits\CampaignAware; use Meilisearch\Client; - class EntitySearchService { use CampaignAware; @@ -18,7 +17,6 @@ class EntitySearchService /** * Send search request - * @param string|null $query Search term */ public function search(string $term = null): array { @@ -33,21 +31,21 @@ public function search(string $term = null): array foreach ($results as $result) { if ($result['type'] == 'quest_element') { - $id = substr($result['id'], -1, strrpos($result['id'], '_')); + $id = mb_substr($result['id'], -1, mb_strrpos($result['id'], '_')); $questElementIds[$result['entity_id']] = $id; - //dd($result); + //dd($result); } elseif ($result['type'] == 'timeline_element') { - $id = substr($result['id'], -1, strrpos($result['id'], '_')); + $id = mb_substr($result['id'], -1, mb_strrpos($result['id'], '_')); $timelineElementIds[$result['entity_id']] = $id; - //dd($result); + //dd($result); } elseif ($result['type'] == 'post') { - $id = substr($result['id'], -1, strrpos($result['id'], '_')); + $id = mb_substr($result['id'], -1, mb_strrpos($result['id'], '_')); $postIds[$result['entity_id']] = $id; - //dd($result); + //dd($result); } elseif ($result['type'] == 'attribute') { - $id = substr($result['id'], -1, strrpos($result['id'], '_')); + $id = mb_substr($result['id'], -1, mb_strrpos($result['id'], '_')); $attributeIds[$result['entity_id']] = $id; - //dd($result); + //dd($result); } else { $ids[$result['entity_id']] = $result['entity_id']; } diff --git a/config/scout.php b/config/scout.php index 6dce0deed6..eba1bb4590 100644 --- a/config/scout.php +++ b/config/scout.php @@ -135,7 +135,7 @@ 'key' => env('MEILISEARCH_KEY'), 'index-settings' => [ 'entities' => [ - 'filterableAttributes'=> ['id', 'campaign_id'], + 'filterableAttributes' => ['id', 'campaign_id'], ], ], ], From ef3111ddb0867d5ad1bb56ee0a2d4df52e6a2678 Mon Sep 17 00:00:00 2001 From: Spitfire Date: Wed, 15 Nov 2023 14:13:07 -0600 Subject: [PATCH 06/15] Meilisearch Alpha changes --- app/Models/Attribute.php | 15 ++--- app/Models/AttributeTemplate.php | 11 ++-- app/Models/MiscModel.php | 15 ++--- app/Models/Post.php | 4 +- app/Models/QuestElement.php | 17 ++--- app/Models/TimelineElement.php | 15 ++--- app/Services/Search/EntitySearchService.php | 72 +++++++++++++-------- docs/meilisearch.md | 33 ++++++++++ 8 files changed, 107 insertions(+), 75 deletions(-) create mode 100644 docs/meilisearch.md diff --git a/app/Models/Attribute.php b/app/Models/Attribute.php index 5a8af8fbdf..931ed7e67e 100644 --- a/app/Models/Attribute.php +++ b/app/Models/Attribute.php @@ -394,16 +394,13 @@ protected function makeAllSearchableUsing($query) public function toSearchableArray() { - $array = $this->toArray(); - $entity = $this->entity->toArray(); - return [ - 'campaign_id' => $entity['campaign_id'], - 'entity_id' => $entity['id'], - 'entity_name' => $entity['name'], - 'name' => $array['name'], - 'type' => 'attribute', - 'value' => $array['value'], + 'campaign_id' => $this->entity->campaign_id, + 'entity_id' => $this->entity->id, + 'entity_name' => $this->entity->name, + 'name' => $this->name, + 'type' => 'attribute', + 'value' => $this->entry, ]; } } diff --git a/app/Models/AttributeTemplate.php b/app/Models/AttributeTemplate.php index f716277252..ef4047c100 100644 --- a/app/Models/AttributeTemplate.php +++ b/app/Models/AttributeTemplate.php @@ -279,14 +279,11 @@ public function datagridSortableColumns(): array public function toSearchableArray() { - $array = $this->toArray(); - $entity = $this->entity->toArray(); - return [ - 'campaign_id' => $entity['campaign_id'], - 'entity_id' => $entity['id'], - 'entity_name' => $entity['name'], - 'name' => $array['name'], + 'campaign_id' => $this->entity->campaign_id, + 'entity_id' => $this->entity->id, + 'entity_name' => $this->entity->name, + 'name' => $this->name, ]; } } diff --git a/app/Models/MiscModel.php b/app/Models/MiscModel.php index 01568f31b1..27141a7ec7 100644 --- a/app/Models/MiscModel.php +++ b/app/Models/MiscModel.php @@ -662,16 +662,13 @@ protected function makeAllSearchableUsing($query) public function toSearchableArray() { - $array = $this->toArray(); - $entity = $this->entity->toArray(); - return [ - 'campaign_id' => $array['campaign_id'], - 'entity_id' => $entity['id'], - 'entity_name' => $entity['name'], - 'name' => $array['name'], - 'type' => $array['type'], - 'entry' => $array['entry'], + 'campaign_id' => $this->entity->campaign_id, + 'entity_id' => $this->entity->id, + 'entity_name' => $this->entity->name, + 'name' => $this->name, + 'type' => $this->type, + 'entry' => $this->entry, ]; } } diff --git a/app/Models/Post.php b/app/Models/Post.php index 359fe60945..619ca52408 100644 --- a/app/Models/Post.php +++ b/app/Models/Post.php @@ -213,9 +213,7 @@ protected function makeAllSearchableUsing($query) { return $query ->select([$this->getTable() . '.*', 'entities.id as entity_id']) - ->leftJoin('entities', function ($join) { - $join->on('entities.entity_id', $this->getTable() . '.id'); - }); + ->leftJoin('entities', 'posts.entity_id', '=', 'entities.id'); } public function toSearchableArray() diff --git a/app/Models/QuestElement.php b/app/Models/QuestElement.php index aff5c8ed25..d1cdd436f6 100644 --- a/app/Models/QuestElement.php +++ b/app/Models/QuestElement.php @@ -145,28 +145,23 @@ public function searchableAs(): string protected function makeAllSearchableUsing($query) { - return $query - ->leftJoin('quests', 'quests.id', '=', 'quest_elements.quest_id') ->select([$this->getTable() . '.*', 'entities.id as entity_id']) + ->leftJoin('quests', 'quests.id', '=', 'quest_elements.quest_id') ->leftJoin('entities', function ($join) { $join->on('entities.entity_id', $this->getTable() . '.id'); - //->where('entities.type_id', $this->entityTypeId()); }); } public function toSearchableArray() { - $array = $this->toArray(); - $entity = $this->quest->entity->toArray(); - return [ - 'campaign_id' => $entity['campaign_id'], - 'entity_id' => $entity['id'], - 'entity_name' => $entity['name'], - 'name' => $array['name'], + 'campaign_id' => $this->quest->entity->campaign_id, + 'entity_id' => $this->quest->entity->id, + 'entity_name' => $this->quest->entity->name, + 'name' => $this->name, 'type' => 'quest_element', - 'entry' => $array['description'], + 'entry' => $this->description, ]; } } diff --git a/app/Models/TimelineElement.php b/app/Models/TimelineElement.php index bc00ea9125..1d0e0fab4f 100644 --- a/app/Models/TimelineElement.php +++ b/app/Models/TimelineElement.php @@ -226,8 +226,8 @@ public function searchableAs(): string protected function makeAllSearchableUsing($query) { return $query - ->leftJoin('timelines', 'timelines.id', '=', 'timeline_elements.timeline_id') ->select([$this->getTable() . '.*', 'entities.id as entity_id']) + ->leftJoin('timelines', 'timelines.id', '=', 'timeline_elements.timeline_id') ->leftJoin('entities', function ($join) { $join->on('entities.entity_id', $this->getTable() . '.id'); }); @@ -235,16 +235,13 @@ protected function makeAllSearchableUsing($query) public function toSearchableArray() { - $array = $this->toArray(); - $entity = $this->timeline->entity->toArray(); - return [ - 'campaign_id' => $entity['campaign_id'], - 'entity_id' => $entity['id'], - 'entity_name' => $entity['name'], - 'name' => $array['name'], + 'campaign_id' => $this->timeline->entity->campaign_id, + 'entity_id' => $this->timeline->entity->id, + 'entity_name' => $this->timeline->entity->name, + 'name' => $this->name, 'type' => 'timeline_element', - 'entry' => $array['entry'], + 'entry' => $this->entry, ]; } } diff --git a/app/Services/Search/EntitySearchService.php b/app/Services/Search/EntitySearchService.php index c49438c2ce..a3ee4ae22a 100644 --- a/app/Services/Search/EntitySearchService.php +++ b/app/Services/Search/EntitySearchService.php @@ -10,11 +10,15 @@ use App\Traits\CampaignAware; use Meilisearch\Client; - class EntitySearchService { use CampaignAware; + protected array $ids = []; + protected array $attributeIds = []; + protected array $timelineElementIds = []; + protected array $postIds = []; + protected array $questElementIds = []; /** * Send search request @@ -22,48 +26,62 @@ class EntitySearchService */ public function search(string $term = null): array { - $client = new Client('http://meilisearch:7700', 'password'); + //Get results from Meilisearch + $client = new Client(config('scout.meilisearch.host'), config('scout.meilisearch.key')); $client->getKeys(); - $ids = []; - $results = $client->index('entities')->search($term, ['filter' => 'campaign_id = ' . $this->campaign->id, 'attributesToRetrieve' => ['id', 'entity_id', 'type'], 'limit' => 20])->getHits(); - $attributeIds = []; - $timelineElementIds = []; - $postIds = []; - $questElementIds = []; + $results = $client->index('entities')->search($term, ['filter' => 'campaign_id = ' . $this->campaign->id, 'attributesToRetrieve' => ['id', 'entity_id', 'type'], 'attributesToSearchOn' => ['name', 'entry', 'entity_name', 'value'], 'limit' => 20])->getHits(); + + return $this->process($results)->fetch(); + } + /** + * Process results to fetch entities from db + * @param array $results Search term + */ + protected function process(array $results = []): self + { foreach ($results as $result) { if ($result['type'] == 'quest_element') { $id = substr($result['id'], -1, strrpos($result['id'], '_')); - $questElementIds[$result['entity_id']] = $id; - //dd($result); + $this->questElementIds[$result['entity_id']] = $id; } elseif ($result['type'] == 'timeline_element') { $id = substr($result['id'], -1, strrpos($result['id'], '_')); - $timelineElementIds[$result['entity_id']] = $id; - //dd($result); + $this->timelineElementIds[$result['entity_id']] = $id; } elseif ($result['type'] == 'post') { $id = substr($result['id'], -1, strrpos($result['id'], '_')); - $postIds[$result['entity_id']] = $id; - //dd($result); + $this->postIds[$result['entity_id']] = $id; } elseif ($result['type'] == 'attribute') { $id = substr($result['id'], -1, strrpos($result['id'], '_')); - $attributeIds[$result['entity_id']] = $id; - //dd($result); + $this->attributeIds[$result['entity_id']] = $id; } else { - $ids[$result['entity_id']] = $result['entity_id']; + $this->ids[$result['entity_id']] = $result['entity_id']; } } + //If the search also threw the entity as a possible result dont bother loading the other models - $attributeIds = array_diff_key($attributeIds, $ids); - $timelineElementIds = array_diff_key($timelineElementIds, $ids); - $questElementIds = array_diff_key($questElementIds, $ids); - $postIds = array_diff_key($postIds, $ids); + $this->attributeIds = array_diff_key($this->attributeIds, $this->ids); + $this->timelineElementIds = array_diff_key($this->timelineElementIds, $this->ids); + $this->questElementIds = array_diff_key($this->questElementIds, $this->ids); + $this->postIds = array_diff_key($this->postIds, $this->ids); + + return $this; + } + + /** + * Fetch entities from DB + */ + protected function fetch(): array + { + $posts = Post::whereIn('id', $this->postIds)->get(); + $attributes = Attribute::with('entity')->has('entity')->whereIn('id', $this->attributeIds)->get(); + $questElements = QuestElement::with(['quest', 'quest.entity'])->has('quest')->whereIn('id', $this->questElementIds)->get(); + $timelineElements = TimelineElement::with(['timeline', 'timeline.entity'])->has('timeline')->whereIn('id', $this->timelineElementIds)->get(); - $posts = Post::whereIn('id', $postIds)->get(); - $attributes = Attribute::with('entity')->has('entity')->whereIn('id', $attributeIds)->get(); - $questElements = QuestElement::with(['quest', 'quest.entity'])->has('quest')->has('quest')->whereIn('id', $questElementIds)->get(); - $timelineElements = TimelineElement::with(['timeline', 'timeline.entity'])->has('timeline')->whereIn('id', $timelineElementIds)->get(); + //Get entities from db + $entities = Entity::whereIn('id', $this->ids)->get(); - $entities = Entity::whereIn('id', $ids)->get(); + //Process entities for output + $output = []; foreach ($entities as $entity) { $output[$entity->id] = ['id' => $entity->id, 'entity' => $entity->name, 'url' => $entity->url()]; } @@ -71,7 +89,7 @@ public function search(string $term = null): array $output[$attribute->entity->id] = ['id' => $attribute->entity->id, 'entity' => $attribute->entity->name, 'url' => $attribute->entity->url()]; } foreach ($posts as $post) { - $output[$post->entity->id] = ['id' => $post->entity->id, 'entity' => $post->entity->name, 'url' => $post->url()]; + $output[$post->entity->id] = ['id' => $post->entity->id, 'entity' => $post->entity->name, 'url' => $post->entity->url()]; } foreach ($questElements as $questElement) { $output[$questElement->quest->entity->id] = ['id' => $questElement->quest->entity->id, 'entity' => $questElement->quest->name, 'url' => $questElement->quest->entity->url()]; diff --git a/docs/meilisearch.md b/docs/meilisearch.md new file mode 100644 index 0000000000..8d28067034 --- /dev/null +++ b/docs/meilisearch.md @@ -0,0 +1,33 @@ +# Setup + +Before importing entities to meilisearch is important to do some setup, first of all there are some .ENV +parameters to be set. + +`SCOUT_DRIVER` tells scout which search engine to use, it should be set to `meilisearch`. + +`SCOUT_QUEUE` tells scout if it should use the jobs queue if set to true or not if set to false/not set. + +`MEILISEARCH_HOST` is the url of the meilisearch server, where the requests will be sent to, by default its set to: `http://meilisearch:7700` which is usually the route for a local test setup. + +`MEILISEARCH_KEY` is the key/password which authorizes read/write to the Meilisearch database, information on how to set it up can be found on Meilisearch's docs: `https://www.meilisearch.com/docs/learn/security/master_api_keys`. + +Now we can start importing the entities. + +# Importing entities + +To import entities we need to run: + +> sail artisan scout:import "App\Models\ModelName" + +This has to be run for each model type we wish to import to the Meilisearch database, for example if we wish to import TimelineElements and Characters we would do: + +> sail artisan scout:import "App\Models\TimelineElements" + +> sail artisan scout:import "App\Models\Characters" + +Its also important to run this following command the first time meilisearch is set up and whenever any of the index settings on `config/scout.php` are modified: + +> sail artisan scout:sync-index-settings + + + From 690f141367bb3eaa485d6db563cf8ebf4d92dd35 Mon Sep 17 00:00:00 2001 From: spitfire305 Date: Wed, 15 Nov 2023 20:16:39 +0000 Subject: [PATCH 07/15] Fix styling --- app/Models/Post.php | 4 ++-- app/Models/QuestElement.php | 10 +++++----- app/Models/TimelineElement.php | 10 +++++----- app/Services/Search/EntitySearchService.php | 20 ++++++++++---------- 4 files changed, 22 insertions(+), 22 deletions(-) diff --git a/app/Models/Post.php b/app/Models/Post.php index 026fbc5606..ae0e0c833d 100644 --- a/app/Models/Post.php +++ b/app/Models/Post.php @@ -211,8 +211,8 @@ public function searchableAs(): string protected function makeAllSearchableUsing($query) { return $query - ->select([$this->getTable() . '.*', 'entities.id as entity_id']) - ->leftJoin('entities', 'posts.entity_id', '=', 'entities.id'); + ->select([$this->getTable() . '.*', 'entities.id as entity_id']) + ->leftJoin('entities', 'posts.entity_id', '=', 'entities.id'); } public function toSearchableArray() diff --git a/app/Models/QuestElement.php b/app/Models/QuestElement.php index 70b14b8a3f..80271a3e23 100644 --- a/app/Models/QuestElement.php +++ b/app/Models/QuestElement.php @@ -145,11 +145,11 @@ public function searchableAs(): string protected function makeAllSearchableUsing($query) { return $query - ->select([$this->getTable() . '.*', 'entities.id as entity_id']) - ->leftJoin('quests', 'quests.id', '=', 'quest_elements.quest_id') - ->leftJoin('entities', function ($join) { - $join->on('entities.entity_id', $this->getTable() . '.id'); - }); + ->select([$this->getTable() . '.*', 'entities.id as entity_id']) + ->leftJoin('quests', 'quests.id', '=', 'quest_elements.quest_id') + ->leftJoin('entities', function ($join) { + $join->on('entities.entity_id', $this->getTable() . '.id'); + }); } public function toSearchableArray() diff --git a/app/Models/TimelineElement.php b/app/Models/TimelineElement.php index f19a0190b8..a5cd7ae9df 100644 --- a/app/Models/TimelineElement.php +++ b/app/Models/TimelineElement.php @@ -225,11 +225,11 @@ public function searchableAs(): string protected function makeAllSearchableUsing($query) { return $query - ->select([$this->getTable() . '.*', 'entities.id as entity_id']) - ->leftJoin('timelines', 'timelines.id', '=', 'timeline_elements.timeline_id') - ->leftJoin('entities', function ($join) { - $join->on('entities.entity_id', $this->getTable() . '.id'); - }); + ->select([$this->getTable() . '.*', 'entities.id as entity_id']) + ->leftJoin('timelines', 'timelines.id', '=', 'timeline_elements.timeline_id') + ->leftJoin('entities', function ($join) { + $join->on('entities.entity_id', $this->getTable() . '.id'); + }); } public function toSearchableArray() diff --git a/app/Services/Search/EntitySearchService.php b/app/Services/Search/EntitySearchService.php index c567a8f5d9..ec98b3d7a7 100644 --- a/app/Services/Search/EntitySearchService.php +++ b/app/Services/Search/EntitySearchService.php @@ -29,7 +29,7 @@ public function search(string $term = null): array $client = new Client(config('scout.meilisearch.host'), config('scout.meilisearch.key')); $client->getKeys(); $results = $client->index('entities')->search($term, ['filter' => 'campaign_id = ' . $this->campaign->id, 'attributesToRetrieve' => ['id', 'entity_id', 'type'], 'attributesToSearchOn' => ['name', 'entry', 'entity_name', 'value'], 'limit' => 20])->getHits(); - + return $this->process($results)->fetch(); } @@ -41,21 +41,21 @@ protected function process(array $results = []): self { foreach ($results as $result) { if ($result['type'] == 'quest_element') { - $id = substr($result['id'], -1, strrpos($result['id'], '_')); + $id = mb_substr($result['id'], -1, mb_strrpos($result['id'], '_')); $questElementIds[$result['entity_id']] = $id; - //dd($result); + //dd($result); } elseif ($result['type'] == 'timeline_element') { - $id = substr($result['id'], -1, strrpos($result['id'], '_')); + $id = mb_substr($result['id'], -1, mb_strrpos($result['id'], '_')); $timelineElementIds[$result['entity_id']] = $id; - //dd($result); + //dd($result); } elseif ($result['type'] == 'post') { - $id = substr($result['id'], -1, strrpos($result['id'], '_')); + $id = mb_substr($result['id'], -1, mb_strrpos($result['id'], '_')); $postIds[$result['entity_id']] = $id; - //dd($result); + //dd($result); } elseif ($result['type'] == 'attribute') { - $id = substr($result['id'], -1, strrpos($result['id'], '_')); + $id = mb_substr($result['id'], -1, mb_strrpos($result['id'], '_')); $attributeIds[$result['entity_id']] = $id; - //dd($result); + //dd($result); } else { $this->ids[$result['entity_id']] = $result['entity_id']; } @@ -66,7 +66,7 @@ protected function process(array $results = []): self $this->timelineElementIds = array_diff_key($this->timelineElementIds, $this->ids); $this->questElementIds = array_diff_key($this->questElementIds, $this->ids); $this->postIds = array_diff_key($this->postIds, $this->ids); - + return $this; } From 48a14ef4b11e54e0a091214f8fb692ecde90d105 Mon Sep 17 00:00:00 2001 From: ilestis Date: Mon, 20 Nov 2023 08:57:59 -0600 Subject: [PATCH 08/15] Update docs and add general setup for speedup --- app/Console/Commands/SetupMeilisearch.php | 77 +++++++++++++++++++++++ app/Models/MiscModel.php | 3 +- app/Models/Post.php | 3 +- app/Models/QuestElement.php | 4 +- app/Models/TimelineElement.php | 4 +- docs/meilisearch.md | 16 +++-- 6 files changed, 99 insertions(+), 8 deletions(-) create mode 100644 app/Console/Commands/SetupMeilisearch.php diff --git a/app/Console/Commands/SetupMeilisearch.php b/app/Console/Commands/SetupMeilisearch.php new file mode 100644 index 0000000000..ebd2702923 --- /dev/null +++ b/app/Console/Commands/SetupMeilisearch.php @@ -0,0 +1,77 @@ +option('chunk')); + $this->info('All ['.$model.'] records have been imported.'); + } + } +} diff --git a/app/Models/MiscModel.php b/app/Models/MiscModel.php index c485a3132c..e6a18e7a57 100644 --- a/app/Models/MiscModel.php +++ b/app/Models/MiscModel.php @@ -656,7 +656,8 @@ protected function makeAllSearchableUsing($query) ->leftJoin('entities', function ($join) { $join->on('entities.entity_id', $this->getTable() . '.id') ->where('entities.type_id', $this->entityTypeId()); - }); + }) + ->has('entity'); } public function toSearchableArray() diff --git a/app/Models/Post.php b/app/Models/Post.php index ae0e0c833d..d7884c943d 100644 --- a/app/Models/Post.php +++ b/app/Models/Post.php @@ -212,7 +212,8 @@ protected function makeAllSearchableUsing($query) { return $query ->select([$this->getTable() . '.*', 'entities.id as entity_id']) - ->leftJoin('entities', 'posts.entity_id', '=', 'entities.id'); + ->leftJoin('entities', 'posts.entity_id', '=', 'entities.id') + ->has('entity'); } public function toSearchableArray() diff --git a/app/Models/QuestElement.php b/app/Models/QuestElement.php index 80271a3e23..f39d89a461 100644 --- a/app/Models/QuestElement.php +++ b/app/Models/QuestElement.php @@ -149,7 +149,9 @@ protected function makeAllSearchableUsing($query) ->leftJoin('quests', 'quests.id', '=', 'quest_elements.quest_id') ->leftJoin('entities', function ($join) { $join->on('entities.entity_id', $this->getTable() . '.id'); - }); + }) + ->has('quest') + ->has('quest.entity'); } public function toSearchableArray() diff --git a/app/Models/TimelineElement.php b/app/Models/TimelineElement.php index a5cd7ae9df..7884c51b2a 100644 --- a/app/Models/TimelineElement.php +++ b/app/Models/TimelineElement.php @@ -229,7 +229,9 @@ protected function makeAllSearchableUsing($query) ->leftJoin('timelines', 'timelines.id', '=', 'timeline_elements.timeline_id') ->leftJoin('entities', function ($join) { $join->on('entities.entity_id', $this->getTable() . '.id'); - }); + }) + ->has('timeline') + ->has('timeline.entity'); } public function toSearchableArray() diff --git a/docs/meilisearch.md b/docs/meilisearch.md index 8d28067034..4251f41a94 100644 --- a/docs/meilisearch.md +++ b/docs/meilisearch.md @@ -7,15 +7,21 @@ parameters to be set. `SCOUT_QUEUE` tells scout if it should use the jobs queue if set to true or not if set to false/not set. -`MEILISEARCH_HOST` is the url of the meilisearch server, where the requests will be sent to, by default its set to: `http://meilisearch:7700` which is usually the route for a local test setup. +`MEILISEARCH_HOST` is the url of the meilisearch server, where the requests will be sent to, by default its set to: `http://localhost:7700` which is usually the route for a local test setup. -`MEILISEARCH_KEY` is the key/password which authorizes read/write to the Meilisearch database, information on how to set it up can be found on Meilisearch's docs: `https://www.meilisearch.com/docs/learn/security/master_api_keys`. +`MEILISEARCH_KEY` is the key/password which authorizes read/write to the meilisearch database, information on how to set it up can be found on Meilisearch's docs: `https://www.meilisearch.com/docs/learn/security/master_api_keys`. Now we can start importing the entities. # Importing entities -To import entities we need to run: +To import all entities that are setup to work with meilisearch, run: + +> sail artisan setup:meilisearch + +## Individual models + +To import entities from an individual model, run: > sail artisan scout:import "App\Models\ModelName" @@ -25,7 +31,9 @@ This has to be run for each model type we wish to import to the Meilisearch data > sail artisan scout:import "App\Models\Characters" -Its also important to run this following command the first time meilisearch is set up and whenever any of the index settings on `config/scout.php` are modified: +# Config change + +It's also important to run this following command the first time meilisearch is set up and whenever any of the index settings on `config/scout.php` are modified: > sail artisan scout:sync-index-settings From 5077c7168af3246e2aa5463e3b7459a69537b640 Mon Sep 17 00:00:00 2001 From: ilestis Date: Mon, 20 Nov 2023 09:16:38 -0600 Subject: [PATCH 09/15] Update config --- app/Console/Commands/SetupMeilisearch.php | 2 ++ .../Api/v1/FullTextSearchApiController.php | 4 ++- app/Models/Attribute.php | 8 +++-- app/Models/Post.php | 15 ++++----- app/Services/Search/EntitySearchService.php | 32 ++++++++++++------- docs/meilisearch.md | 6 +++- 6 files changed, 42 insertions(+), 25 deletions(-) diff --git a/app/Console/Commands/SetupMeilisearch.php b/app/Console/Commands/SetupMeilisearch.php index ebd2702923..a520b2b4dd 100644 --- a/app/Console/Commands/SetupMeilisearch.php +++ b/app/Console/Commands/SetupMeilisearch.php @@ -3,6 +3,7 @@ namespace App\Console\Commands; use App\Models\Ability; +use App\Models\Attribute; use App\Models\Calendar; use App\Models\Character; use App\Models\Creature; @@ -48,6 +49,7 @@ class SetupMeilisearch extends Command public function handle() { $models = [ + Attribute::class, Ability::class, Calendar::class, Character::class, diff --git a/app/Http/Controllers/Api/v1/FullTextSearchApiController.php b/app/Http/Controllers/Api/v1/FullTextSearchApiController.php index 4b974a6e6a..0414461ce1 100644 --- a/app/Http/Controllers/Api/v1/FullTextSearchApiController.php +++ b/app/Http/Controllers/Api/v1/FullTextSearchApiController.php @@ -23,7 +23,9 @@ public function index(Campaign $campaign) { $this->authorize('access', $campaign); - $results = $this->service->campaign($campaign)->search(request()->term); + $results = $this->service + ->campaign($campaign) + ->search(request()->term); //dd($results); return $results; diff --git a/app/Models/Attribute.php b/app/Models/Attribute.php index 9ce772c1f8..1e4d2b35fe 100644 --- a/app/Models/Attribute.php +++ b/app/Models/Attribute.php @@ -388,18 +388,20 @@ public function searchableAs(): string protected function makeAllSearchableUsing($query) { return $query - ->leftJoin('entities', 'attributes.entity_id', '=', 'entities.id'); + ->select([$this->getTable() . '.*', 'entities.id as entity_id']) + ->leftJoin('entities', $this->getTable() . '.entity_id', '=', 'entities.id') + ->has('entity'); } public function toSearchableArray() { return [ 'campaign_id' => $this->entity->campaign_id, - 'entity_id' => $this->entity->id, + 'entity_id' => $this->entity_id, 'entity_name' => $this->entity->name, 'name' => $this->name, 'type' => 'attribute', - 'value' => $this->entry, + 'entry' => $this->value, ]; } } diff --git a/app/Models/Post.php b/app/Models/Post.php index d7884c943d..815d24c13f 100644 --- a/app/Models/Post.php +++ b/app/Models/Post.php @@ -212,22 +212,19 @@ protected function makeAllSearchableUsing($query) { return $query ->select([$this->getTable() . '.*', 'entities.id as entity_id']) - ->leftJoin('entities', 'posts.entity_id', '=', 'entities.id') + ->leftJoin('entities', $this->getTable() . '.entity_id', '=', 'entities.id') ->has('entity'); } public function toSearchableArray() { - $array = $this->toArray(); - $entity = $this->entity->toArray(); - return [ - 'campaign_id' => $entity['campaign_id'], - 'entity_id' => $entity['id'], - 'entity_name' => $entity['name'], - 'name' => $array['name'], + 'campaign_id' => $this->entity->campaign_id, + 'entity_id' => $this->entity_id, + 'entity_name' => $this->entity->name, + 'name' => $this->name, 'type' => 'post', - 'entry' => $array['entry'], + 'entry' => $this->entry, ]; } } diff --git a/app/Services/Search/EntitySearchService.php b/app/Services/Search/EntitySearchService.php index ec98b3d7a7..a64451cfba 100644 --- a/app/Services/Search/EntitySearchService.php +++ b/app/Services/Search/EntitySearchService.php @@ -8,6 +8,7 @@ use App\Models\TimelineElement; use App\Models\Post; use App\Traits\CampaignAware; +use Illuminate\Support\Str; use Meilisearch\Client; class EntitySearchService @@ -28,7 +29,17 @@ public function search(string $term = null): array //Get results from Meilisearch $client = new Client(config('scout.meilisearch.host'), config('scout.meilisearch.key')); $client->getKeys(); - $results = $client->index('entities')->search($term, ['filter' => 'campaign_id = ' . $this->campaign->id, 'attributesToRetrieve' => ['id', 'entity_id', 'type'], 'attributesToSearchOn' => ['name', 'entry', 'entity_name', 'value'], 'limit' => 20])->getHits(); + $results = $client->index('entities') + ->search($term, [ + 'filter' => 'campaign_id = ' . $this->campaign->id, + 'attributesToRetrieve' => [ + 'id', 'entity_id', 'type' + ], + 'attributesToSearchOn' => [ + 'name', 'entry', 'entity_name', 'value' + ], + 'limit' => 20 + ])->getHits(); return $this->process($results)->fetch(); } @@ -41,27 +52,27 @@ protected function process(array $results = []): self { foreach ($results as $result) { if ($result['type'] == 'quest_element') { - $id = mb_substr($result['id'], -1, mb_strrpos($result['id'], '_')); - $questElementIds[$result['entity_id']] = $id; + $id = Str::afterLast($result['id'], '_'); + $this->questElementIds[$result['entity_id']] = $id; //dd($result); } elseif ($result['type'] == 'timeline_element') { - $id = mb_substr($result['id'], -1, mb_strrpos($result['id'], '_')); - $timelineElementIds[$result['entity_id']] = $id; + $id = Str::afterLast($result['id'], '_'); + $this->timelineElementIds[$result['entity_id']] = $id; //dd($result); } elseif ($result['type'] == 'post') { - $id = mb_substr($result['id'], -1, mb_strrpos($result['id'], '_')); - $postIds[$result['entity_id']] = $id; + $id = Str::afterLast($result['id'], '_'); + $this->postIds[$result['entity_id']] = $id; //dd($result); } elseif ($result['type'] == 'attribute') { - $id = mb_substr($result['id'], -1, mb_strrpos($result['id'], '_')); - $attributeIds[$result['entity_id']] = $id; + $id = Str::afterLast($result['id'], '_'); + $this->attributeIds[$result['entity_id']] = $id; //dd($result); } else { $this->ids[$result['entity_id']] = $result['entity_id']; } } - //If the search also threw the entity as a possible result dont bother loading the other models + //If the search also threw the entity as a possible result don't bother loading the other models $this->attributeIds = array_diff_key($this->attributeIds, $this->ids); $this->timelineElementIds = array_diff_key($this->timelineElementIds, $this->ids); $this->questElementIds = array_diff_key($this->questElementIds, $this->ids); @@ -103,5 +114,4 @@ protected function fetch(): array return $output; } - } diff --git a/docs/meilisearch.md b/docs/meilisearch.md index 4251f41a94..faee692c18 100644 --- a/docs/meilisearch.md +++ b/docs/meilisearch.md @@ -35,7 +35,11 @@ This has to be run for each model type we wish to import to the Meilisearch data It's also important to run this following command the first time meilisearch is set up and whenever any of the index settings on `config/scout.php` are modified: -> sail artisan scout:sync-index-settings +> sail artisan scout:sync-index-settings +# Testing +Call the following api endpoint with a valid token + +> http://api.kanka.test:8081/1.0/campaigns/xxx/fulltext-search?term=adam From 0f567389a0b52f20886124319cdfee2080d950fb Mon Sep 17 00:00:00 2001 From: ilestis Date: Mon, 20 Nov 2023 09:37:46 -0600 Subject: [PATCH 10/15] Meilisearch: default order --- app/Services/Search/EntitySearchService.php | 2 +- config/scout.php | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app/Services/Search/EntitySearchService.php b/app/Services/Search/EntitySearchService.php index a64451cfba..190ca05be5 100644 --- a/app/Services/Search/EntitySearchService.php +++ b/app/Services/Search/EntitySearchService.php @@ -92,7 +92,7 @@ protected function fetch(): array $timelineElements = TimelineElement::with(['timeline', 'timeline.entity'])->has('timeline')->whereIn('id', $this->timelineElementIds)->get(); //Get entities from db - $entities = Entity::whereIn('id', $this->ids)->get(); + $entities = Entity::whereIn('id', $this->ids)->orderBy('name')->get(); //Process entities for output $output = []; diff --git a/config/scout.php b/config/scout.php index eba1bb4590..60bdde2141 100644 --- a/config/scout.php +++ b/config/scout.php @@ -136,6 +136,7 @@ 'index-settings' => [ 'entities' => [ 'filterableAttributes' => ['id', 'campaign_id'], + 'sortableAttributes' => ['name', 'entry'], ], ], ], From fc3e6fdc17e81ba827a98f776e9a89c1a1a0fce8 Mon Sep 17 00:00:00 2001 From: Spitfire Date: Mon, 27 Nov 2023 15:48:26 -0600 Subject: [PATCH 11/15] Melisearch WIP 2 --- .../Api/v1/FullTextSearchApiController.php | 16 +++++++++------- app/Models/Attribute.php | 3 ++- app/Models/MiscModel.php | 3 ++- app/Models/Post.php | 3 ++- app/Models/QuestElement.php | 3 ++- app/Models/TimelineElement.php | 3 ++- 6 files changed, 19 insertions(+), 12 deletions(-) diff --git a/app/Http/Controllers/Api/v1/FullTextSearchApiController.php b/app/Http/Controllers/Api/v1/FullTextSearchApiController.php index 0414461ce1..a7393f423e 100644 --- a/app/Http/Controllers/Api/v1/FullTextSearchApiController.php +++ b/app/Http/Controllers/Api/v1/FullTextSearchApiController.php @@ -3,6 +3,7 @@ namespace App\Http\Controllers\Api\v1; use App\Models\Campaign; +use App\Models\Entity; use App\Http\Resources\EntityResource as Resource; use App\Services\Search\EntitySearchService; @@ -22,16 +23,17 @@ public function __construct(EntitySearchService $service) public function index(Campaign $campaign) { $this->authorize('access', $campaign); + $term = request()->term; + $entity = Entity::where(['name' => request()->term, 'campaign_id' => $campaign->id])->first(); + if ($entity) { + $term = $term . ' [' . $entity->type() . ':' . $entity->id . ']'; + + } $results = $this->service ->campaign($campaign) - ->search(request()->term); - //dd($results); - return $results; - - return Resource::collection($campaign->entities()->whereIn('id', $results) - ->paginate() - ->appends(request()->except(['page', 'lastSync']))); + ->search($term); + return $results; } } diff --git a/app/Models/Attribute.php b/app/Models/Attribute.php index 1e4d2b35fe..e04fc9a2d3 100644 --- a/app/Models/Attribute.php +++ b/app/Models/Attribute.php @@ -390,7 +390,8 @@ protected function makeAllSearchableUsing($query) return $query ->select([$this->getTable() . '.*', 'entities.id as entity_id']) ->leftJoin('entities', $this->getTable() . '.entity_id', '=', 'entities.id') - ->has('entity'); + ->has('entity') + ->with('entity'); } public function toSearchableArray() diff --git a/app/Models/MiscModel.php b/app/Models/MiscModel.php index e6a18e7a57..12b25a2c55 100644 --- a/app/Models/MiscModel.php +++ b/app/Models/MiscModel.php @@ -657,7 +657,8 @@ protected function makeAllSearchableUsing($query) $join->on('entities.entity_id', $this->getTable() . '.id') ->where('entities.type_id', $this->entityTypeId()); }) - ->has('entity'); + ->has('entity') + ->with('entity'); } public function toSearchableArray() diff --git a/app/Models/Post.php b/app/Models/Post.php index 815d24c13f..eabbb88f58 100644 --- a/app/Models/Post.php +++ b/app/Models/Post.php @@ -213,7 +213,8 @@ protected function makeAllSearchableUsing($query) return $query ->select([$this->getTable() . '.*', 'entities.id as entity_id']) ->leftJoin('entities', $this->getTable() . '.entity_id', '=', 'entities.id') - ->has('entity'); + ->has('entity') + ->with('entity'); } public function toSearchableArray() diff --git a/app/Models/QuestElement.php b/app/Models/QuestElement.php index f39d89a461..724978902e 100644 --- a/app/Models/QuestElement.php +++ b/app/Models/QuestElement.php @@ -151,7 +151,8 @@ protected function makeAllSearchableUsing($query) $join->on('entities.entity_id', $this->getTable() . '.id'); }) ->has('quest') - ->has('quest.entity'); + ->has('quest.entity') + ->with('quest', 'quest.entity'); } public function toSearchableArray() diff --git a/app/Models/TimelineElement.php b/app/Models/TimelineElement.php index 7884c51b2a..0c37b4ce80 100644 --- a/app/Models/TimelineElement.php +++ b/app/Models/TimelineElement.php @@ -231,7 +231,8 @@ protected function makeAllSearchableUsing($query) $join->on('entities.entity_id', $this->getTable() . '.id'); }) ->has('timeline') - ->has('timeline.entity'); + ->has('timeline.entity') + ->with('timeline', 'timeline.entity'); } public function toSearchableArray() From 6f8252f84cd0a37bd9546f2027c4cceca2ba3f3f Mon Sep 17 00:00:00 2001 From: Spitfire Date: Mon, 27 Nov 2023 15:49:17 -0600 Subject: [PATCH 12/15] WIP --- app/Http/Controllers/Api/v1/FullTextSearchApiController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Http/Controllers/Api/v1/FullTextSearchApiController.php b/app/Http/Controllers/Api/v1/FullTextSearchApiController.php index a7393f423e..a86a4a6716 100644 --- a/app/Http/Controllers/Api/v1/FullTextSearchApiController.php +++ b/app/Http/Controllers/Api/v1/FullTextSearchApiController.php @@ -26,7 +26,7 @@ public function index(Campaign $campaign) $term = request()->term; $entity = Entity::where(['name' => request()->term, 'campaign_id' => $campaign->id])->first(); if ($entity) { - $term = $term . ' [' . $entity->type() . ':' . $entity->id . ']'; + $term = $term . ' [' . $entity->type() . ':' . $entity->id; } From 829762561e841fbc78edebcc81fbf40928201e3c Mon Sep 17 00:00:00 2001 From: Spitfire Date: Mon, 27 Nov 2023 15:57:21 -0600 Subject: [PATCH 13/15] Wip --- app/Http/Controllers/Api/v1/FullTextSearchApiController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Http/Controllers/Api/v1/FullTextSearchApiController.php b/app/Http/Controllers/Api/v1/FullTextSearchApiController.php index a86a4a6716..de87211bbb 100644 --- a/app/Http/Controllers/Api/v1/FullTextSearchApiController.php +++ b/app/Http/Controllers/Api/v1/FullTextSearchApiController.php @@ -26,7 +26,7 @@ public function index(Campaign $campaign) $term = request()->term; $entity = Entity::where(['name' => request()->term, 'campaign_id' => $campaign->id])->first(); if ($entity) { - $term = $term . ' [' . $entity->type() . ':' . $entity->id; + $term = '[' . $entity->type() . ':' . $entity->id . ' ' . $term; } From 7decd515b7e701187c9d906faa4f4bb161607bb3 Mon Sep 17 00:00:00 2001 From: Spitfire Date: Mon, 27 Nov 2023 18:16:39 -0600 Subject: [PATCH 14/15] WIP 3 --- app/Console/Commands/SetupMeilisearch.php | 7 +++++ .../Api/v1/FullTextSearchApiController.php | 6 ++-- app/Models/Attribute.php | 1 - app/Models/AttributeTemplate.php | 1 - app/Models/MiscModel.php | 1 - app/Models/Post.php | 1 - app/Models/QuestElement.php | 1 - app/Models/TimelineElement.php | 1 - app/Services/Search/EntitySearchService.php | 29 +++++++++++-------- 9 files changed, 26 insertions(+), 22 deletions(-) diff --git a/app/Console/Commands/SetupMeilisearch.php b/app/Console/Commands/SetupMeilisearch.php index a520b2b4dd..28e904c1bf 100644 --- a/app/Console/Commands/SetupMeilisearch.php +++ b/app/Console/Commands/SetupMeilisearch.php @@ -23,6 +23,7 @@ use App\Models\Timeline; use App\Models\TimelineElement; use Illuminate\Console\Command; +use Meilisearch\Client; class SetupMeilisearch extends Command { @@ -48,6 +49,12 @@ class SetupMeilisearch extends Command */ public function handle() { + //Update Non Separator Tokens for entity mentions + $client = new Client(config('scout.meilisearch.host'), config('scout.meilisearch.key')); + $client->getKeys(); + $client->index('entities')->resetSeparatorTokens(); + $client->index('entities') + ->updateNonSeparatorTokens([':']); $models = [ Attribute::class, Ability::class, diff --git a/app/Http/Controllers/Api/v1/FullTextSearchApiController.php b/app/Http/Controllers/Api/v1/FullTextSearchApiController.php index de87211bbb..a2481904cc 100644 --- a/app/Http/Controllers/Api/v1/FullTextSearchApiController.php +++ b/app/Http/Controllers/Api/v1/FullTextSearchApiController.php @@ -26,14 +26,12 @@ public function index(Campaign $campaign) $term = request()->term; $entity = Entity::where(['name' => request()->term, 'campaign_id' => $campaign->id])->first(); if ($entity) { - $term = '[' . $entity->type() . ':' . $entity->id . ' ' . $term; - + $term2 = $entity->type() . ':' . $entity->id; } $results = $this->service ->campaign($campaign) - ->search($term); - + ->search($term, $term2); return $results; } } diff --git a/app/Models/Attribute.php b/app/Models/Attribute.php index e04fc9a2d3..d5a522503a 100644 --- a/app/Models/Attribute.php +++ b/app/Models/Attribute.php @@ -399,7 +399,6 @@ public function toSearchableArray() return [ 'campaign_id' => $this->entity->campaign_id, 'entity_id' => $this->entity_id, - 'entity_name' => $this->entity->name, 'name' => $this->name, 'type' => 'attribute', 'entry' => $this->value, diff --git a/app/Models/AttributeTemplate.php b/app/Models/AttributeTemplate.php index ef4047c100..f33e2af8d3 100644 --- a/app/Models/AttributeTemplate.php +++ b/app/Models/AttributeTemplate.php @@ -282,7 +282,6 @@ public function toSearchableArray() return [ 'campaign_id' => $this->entity->campaign_id, 'entity_id' => $this->entity->id, - 'entity_name' => $this->entity->name, 'name' => $this->name, ]; } diff --git a/app/Models/MiscModel.php b/app/Models/MiscModel.php index 12b25a2c55..252e9b5200 100644 --- a/app/Models/MiscModel.php +++ b/app/Models/MiscModel.php @@ -666,7 +666,6 @@ public function toSearchableArray() return [ 'campaign_id' => $this->entity->campaign_id, 'entity_id' => $this->entity->id, - 'entity_name' => $this->entity->name, 'name' => $this->name, 'type' => $this->type, 'entry' => $this->entry, diff --git a/app/Models/Post.php b/app/Models/Post.php index eabbb88f58..b94c0992c4 100644 --- a/app/Models/Post.php +++ b/app/Models/Post.php @@ -222,7 +222,6 @@ public function toSearchableArray() return [ 'campaign_id' => $this->entity->campaign_id, 'entity_id' => $this->entity_id, - 'entity_name' => $this->entity->name, 'name' => $this->name, 'type' => 'post', 'entry' => $this->entry, diff --git a/app/Models/QuestElement.php b/app/Models/QuestElement.php index 724978902e..7f36f86fe6 100644 --- a/app/Models/QuestElement.php +++ b/app/Models/QuestElement.php @@ -160,7 +160,6 @@ public function toSearchableArray() return [ 'campaign_id' => $this->quest->entity->campaign_id, 'entity_id' => $this->quest->entity->id, - 'entity_name' => $this->quest->entity->name, 'name' => $this->name, 'type' => 'quest_element', 'entry' => $this->description, diff --git a/app/Models/TimelineElement.php b/app/Models/TimelineElement.php index 0c37b4ce80..31fe092d49 100644 --- a/app/Models/TimelineElement.php +++ b/app/Models/TimelineElement.php @@ -240,7 +240,6 @@ public function toSearchableArray() return [ 'campaign_id' => $this->timeline->entity->campaign_id, 'entity_id' => $this->timeline->entity->id, - 'entity_name' => $this->timeline->entity->name, 'name' => $this->name, 'type' => 'timeline_element', 'entry' => $this->entry, diff --git a/app/Services/Search/EntitySearchService.php b/app/Services/Search/EntitySearchService.php index 190ca05be5..55aa3331e6 100644 --- a/app/Services/Search/EntitySearchService.php +++ b/app/Services/Search/EntitySearchService.php @@ -10,6 +10,7 @@ use App\Traits\CampaignAware; use Illuminate\Support\Str; use Meilisearch\Client; +use Meilisearch\Contracts\SearchQuery; class EntitySearchService { @@ -24,22 +25,26 @@ class EntitySearchService /** * Send search request */ - public function search(string $term = null): array + public function search(string $term = null, string $term2 = null): array { //Get results from Meilisearch $client = new Client(config('scout.meilisearch.host'), config('scout.meilisearch.key')); $client->getKeys(); - $results = $client->index('entities') - ->search($term, [ - 'filter' => 'campaign_id = ' . $this->campaign->id, - 'attributesToRetrieve' => [ - 'id', 'entity_id', 'type' - ], - 'attributesToSearchOn' => [ - 'name', 'entry', 'entity_name', 'value' - ], - 'limit' => 20 - ])->getHits(); + + $results = $client->multiSearch([ + (new SearchQuery()) + ->setIndexUid('entities') + ->setQuery($term) + ->setAttributesToRetrieve(['id', 'entity_id', 'type']) + ->setLimit(10), + (new SearchQuery()) + ->setIndexUid('entities') + ->setQuery($term2) + ->setAttributesToRetrieve(['id', 'entity_id', 'type']) + ->setLimit(10), + ]); + + $results = array_merge($results['results'][0]['hits'], $results['results'][1]['hits']); return $this->process($results)->fetch(); } From 0f3b02bb4ccdc64b1d679b1e30753ff5039c4a48 Mon Sep 17 00:00:00 2001 From: spitfire305 Date: Thu, 21 Mar 2024 20:39:46 +0000 Subject: [PATCH 15/15] Fix styling --- app/Console/Commands/SetupMeilisearch.php | 4 ++-- .../Api/v1/FullTextSearchApiController.php | 1 - app/Observers/CampaignObserver.php | 2 +- app/Renderers/DatagridRenderer2.php | 2 +- app/Services/Search/EntitySearchService.php | 18 +++++++++--------- routes/api.v1.php | 2 +- 6 files changed, 14 insertions(+), 15 deletions(-) diff --git a/app/Console/Commands/SetupMeilisearch.php b/app/Console/Commands/SetupMeilisearch.php index 28e904c1bf..7e783100b5 100644 --- a/app/Console/Commands/SetupMeilisearch.php +++ b/app/Console/Commands/SetupMeilisearch.php @@ -78,9 +78,9 @@ public function handle() TimelineElement::class, ]; foreach ($models as $model) { - $object = new $model; + $object = new $model(); $object::makeAllSearchable($this->option('chunk')); - $this->info('All ['.$model.'] records have been imported.'); + $this->info('All [' . $model . '] records have been imported.'); } } } diff --git a/app/Http/Controllers/Api/v1/FullTextSearchApiController.php b/app/Http/Controllers/Api/v1/FullTextSearchApiController.php index a2481904cc..ea66227d49 100644 --- a/app/Http/Controllers/Api/v1/FullTextSearchApiController.php +++ b/app/Http/Controllers/Api/v1/FullTextSearchApiController.php @@ -4,7 +4,6 @@ use App\Models\Campaign; use App\Models\Entity; -use App\Http\Resources\EntityResource as Resource; use App\Services\Search\EntitySearchService; class FullTextSearchApiController extends ApiController diff --git a/app/Observers/CampaignObserver.php b/app/Observers/CampaignObserver.php index 0b32b8ca9e..268c13530c 100644 --- a/app/Observers/CampaignObserver.php +++ b/app/Observers/CampaignObserver.php @@ -53,7 +53,7 @@ public function saving(Campaign $campaign) $isPublic = request()->get('is_public', null); if (!empty($isPublic) && $previousVisibility == Campaign::VISIBILITY_PRIVATE) { $campaign->visibility_id = Campaign::VISIBILITY_PUBLIC; - // Default to public for now. Later will have REVIEW mode. + // Default to public for now. Later will have REVIEW mode. } elseif (empty($isPublic) && $previousVisibility != Campaign::VISIBILITY_PRIVATE) { $campaign->visibility_id = Campaign::VISIBILITY_PRIVATE; } diff --git a/app/Renderers/DatagridRenderer2.php b/app/Renderers/DatagridRenderer2.php index d475ea333a..3e9ccc320c 100644 --- a/app/Renderers/DatagridRenderer2.php +++ b/app/Renderers/DatagridRenderer2.php @@ -158,7 +158,7 @@ public function bulks(): array } continue; } - // More specific use cases? + // More specific use cases? } elseif ($bulk === Layout::ACTION_DELETE) { if (auth()->check() && auth()->user()->isAdmin()) { $this->bulks[] = $bulk; diff --git a/app/Services/Search/EntitySearchService.php b/app/Services/Search/EntitySearchService.php index 55aa3331e6..1534e43e51 100644 --- a/app/Services/Search/EntitySearchService.php +++ b/app/Services/Search/EntitySearchService.php @@ -33,17 +33,17 @@ public function search(string $term = null, string $term2 = null): array $results = $client->multiSearch([ (new SearchQuery()) - ->setIndexUid('entities') - ->setQuery($term) - ->setAttributesToRetrieve(['id', 'entity_id', 'type']) - ->setLimit(10), + ->setIndexUid('entities') + ->setQuery($term) + ->setAttributesToRetrieve(['id', 'entity_id', 'type']) + ->setLimit(10), (new SearchQuery()) ->setIndexUid('entities') ->setQuery($term2) ->setAttributesToRetrieve(['id', 'entity_id', 'type']) ->setLimit(10), ]); - + $results = array_merge($results['results'][0]['hits'], $results['results'][1]['hits']); return $this->process($results)->fetch(); @@ -59,19 +59,19 @@ protected function process(array $results = []): self if ($result['type'] == 'quest_element') { $id = Str::afterLast($result['id'], '_'); $this->questElementIds[$result['entity_id']] = $id; - //dd($result); + //dd($result); } elseif ($result['type'] == 'timeline_element') { $id = Str::afterLast($result['id'], '_'); $this->timelineElementIds[$result['entity_id']] = $id; - //dd($result); + //dd($result); } elseif ($result['type'] == 'post') { $id = Str::afterLast($result['id'], '_'); $this->postIds[$result['entity_id']] = $id; - //dd($result); + //dd($result); } elseif ($result['type'] == 'attribute') { $id = Str::afterLast($result['id'], '_'); $this->attributeIds[$result['entity_id']] = $id; - //dd($result); + //dd($result); } else { $this->ids[$result['entity_id']] = $result['entity_id']; } diff --git a/routes/api.v1.php b/routes/api.v1.php index e9b36fc505..3034908722 100644 --- a/routes/api.v1.php +++ b/routes/api.v1.php @@ -107,7 +107,7 @@ Route::post('campaigns/{campaign}/default-thumbnails', [App\Http\Controllers\Api\v1\DefaultThumbnailApiController::class, 'upload']); Route::delete('campaigns/{campaign}/default-thumbnails', [App\Http\Controllers\Api\v1\DefaultThumbnailApiController::class, 'delete']); -Route::get('campaigns/{campaign}/fulltext-search', [\App\Http\Controllers\Api\v1\FullTextSearchApiController::class, 'index']); +Route::get('campaigns/{campaign}/fulltext-search', [App\Http\Controllers\Api\v1\FullTextSearchApiController::class, 'index']); Route::get('campaigns/{campaign}/families/{family}/tree', [App\Http\Controllers\Api\v1\FamilyTreeApiController::class, 'show']); Route::post('campaigns/{campaign}/families/{family}/tree', [App\Http\Controllers\Api\v1\FamilyTreeApiController::class, 'store']);