Skip to content

Commit

Permalink
fix(world): implement eager loading, refactor queries (#1180)
Browse files Browse the repository at this point in the history
- only load extra item info (artists, shops) if extra fields are enabled
- add "with" property to relevant models
  • Loading branch information
itinerare authored Jan 6, 2025
1 parent 17a26b9 commit b1a146b
Show file tree
Hide file tree
Showing 8 changed files with 79 additions and 49 deletions.
36 changes: 26 additions & 10 deletions app/Http/Controllers/WorldController.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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.'%');
Expand All @@ -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()),
]);
}

Expand Down Expand Up @@ -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']);
}
Expand Down Expand Up @@ -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);
Expand All @@ -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')
Expand All @@ -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')
Expand Down Expand Up @@ -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);
Expand All @@ -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) {
Expand Down Expand Up @@ -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);
Expand All @@ -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(),
]);
}

Expand All @@ -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.'%');
Expand Down
35 changes: 29 additions & 6 deletions app/Models/Item/Item.php
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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.
*
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
}

/**
Expand All @@ -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;
}
}

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

/**
* Validation rules for creation.
*
Expand Down
26 changes: 13 additions & 13 deletions config/lorekeeper/extensions.php
Original file line number Diff line number Diff line change
Expand Up @@ -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' => [
Expand All @@ -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.
Expand Down
8 changes: 4 additions & 4 deletions resources/views/world/_item_entry.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand All @@ -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)
Expand All @@ -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 }}
Expand Down
2 changes: 1 addition & 1 deletion resources/views/world/_species_entry.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down
8 changes: 4 additions & 4 deletions resources/views/world/item_page.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -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'])
Expand All @@ -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 }}
Expand Down
12 changes: 1 addition & 11 deletions resources/views/world/items.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit b1a146b

Please sign in to comment.