Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(world): implement eager loading, refactor queries #1180

Merged
merged 1 commit into from
Jan 6, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 26 additions & 10 deletions app/Http/Controllers/WorldController.php
Original file line number Diff line number Diff line change
@@ -10,7 +10,6 @@
use App\Models\Item\ItemCategory;
use App\Models\Rarity;
use App\Models\Shop\Shop;
use App\Models\Shop\ShopStock;
use App\Models\Species\Species;
use App\Models\Species\Subtype;
use App\Models\User\User;
@@ -78,6 +77,11 @@ public function getRarities(Request $request) {
*/
public function getSpecieses(Request $request) {
$query = Species::query();

if (config('lorekeeper.extensions.species_trait_index.enable')) {
$query->withCount('features');
}

$name = $request->get('name');
if ($name) {
$query->where('name', 'LIKE', '%'.$name.'%');
@@ -96,14 +100,14 @@ public function getSpecieses(Request $request) {
* @return \Illuminate\Contracts\Support\Renderable
*/
public function getSubtypes(Request $request) {
$query = Subtype::query();
$query = Subtype::query()->with('species');
$name = $request->get('name');
if ($name) {
$query->where('name', 'LIKE', '%'.$name.'%');
}

return view('world.subtypes', [
'subtypes' => $query->with('species')->visible(Auth::check() ? Auth::user() : null)->orderBy('sort', 'DESC')->orderBy('id')->paginate(20)->appends($request->query()),
'subtypes' => $query->visible(Auth::check() ? Auth::user() : null)->orderBy('sort', 'DESC')->orderBy('id')->paginate(20)->appends($request->query()),
]);
}

@@ -147,8 +151,10 @@ public function getFeatureCategories(Request $request) {
* @return \Illuminate\Contracts\Support\Renderable
*/
public function getFeatures(Request $request) {
$query = Feature::visible(Auth::check() ? Auth::user() : null)->with('category')->with('rarity')->with('species');
$query = Feature::visible(Auth::check() ? Auth::user() : null)->with('category', 'rarity', 'species', 'subtype');

$data = $request->only(['rarity_id', 'feature_category_id', 'species_id', 'subtype_id', 'name', 'sort']);

if (isset($data['rarity_id']) && $data['rarity_id'] != 'none') {
$query->where('rarity_id', $data['rarity_id']);
}
@@ -230,6 +236,7 @@ public function getFeatures(Request $request) {
public function getSpeciesFeatures($id) {
$categories = FeatureCategory::orderBy('sort', 'DESC')->get();
$rarities = Rarity::orderBy('sort', 'ASC')->get();

$species = Species::visible(Auth::check() ? Auth::user() : null)->where('id', $id)->first();
if (!$species) {
abort(404);
@@ -241,6 +248,7 @@ public function getSpeciesFeatures($id) {
$features = count($categories) ?
$species->features()
->visible(Auth::check() ? Auth::user() : null)
->with('rarity', 'subtype')
->orderByRaw('FIELD(feature_category_id,'.implode(',', $categories->pluck('id')->toArray()).')')
->orderByRaw('FIELD(rarity_id,'.implode(',', $rarities->pluck('id')->toArray()).')')
->orderBy('has_image', 'DESC')
@@ -256,6 +264,7 @@ public function getSpeciesFeatures($id) {
->groupBy(['feature_category_id', 'id']) :
$species->features()
->visible(Auth::check() ? Auth::user() : null)
->with('rarity', 'subtype')
->orderByRaw('FIELD(rarity_id,'.implode(',', $rarities->pluck('id')->toArray()).')')
->orderBy('has_image', 'DESC')
->orderBy('name')
@@ -286,7 +295,7 @@ public function getSpeciesFeatures($id) {
* @return \Illuminate\Contracts\Support\Renderable
*/
public function getSpeciesFeatureDetail($speciesId, $id) {
$feature = Feature::where('id', $id)->first();
$feature = Feature::where('id', $id)->with('species', 'subtype', 'rarity')->first();

if (!$feature) {
abort(404);
@@ -308,6 +317,10 @@ public function getSpeciesFeatureDetail($speciesId, $id) {
public function getItems(Request $request) {
$query = Item::with('category')->released(Auth::user() ?? null);

if (config('lorekeeper.extensions.item_entry_expansion.extra_fields')) {
$query->with('artist', 'shopStock')->withCount('shopStock');
}

$categoryVisibleCheck = ItemCategory::visible(Auth::check() ? Auth::user() : null)->pluck('id', 'name')->toArray();
// query where category is visible, or, no category and released
$query->where(function ($query) use ($categoryVisibleCheck) {
@@ -366,9 +379,13 @@ public function getItems(Request $request) {
* @return \Illuminate\Contracts\Support\Renderable
*/
public function getItem($id) {
$categories = ItemCategory::orderBy('sort', 'DESC')->get();
$item = Item::where('id', $id)->released(Auth::user() ?? null)->with('category');

$item = Item::where('id', $id)->released(Auth::user() ?? null)->first();
if (config('lorekeeper.extensions.item_entry_expansion.extra_fields')) {
$item->with('artist', 'shopStock')->withCount('shopStock');
}

$item = $item->first();

if (!$item) {
abort(404);
@@ -384,8 +401,6 @@ public function getItem($id) {
'imageUrl' => $item->imageUrl,
'name' => $item->displayName,
'description' => $item->parsed_description,
'categories' => $categories->keyBy('id'),
'shops' => Shop::whereIn('id', ShopStock::where('item_id', $item->id)->pluck('shop_id')->unique()->toArray())->orderBy('sort', 'DESC')->get(),
]);
}

@@ -395,7 +410,8 @@ public function getItem($id) {
* @return \Illuminate\Contracts\Support\Renderable
*/
public function getCharacterCategories(Request $request) {
$query = CharacterCategory::query();
$query = CharacterCategory::query()->with('sublist');

$name = $request->get('name');
if ($name) {
$query->where('name', 'LIKE', '%'.$name.'%')->orWhere('code', 'LIKE', '%'.$name.'%');
35 changes: 29 additions & 6 deletions app/Models/Item/Item.php
Original file line number Diff line number Diff line change
@@ -5,6 +5,7 @@
use App\Models\Model;
use App\Models\Prompt\Prompt;
use App\Models\Shop\Shop;
use App\Models\Shop\ShopStock;
use App\Models\User\User;

class Item extends Model {
@@ -26,6 +27,16 @@ class Item extends Model {
* @var string
*/
protected $table = 'items';

/**
* The relationships that should always be loaded.
*
* @var array
*/
protected $with = [
'tags',
];

/**
* Validation rules for creation.
*
@@ -86,6 +97,13 @@ public function artist() {
return $this->belongsTo(User::class, 'artist_id');
}

/**
* Get shop stock for this item.
*/
public function shopStock() {
return $this->hasMany(ShopStock::class, 'item_id');
}

/**********************************************************************************************

SCOPES
@@ -343,17 +361,18 @@ public function getResellAttribute() {
}

/**
* Get the shops attribute as an associative array.
* Get the shops that stock this item.
*
* @return array
* @return \Illuminate\Database\Eloquent\Collection
*/
public function getShopsAttribute() {
if (!$this->data) {
if (!config('lorekeeper.extensions.item_entry_expansion.extra_fields') || !$this->shop_stock_count) {
return null;
}
$itemShops = $this->data['shops'];

return Shop::whereIn('id', $itemShops)->get();
$shops = Shop::whereIn('id', $this->shopStock->pluck('shop_id')->toArray())->orderBy('sort', 'DESC')->get();

return $shops;
}

/**
@@ -367,7 +386,11 @@ public function getPromptsAttribute() {
}
$itemPrompts = $this->data['prompts'];

return Prompt::whereIn('id', $itemPrompts)->get();
if (count($itemPrompts)) {
return Prompt::whereIn('id', $itemPrompts)->get();
} else {
return null;
}
}

/**
1 change: 1 addition & 0 deletions app/Models/Species/Subtype.php
Original file line number Diff line number Diff line change
@@ -29,6 +29,7 @@ class Subtype extends Model {
protected $appends = [
'name_with_species',
];

/**
* Validation rules for creation.
*
26 changes: 13 additions & 13 deletions config/lorekeeper/extensions.php
Original file line number Diff line number Diff line change
@@ -20,25 +20,25 @@
*/

// Navbar News Notif - Juni
'navbar_news_notif' => 0,
'navbar_news_notif' => 0,

// Species Trait Index - Mercury
'species_trait_index' => [
'species_trait_index' => [
'enable' => 0,
'trait_modals' => 0, // Enables modals when you click on a trait for more info instead of linking to the traits page - Moif
],

// Character Status Badges - Juni
'character_status_badges' => 0,
'character_status_badges' => 0,

// Character TH Profile Link - Juni
'character_TH_profile_link' => 0,
'character_TH_profile_link' => 0,

// Design Update Voting - Mercury
'design_update_voting' => 0,
'design_update_voting' => 0,

// Item Entry Expansion - Mercury
'item_entry_expansion' => [
'item_entry_expansion' => [
'extra_fields' => 0,
'resale_function' => 0,
'loot_tables' => [
@@ -49,33 +49,33 @@
],

// Group Traits By Category - Uri
'traits_by_category' => 0,
'traits_by_category' => 0,

// Scroll To Top - Uri
'scroll_to_top' => 0, // 1 - On, 0 - off
'scroll_to_top' => 0, // 1 - On, 0 - off

// Character Reward Expansion - Uri
'character_reward_expansion' => [
'character_reward_expansion' => [
'expanded' => 1,
'default_recipient' => 0, // 0 to default to the character's owner (if a user), 1 to default to the submission user.
],

// MYO Image Hide/Remove - Mercury
// Adds an option when approving MYO submissions to hide or delete the MYO placeholder image
'remove_myo_image' => 0,
'remove_myo_image' => 0,

// Auto-populate New Image Traits - Mercury
// Automatically adds the traits present on a character's active image to the list when uploading a new image for an extant character.
'autopopulate_image_features' => 0,
'autopopulate_image_features' => 0,

// Staff Rewards - Mercury
'staff_rewards' => [
'staff_rewards' => [
'enabled' => 0,
'currency_id' => 1,
],

// Organised Traits Dropdown - Draginraptor
'organised_traits_dropdown' => 0,
'organised_traits_dropdown' => 0,

// Previous & Next buttons on Character pages - Speedy
// Adds buttons linking to the previous character as well as the next character on all character pages.
8 changes: 4 additions & 4 deletions resources/views/world/_item_entry.blade.php
Original file line number Diff line number Diff line change
@@ -68,7 +68,7 @@
</p>
@endif
{!! $description !!}
@if (((isset($item->uses) && $item->uses) || (isset($item->source) && $item->source) || $shops->count() || (isset($item->data['prompts']) && $item->data['prompts'])) && config('lorekeeper.extensions.item_entry_expansion.extra_fields'))
@if (((isset($item->uses) && $item->uses) || (isset($item->source) && $item->source) || $item->shop_stock_count || (isset($item->data['prompts']) && $item->data['prompts'])) && config('lorekeeper.extensions.item_entry_expansion.extra_fields'))
<div class="text-right">
<a data-toggle="collapse" href="#item-{{ $item->id }}" class="text-primary">
<strong>Show details...</strong>
@@ -80,7 +80,7 @@
<strong>Uses:</strong> {{ $item->uses }}
</p>
@endif
@if ((isset($item->source) && $item->source) || $shops->count() || (isset($item->data['prompts']) && $item->data['prompts']))
@if ((isset($item->source) && $item->source) || $item->shop_stock_count || (isset($item->data['prompts']) && $item->data['prompts']))
<h5>Availability</h5>
<div class="row">
@if (isset($item->source) && $item->source)
@@ -93,13 +93,13 @@
</p>
</div>
@endif
@if ($shops->count())
@if ($item->shop_stock_count)
<div class="col">
<p>
<strong>Purchaseable At:</strong>
</p>
<div class="row">
@foreach ($shops as $shop)
@foreach ($item->shops as $shop)
<div class="col">
<a href="{{ $shop->url }}">
{{ $shop->name }}
2 changes: 1 addition & 1 deletion resources/views/world/_species_entry.blade.php
Original file line number Diff line number Diff line change
@@ -17,7 +17,7 @@
<i class="fas fa-search"></i>
</a>
</h3>
@if (count($species->features) && config('lorekeeper.extensions.species_trait_index.enable'))
@if (config('lorekeeper.extensions.species_trait_index.enable') && $species->features_count)
<a href="{{ $species->visualTraitsUrl }}">
<strong>Visual Trait Index</strong>
</a>
8 changes: 4 additions & 4 deletions resources/views/world/item_page.blade.php
Original file line number Diff line number Diff line change
@@ -95,14 +95,14 @@
</p>
@endif
{!! $description !!}
@if (((isset($item->uses) && $item->uses) || (isset($item->source) && $item->source) || $shops->count() || (isset($item->data['prompts']) && $item->data['prompts'])) && config('lorekeeper.extensions.item_entry_expansion.extra_fields'))
@if (((isset($item->uses) && $item->uses) || (isset($item->source) && $item->source) || $item->shop_stock_count || (isset($item->data['prompts']) && $item->data['prompts'])) && config('lorekeeper.extensions.item_entry_expansion.extra_fields'))

@if (isset($item->uses) && $item->uses)
<p>
<strong>Uses:</strong> {!! $item->uses !!}
</p>
@endif
@if ((isset($item->source) && $item->source) || $shops->count() || (isset($item->data['prompts']) && $item->data['prompts']))
@if ((isset($item->source) && $item->source) || $item->shop_stock_count || (isset($item->data['prompts']) && $item->data['prompts']))
<h5>Availability</h5>
<div class="row">
@if (isset($item->data['release']) && $item->data['release'])
@@ -111,13 +111,13 @@
<p>{!! $item->data['release'] !!}</p>
</div>
@endif
@if ($shops->count())
@if ($item->shop_stock_count)
<div class="col">
<p>
<strong>Purchaseable At:</strong>
</p>
<div class="row">
@foreach ($shops as $shop)
@foreach ($item->shops as $shop)
<span class="badge" style="font-size:95%; margin:5px;">
<a href="{{ $shop->url }}">
{{ $shop->name }}
12 changes: 1 addition & 11 deletions resources/views/world/items.blade.php
Original file line number Diff line number Diff line change
@@ -49,17 +49,7 @@
@foreach ($items as $item)
<div class="card mb-3">
<div class="card-body">
<?php
$shops = App\Models\Shop\Shop::whereIn(
'id',
App\Models\Shop\ShopStock::where('item_id', $item->id)
->pluck('shop_id')
->toArray(),
)
->orderBy('sort', 'DESC')
->get();
?>
@include('world._item_entry', ['imageUrl' => $item->imageUrl, 'name' => $item->displayName, 'description' => $item->parsed_description, 'idUrl' => $item->idUrl, 'shops' => $shops])
@include('world._item_entry', ['imageUrl' => $item->imageUrl, 'name' => $item->displayName, 'description' => $item->parsed_description, 'idUrl' => $item->idUrl])
</div>
</div>
@endforeach