Witajcie.
Mam zagwozdkę. Mam stronę wykorzystującą https://www.jstree.com oraz Laravel 7 z wykorzystaniem https://packagist.org/packages/kalnoy/nestedset
Mam tabelę z kategoriami (164574 rekordów) - która zajmuje około 22,3 MB (po zrzucie z phpmyadmin). Kategorie są praktycznie niezmienne.
Mój model i migracja wyglądają następująco:
class Category extends Model
{
use ScopeActiveTrait;
use NodeTrait;
use HasSlug;
/**
* Get the options for generating the slug.
*/
public function getSlugOptions() : SlugOptions
{
return SlugOptions::create()
->generateSlugsFrom('category_name')
->slugsShouldBeNoLongerThan(160)
->saveSlugsTo('slug');
}
protected $guarded = ['id'];
protected $fillable = ['category_name', 'description', 'keywords', 'content', 'enable', 'photo', 'order', 'slug', '_lft', '_rgt', 'parent_id'];
public $timestamps = false;
}
Schema::create('categories', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('category_name', 155);
$table->string('description', 155)->nullable();
$table->string('keywords', 155)->nullable();
$table->longText('content')->nullable();
$table->char('enable', 1)->default(0);
$table->string('photo', 155)->nullable();
$table->bigInteger('order')->default(0);
$table->string('slug', 160)->nullable();
NestedSet::columns($table);
$table->engine = "InnoDB";
$table->charset = 'utf8mb4';
$table->collation = 'utf8mb4_unicode_ci';
});
Założenie:
- wyświetlić drzewko kategorii
- zaznaczyć na drzewku wybrane kategorie
Do zapisu wybranych kategorii mam:
Schema::create('selected_product_categories', function (Blueprint $table) {
$table->id();
$table->bigInteger('product_id')->unsigned()->default(0);
$table->foreign('product_id')->references('id')->on('products')->onDelete('cascade');
$table->bigInteger('category_id')->unsigned()->default(0);
$table->foreign('category_id')->references('id')->on('categories')->onDelete('cascade');
$table->timestamps();
});
class SelectedProductCategory extends Model
{
protected $fillable = ['product_id', 'category_id'];
protected $guarded = ['id'];
}
Mój kod do wyświetlania wygląda następująco:
<div id="ajax" class="ajax"></div>
<script>
$(function () {
$('#ajax').jstree({
"checkbox": {
"keep_selected_style": false
},
"plugins": [
"checkbox",
],
'core': {
'data': {
"url": "domain.com/products/categoryTree",
"dataType": "json"
}
}
}).on('changed.jstree', function (e, data) {
var checked_ids = [];
var selectedNodes = $('#ajax').jstree("get_selected", true);
$.each(selectedNodes, function () {
checked_ids.push(this.id);
});
$('.categoryTree').val(checked_ids);
});
});
</script>
public function categoryTree(Category $category, SelectedProductCategory $selectedProductCategory, Request $request)
{
$tree = Cache::remember('categories', 31536000, function () use ($category) {
return $category->select(['id', 'category_name', 'parent_id', 'order', '_lft', '_rgt'])->active()->orderBy('order', 'ASC')->get();
});
$nodes = $this->generateJsTree($tree->toTree(), ($request->exists('id')) ? $selectedProductCategory->where('product_id', $request->input('id'))->orderBy('id', 'ASC')->get() : null);
return $nodes;
}
private function generateJsTree($nodes, $selectedCategories): array
{
$categoryArray = array();
$traverse = function ($categories, $prefix = '-') use (&$traverse, &$categoryArray, $selectedCategories) {
foreach ($categories as $category) {
$selected = false;
if (!is_null($selectedCategories)) {
$selected = $selectedCategories->contains('category_id', $category->id) ? true : false;
}
$categoryArray[] = ['id' => $category->id, 'text' => $category->category_name, 'parent' => $category->parent_id ?? '#', 'state' => ['opened' => false, 'selected' => $selected]];
$traverse($category->children, $prefix . '-');
}
};
$traverse($nodes);
return $categoryArray;
}
Skrypt generuje mi plik z cache (~250MB) na serwerze, jednak drzewko wyświetla się baaaardzo wolno (po 3-5min).
W momencie gdy wkleję link z html do przeglądarki: domain.com/products/categoryTree to wygenerowanie danych zajmuje mu parę minut.
Co może być przyczyną takiego długiego wczytywania?
Co można lepiej zoptymalizować? Bardzo proszę o pomoc :)