缺少 [Route: home.products] [URI: item/{id}/{slug}] 的必需参数。 (查看:/home/elawzsuf/website.com/resources/views/front/default/partials/top_menu.blade.php) (查看:/home/elawzsuf/website.com/resources/views/front/default/partials/top_menu.blade.php) (查看:/home/elawzsuf/website.com/resources/views/front/default/partials/top_menu.blade.php) {"userId":2,"exception":"[object] (ErrorException(code: 0):
<块引用>缺少 [Route: home.products] [URI: item/{id}/{slug}] 的必需参数。 (查看:/home/elawzsuf/website.com/resources/views/front/default/partials/top_menu.blade.php) (查看:/home/elawzsuf/website.com/resources/views/front/default/partials/top_menu.blade.php) (查看:/home/elawzsuf/website.com/resources/views/front/default/partials/top_menu.blade.php) 在/home/elawzsuf/website.com/vendor/laravel/framework/src/Illuminate/Routing/Exceptions/UrlGenerationException.php:17)
网络:
Route::get('item/{id}/{slug}', 'HomeController@product')
->name('home.product');
控制器:
public function product(Request $request)
{
$user_id = request()->user()->id ?? 'null';
$product = Product::by_id($request->id, $user_id);
$product->getAttributes() || abort(404);
if(mb_strtolower(urldecode($request->slug)) !== mb_strtolower(urldecode($product->slug)))
{
return redirect(item_url($product));
}
$product->remaining_downloads = null;
if($promotional_price_time = json_decode($product->promotional_price_time))
{
$promotional_price_time->from = format_date($promotional_price_time->from, 'Y-m-d');
$promotional_price_time->to = format_date($promotional_price_time->to, 'Y-m-d');
$product->promotional_price_time = json_encode($promotional_price_time);
}
$product_prices = Product_Price::selectRaw("product_price.*, licenses.name as license_name, licenses.regular,
products.promotional_price_time IS NOT NULL as has_promo_time,
IF(product_price.promo_price IS NOT NULL AND DATE_FORMAT(CURRENT_TIMESTAMP, '%Y-%m-%d') BETWEEN STR_TO_DATE(SUBSTR(products.promotional_price_time, 10, 10), '%Y-%m-%d') and STR_TO_DATE(SUBSTR(products.promotional_price_time, 28, 10), '%Y-%m-%d'), products.promotional_price_time, null) AS promotional_time")
->leftJoin('licenses', 'licenses.id', '=', 'product_price.license_id')
->join('products USE INDEX(primary)', 'products.id', '=', 'product_price.product_id')
->where('product_id', $product->id)
->get()->toArray();
$product_prices = array_combine(array_column($product_prices, 'license_id'), $product_prices);
if(exchange_rate_required())
{
foreach($product_prices as &$product_price)
{
$product_price['price'] = convert_amount($product_price['price']);
if($product_price['promo_price'])
{
$product_price['promo_price'] = convert_amount($product_price['promo_price']);
}
}
}
$valid_subscription = null;
if(Auth::check())
{
$subscription = User_Subscription::useIndex('user_id', 'subscription_id')
->selectRaw("
(user_subscription.ends_at IS NOT NULL AND CURRENT_TIMESTAMP > user_subscription.ends_at) OR
(subscriptions.limit_downloads > 0 AND user_subscription.downloads >= subscriptions.limit_downloads) OR
(subscriptions.limit_downloads_per_day > 0 AND user_subscription.daily_downloads >= subscriptions.limit_downloads_per_day AND user_subscription.daily_downloads_date = CURDATE())
AS expired, subscriptions.products, subscriptions.limit_downloads_same_item,
IF(subscriptions.limit_downloads_same_item > 0, subscriptions.limit_downloads_same_item - IFNULL(subscription_same_item_downloads.downloads, 0), null) as remaining_downloads,
(subscriptions.limit_downloads_same_item > 0 AND subscription_same_item_downloads.downloads >= subscriptions.limit_downloads_same_item) as same_items_downloads_reached")
->join('subscriptions', 'user_subscription.subscription_id', '=', 'subscriptions.id')
->join('products', function($join) use($product)
{
$join->where('products.id', '=', $product->id)
->where('products.for_subscriptions', 1);
})
->leftJoin('subscription_same_item_downloads USE INDEX(product_id, subscription_id)', function($join) use($product)
{
$join->on('subscription_same_item_downloads.subscription_id', '=', 'user_subscription.id')
->where('subscription_same_item_downloads.product_id', $product->id);
})
->join('transactions USE INDEX(primary)', 'user_subscription.transaction_id', '=', 'transactions.id')
->where(function($query)
{
$query->where('transactions.refunded', 0)
->orWhere('transactions.refunded', null);
})
->where('transactions.status', 'paid')
->where('user_subscription.user_id', Auth::id())
->whereRaw('CASE
WHEN subscriptions.products IS NOT NULL
THEN FIND_IN_SET(?, subscriptions.products)
ELSE
1=1
END
', [$product->id])
->first();
if($subscription)
{
$valid_subscription = !$subscription->expired && !$subscription->same_items_downloads_reached;
$product->remaining_downloads = $subscription->remaining_downloads;
}
}
$product->table_of_contents = json_decode($product->table_of_contents);
if(!$product->purchased && !$valid_subscription)
{
if($guest_token = $request->query('guest_token'))
{
$product->purchased = Transaction::useIndex('guest_token')
->where(['guest_token' => $guest_token, 'status' => 'paid', 'refunded' => 0, 'confirmed' => 1])
->where('transactions.products_ids', 'LIKE', "'%{$product->id}%'")
->first();
}
}
$meta_data = $this->meta_data;
if($request->isMethod('POST'))
{
$type = $request->input('type');
$redirect_url = url()->current().'#'.$request->input('type');
if($type === 'reviews')
{
if(! $product->purchased) abort(404);
$rating = $request->input('rating');
$review = $request->input('review');
$approved = auth_is_admin() ? 1 : (config('app.auto_approve.reviews') ? 1 : 0);
if(!ctype_digit($rating)) return redirect($redirect_url);
DB::insert("INSERT INTO reviews (product_id, user_id, rating, content, approved) VALUES (?, ?, ?, ?, ?)
ON DUPLICATE KEY UPDATE rating = ?, content = ?",
[$product->id, $user_id, $rating, $review, $approved, $rating, $review]);
if(!$approved)
$request->session()->put(['review_response' => 'Your review is waiting for approval. Thank you!']);
if(Auth::check() && !auth_is_admin() && config('app.admin_notifications.reviews'))
{
$mail_props = [
'data' => ['text' => __('A new review has been posted by :user for :item.', ['user' => $request->user()->name ?? null, 'item' => $product->name]),
'subject' => __('You have a new review.')],
'action' => 'send',
'view' => 'mail.message',
'to' => User::where('role', 'admin')->first()->email,
'subject' => __('You have a new review.')
];
NewMail::dispatch($mail_props, config('mail.mailers.smtp.use_queue'));
}
}
elseif($type === 'support')
{
if(! $comment = $request->input('comment'))
{
return redirect($redirect_url);
}
$approved = auth_is_admin() ? 1 : (config('app.auto_approve.support') ? 1 : 0);
$comment = strip_tags($comment);
if($request->comment_id) // parent
{
if($parent_comment = Comment::where('id', $request->comment_id)->where('parent', null)->where('product_id', $product->id)->first())
{
DB::insert("INSERT INTO comments (product_id, user_id, body, approved, parent) VALUES (?, ?, ?, ?, ?)",
[$product->id, $user_id, $comment, $approved, $parent_comment->id]);
}
}
else
{
DB::insert("INSERT INTO comments (product_id, user_id, body, approved) VALUES (?, ?, ?, ?)",
[$product->id, $user_id, $comment, $approved]);
}
if(!$approved)
$request->session()->put(['comment_response' => __('Your comment is waiting for approval. Thank you!')]);
if(Auth::check() && !auth_is_admin() && config('app.admin_notifications.comments'))
{
$mail_props = [
'data' => ['text' => __('A new comment has been posted by :user for :item.', ['user' => $request->user()->name ?? null, 'item' => $product->name]),
'subject' => __('You have a new comment.')],
'action' => 'send',
'view' => 'mail.message',
'to' => User::where('role', 'admin')->first()->email,
'subject' => __('You have a new comment.')
];
NewMail::dispatch($mail_props, config('mail.mailers.smtp.use_queue'));
}
}
return redirect($redirect_url);
}
Self::init_notifications();
DB::update('UPDATE products USE INDEX(primary) SET views = views+1 WHERE id = ?', [$product->id]);
$reviews = Review::useIndex('product_id', 'approved')
->selectRaw("reviews.*, users.name, SUBSTR(users.email, 1, LOCATE('@', users.email)-1) as alias_name, CONCAT(users.firstname, ' ', users.lastname) AS fullname, IFNULL(users.avatar, 'default.jpg') AS avatar")
->leftJoin('users', 'users.id', '=', 'reviews.user_id')
->where(['reviews.product_id' => $product->id, 'reviews.approved' => 1])
->orderBy('created_at', 'DESC')->get();
$comments = Comment::useIndex('product_id', 'approved')
->selectRaw("comments.*, users.name, SUBSTR(users.email, 1, LOCATE('@', users.email)-1) as alias_name, CONCAT(users.firstname, ' ', users.lastname) AS fullname, IFNULL(users.avatar, 'default.jpg') AS avatar, IF(users.role = 'admin', 1, 0) as is_admin,
IF((SELECT COUNT(transactions.id) FROM transactions WHERE transactions.user_id = comments.user_id AND transactions.status = 'paid' AND transactions.refunded = 0 AND transactions.confirmed = 1 AND transactions.products_ids REGEXP CONCAT('\'', comments.product_id, '\'')) > 0, 1, 0) as item_purchased")
->leftJoin('users', 'users.id', '=', 'comments.user_id')
->where(['comments.product_id' => $product->id, 'comments.approved' => 1])
->orderBy('id', 'ASC')->get();
$similar_products = Product::useIndex('primary', 'category', 'active')
->selectRaw(implode(',', Self::$product_columns).', categories.name as category_name, categories.slug as category_slug')
->leftJoin('categories', 'categories.id', '=', 'products.category')
->leftJoin('categories as subcategories', 'products.subcategories', 'REGEXP', DB::raw('CONCAT("\'", subcategories.id, "\'")'))
->leftJoin('transactions', 'products_ids', 'REGEXP', DB::raw('concat("\'", products.id, "\'")'))
->leftJoin('licenses', function($join)
{
$join->on('licenses.item_type', '=', 'products.type')
->where('licenses.regular', 1);
})
->leftJoin('product_price', function($join)
{
$join->on('product_price.license_id', '=', 'licenses.id')
->on('product_price.product_id', '=', 'products.id');
})
->where(['products.category' => $product->category_id,
'products.active' => 1,
'products.for_subscriptions' => 0,
'products.is_dir' => (isFolderProcess() ? 1 : 0)])
->where('products.id', '!=', $product->id)
->groupBy('products.id', 'products.name', 'products.views', 'products.preview', 'products.preview_type',
'products.slug', 'products.updated_at', 'products.hidden_content', 'products.active', 'products.stock', 'products.bpm', 'products.label', 'products.pages',
'products.authors', 'products.language', 'products.words', 'products.formats',
'products.cover', 'product_price.price', 'products.last_update',
'category_name', 'category_slug', 'categories.id', 'promotional_price_time', 'products.tags', 'products.short_description', 'product_price.promo_price', 'products.free', 'products.trending', 'products.is_dir', 'products.for_subscriptions', 'products.type', 'licenses.id', 'licenses.name', 'products.country_city')
->orderByRaw('rand()')
->limit(5)->get();
if($parents = $comments->where('parent', null)->sortByDesc('id')) // parents comments only
{
$children = $comments->where('parent', '!=', null); // children comments only
// Append children comments to their parents
$parents->map(function (&$item, $key) use ($children, $request, $product)
{
$request->merge(['item_type' => 'comment', 'item_id' => $item->id, 'product_id' => $product->id]);
$item->reactions = $this->get_reactions($request);
$item->children = $children->where('parent', $item->id)->sortBy('created_at');
foreach($item->children as $children)
{
$request->merge(['item_type' => 'comment', 'item_id' => $children->id, 'product_id' => $product->id]);
$children->reactions = $this->get_reactions($request);
}
});
}
if($product->country_city)
{
$country_city = json_decode($product->country_city);
$product->country = $country_city->country ?? null;
$product->city = $country_city->city ?? null;
}
if($product->screenshots)
{
$product->screenshots = array_reduce(explode(',', $product->screenshots), function($ac, $img)
{
$ac[] = asset_("storage/screenshots/{$img}");
return $ac;
}, []);
}
$product->tags = array_filter(explode(',', $product->tags));
$product->additional_fields = json_decode($product->additional_fields);
$product->faq = json_decode($product->faq, true) ?? [];
if(count(array_column($product->faq, 'Q')))
{
$faqs = [];
foreach($product->faq as $faq)
{
$faqs[] = [
'question' => $faq['Q'] ?? '',
'answer' => $faq['A'] ?? ''
];
}
$product->faq = $faqs;
}
$product->faq = arr2obj($product->faq);
$meta_data->title = $product->name;
$meta_data->description = $product->short_description;
$meta_data->image = asset("storage/covers/{$product->cover}");
return view_('product', [
'title' => mb_ucfirst($product->name),
'product' => $product,
'reviews' => $reviews,
'comments' => $parents, // Parents comments with their children in
'similar_products' => $similar_products,
'meta_data' => $meta_data,
'valid_subscription' => $valid_subscription,
'product_prices' => $product_prices
]);
}
top_menu.blade.php
<div class="menu">
<div>
<div class="ui unstackable items">
@if(config('notifications'))
@foreach(config('notifications') as $notif)
<a class="item mx-0"
data-id="{{ $notif->id }}"
data-href="{{ route('home.product', ['id' => $notif->product_id, 'slug' => $notif->slug . ($notif->for == 1 ? '#support' : ($notif->for == 2 ? '#reviews' : ''))]) }}">
<div class="ui image">
@if($notif->for == 0)
<img src="{{ asset_("storage/thumbnails/{$notif->image}") }}">
@else
<img src="{{ asset_("storage/avatars/{$notif->image}") }}">
@endif
</div>
<div class="content pl-1">
<p>{!! __($notif->text, ['product_name' => "<strong>{$notif->name}</strong>"]) !!}</p>
<time>{{ \Carbon\Carbon::parse($notif->updated_at)->diffForHumans() }}</time>
</div>
</a>
@endforeach
@else
<div class="item mx-0">
<div class="ui w-100 small message p-1 circular-corner bold">
{{ __('You have 0 new notifications') }}
</div>
</div>
@endif
@auth
<a href="{{ route('home.notifications') }}" class="item mx-0 all">{{ __('View all') }}</a>
@endauth
</div>
</div>
</div>
</div>
@endauth