https://t.me/RX1948
Server : Apache/2.4.18 (Ubuntu)
System : Linux canvaswebdesign 3.13.0-71-generic #114-Ubuntu SMP Tue Dec 1 02:34:22 UTC 2015 x86_64
User : oppastar ( 1041)
PHP Version : 7.0.33-0ubuntu0.16.04.15
Disable Function : pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,
Directory :  /var/www/laciasmara.com/public_html/shop/application/controllers/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Current File : //var/www/laciasmara.com/public_html/shop/application/controllers/Search.php
<?php defined('BASEPATH') or exit('No direct script access allowed');

class Search extends Public_Controller
{

	public function __construct()
	{
		parent::__construct();
		$this->load->model('Top_banner_m');
		$this->load->model('Review_m');
		$this->load->model('Footer_m');
		$this->load->model('Statistic_m');
		$this->load->model('Category_m');

		$this->load->library('GoogleClient');
		$this->load->library('VisitorTracking');
		$loginUrl = $this->googleclient->getLoginUrl();
		$this->data_footer['googleUrl'] = $loginUrl;
	}

	public function index()
	{
		redirect(base_url());
	}

	public function product()
	{
		// Ambil query dari URL
		$query = $this->input->get('q', TRUE); // 'TRUE' untuk XSS filtering
		$source = $this->input->get('utm_source', TRUE);
		$this->visitortracking->trackVisitor();

		// Ambil data konfigurasi website
		$website_data = $this->db->select('website_icon, browser_title, meta_description')
			->from('configuration')
			->where('id_configuration', 1)
			->get()
			->row();

		$banners = $this->Top_banner_m->get_active_banners();

		// Gunakan optimized query untuk pencarian produk
		$optimized_query = $this->get_optimized_product_query();

		// Tambahkan filter pencarian ke query
		$search_query = "
			SELECT * FROM (
				$optimized_query
			) AS product_results
			WHERE (
				product_results.title LIKE ?
				OR product_results.alias LIKE ?
				OR EXISTS (
					SELECT 1 FROM products p2 
					WHERE p2.id_products = product_results.id_products 
					AND (
						p2.description LIKE ?
						OR p2.meta_description LIKE ?
					)
				)
				OR EXISTS (
					SELECT 1 FROM brands b2 
					WHERE b2.id_brands = product_results.brand_id 
					AND (
						b2.brand LIKE ?
						OR b2.alias LIKE ?
					)
				)
			)
			ORDER BY 
				product_results.sort_order ASC,
				product_results.best_seller DESC,
				product_results.new_arrival DESC,
				product_results.popular_product DESC,
				product_results.priority DESC,
				product_results.brand_priority DESC,
				product_results.created_at DESC
		";

		// Prepare search parameters
		$search_term = "%{$query}%";
		$search_params = [
			$search_term, // title
			$search_term, // alias
			$search_term, // description
			$search_term, // meta_description
			$search_term, // brand
			$search_term  // brand alias
		];

		// Execute query
		$products = $this->db->query($search_query, $search_params)->result_array();

		$campaign = $this->campaignmanager->get_campaign_from_session();
		if ($campaign) {
			$this->load->model('Promotional_campaign_m');

			// Filter hanya produk yang eligible
			foreach ($products as $key => &$product) {
				$product_category = $this->db->select('id_category')
					->from('category_product')
					->where('id_product', $product['id_products'])
					->get()
					->row();

				if ($product_category) {
					$is_eligible = $this->Promotional_campaign_m->is_product_eligible(
						$campaign->id,
						$product['id_products'],
						$product_category->id_category
					);

					if ($is_eligible) {
						$product['is_campaign_eligible'] = true;
					}
				}
			}

			// Apply discount ke semua yang eligible sekaligus
			$products = $this->campaignmanager->apply_discount_to_products_array(
				$products,
				$campaign
			);
		}

		// Format data produk
		$formatted_products = $this->prepare_search_products($products);

		$meta_description = ($this->session->userdata('site_lang') == 'english')
			? "Can't decide? Just type and find the perfect pleasure to level up your intimate experience!"
			: "Jangan bingung pilih yang mana! Cukup ketik dan temukan piranti asmara yang cocok untuk nemenin pengalaman intim kamu.";

		$this->data_header['browser_title'] .= ' - Search Results for "' . htmlspecialchars($query, ENT_QUOTES, 'UTF-8') . '"';
		$this->data_header['meta_description'] = $meta_description;
		$this->data_header['products'] = $formatted_products;
		$this->data_header['query'] = $query;
		$this->data_header['total_products'] = count($formatted_products);


		if ($this->session->userdata('site_lang') == 'english') {
			$this->lang->load('mainpage', 'english');
		} else {
			$this->lang->load('mainpage', 'indonesian');
		}


		// Load view
		$this->load->view("themes/$this->theme_no/header_new", $this->data_header);
		$this->load->view("themes/$this->theme_no/search_result", $this->data);
		$this->load->view("themes/$this->theme_no/footer_new", $this->data_footer);
	}

	private function get_optimized_product_query()
	{
		return "
			SELECT 
				p.id_products,
				p.title,
				p.alias,
				p.brand_id,
				p.created_at,
				p.best_seller,
				p.new_arrival,
				p.popular_product,
				p.priority,
				
				-- Product Details
				COALESCE(primary_variant.id, first_variant.id) AS id_detail,
				COALESCE(primary_variant.price, first_variant.price) AS price,
				COALESCE(primary_variant.discounted_price, first_variant.discounted_price) AS discounted_price,
				COALESCE(primary_variant.sku, first_variant.sku) AS sku,
				
				-- Product Images
				COALESCE(
					main_image.image,
					COALESCE(primary_variant_image.image, first_variant_image.image),
					p.image
				) AS image,
				COALESCE(
					main_image_secondary.image,
					COALESCE(primary_variant_image_secondary.image, first_variant_image_secondary.image),
					p.image1
				) AS image_secondary,
				
				-- Stock Information
				stock_summary.total_stock,
				stock_summary.total_stock_keep,
				stock_summary.total_stock_sell,
				stock_summary.available_variants,
				stock_summary.total_variants,
				
				-- Current variant stock
				COALESCE(
					GREATEST(0, COALESCE(primary_variant_stock.stock, 0) - COALESCE(primary_variant_stock.stock_keep, 0)),
					GREATEST(0, COALESCE(first_variant_stock.stock, 0) - COALESCE(first_variant_stock.stock_keep, 0)),
					0
				) AS current_variant_stock_sell,
				
				-- Availability Flags
				CASE 
					WHEN stock_summary.total_stock_sell <= 0 THEN 1 
					ELSE 0 
				END AS is_completely_sold_out,
				
				CASE 
					WHEN COALESCE(
						GREATEST(0, COALESCE(primary_variant_stock.stock, 0) - COALESCE(primary_variant_stock.stock_keep, 0)),
						GREATEST(0, COALESCE(first_variant_stock.stock, 0) - COALESCE(first_variant_stock.stock_keep, 0)),
						0
					) <= 0 THEN 1 
					ELSE 0 
				END AS current_variant_out_of_stock,
				
				CASE 
					WHEN stock_summary.available_variants > 1 THEN 1 
					ELSE 0 
				END AS has_other_variants_available,
				
				-- Variants
				COALESCE(
					primary_variant_attrs.variants,
					first_variant_attrs.variants,
					'No variants available'
				) AS variants,
				
				-- Badges Information
				COALESCE(product_badges_data.badges_names, '') AS badges_names,
				COALESCE(product_badges_data.badges_data, '') AS badges_data,
				COALESCE(product_badges_data.badges_count, 0) AS badges_count,
				
				-- Additional data
				COALESCE(total_sales.total_sales, 0) AS total_sales,
				COALESCE(total_reviews.total_reviews, 0) AS total_reviews,
				COALESCE(reseller_price.price, 0) AS reseller_price,
				COALESCE(reseller_price.min_quantity, 0) AS reseller_min_quantity,
				COALESCE(b.priority, 0) AS brand_priority,
				
				-- Discount calculations
				CASE
					WHEN COALESCE(primary_variant.discounted_price, first_variant.discounted_price) > 0 
						AND COALESCE(primary_variant.discounted_price, first_variant.discounted_price) < COALESCE(primary_variant.price, first_variant.price)
					THEN (COALESCE(primary_variant.price, first_variant.price) - COALESCE(primary_variant.discounted_price, first_variant.discounted_price))
					ELSE 0
				END AS savings_amount,
				
				CASE
					WHEN COALESCE(primary_variant.discounted_price, first_variant.discounted_price) > 0 
						AND COALESCE(primary_variant.discounted_price, first_variant.discounted_price) < COALESCE(primary_variant.price, first_variant.price)
					THEN ROUND(((COALESCE(primary_variant.price, first_variant.price) - COALESCE(primary_variant.discounted_price, first_variant.discounted_price)) / COALESCE(primary_variant.price, first_variant.price)) * 100, 0)
					ELSE 0
				END AS discount_percentage,
				
				-- Sort order
				CASE 
					WHEN stock_summary.total_stock_sell <= 0 THEN 1 
					ELSE 0 
				END AS sort_order

			FROM products p

			-- Stock Summary
			LEFT JOIN (
				SELECT 
					pd.product_id,
					COUNT(DISTINCT pd.id) AS total_variants,
					SUM(COALESCE(s.stock, 0)) AS total_stock,
					SUM(COALESCE(s.stock_keep, 0)) AS total_stock_keep,
					SUM(GREATEST(0, COALESCE(s.stock, 0) - COALESCE(s.stock_keep, 0))) AS total_stock_sell,
					SUM(CASE WHEN GREATEST(0, COALESCE(s.stock, 0) - COALESCE(s.stock_keep, 0)) > 0 THEN 1 ELSE 0 END) AS available_variants
				FROM product_details pd
				LEFT JOIN stock s ON pd.id = s.id_product_detail
				GROUP BY pd.product_id
			) stock_summary ON p.id_products = stock_summary.product_id

			-- Primary Variant
			LEFT JOIN (
				SELECT pd.*
				FROM product_details pd
				INNER JOIN (
					SELECT product_id, MIN(id) as min_id
					FROM product_details
					GROUP BY product_id
				) min_pd ON pd.product_id = min_pd.product_id AND pd.id = min_pd.min_id
			) primary_variant ON p.id_products = primary_variant.product_id

			LEFT JOIN (
				SELECT pd.*
				FROM product_details pd
				LEFT JOIN stock s ON pd.id = s.id_product_detail
				INNER JOIN (
					SELECT pd.product_id, MAX(GREATEST(0, COALESCE(s.stock, 0) - COALESCE(s.stock_keep, 0))) AS max_stock
					FROM product_details pd
					LEFT JOIN stock s ON pd.id = s.id_product_detail
					GROUP BY pd.product_id
				) max_stock_pd ON pd.product_id = max_stock_pd.product_id
				LEFT JOIN stock s2 ON pd.id = s2.id_product_detail
				WHERE GREATEST(0, COALESCE(s2.stock, 0) - COALESCE(s2.stock_keep, 0)) = max_stock_pd.max_stock
			) first_variant ON p.id_products = first_variant.product_id

			-- Stock for displayed variants
			LEFT JOIN stock primary_variant_stock ON primary_variant.id = primary_variant_stock.id_product_detail
			LEFT JOIN stock first_variant_stock ON first_variant.id = first_variant_stock.id_product_detail

			-- Product Images
			LEFT JOIN product_images main_image ON p.id_products = main_image.product_id 
				AND main_image.product_details_id = 0 
				AND main_image.priority = 1 
				AND main_image.status = '1'

			LEFT JOIN product_images main_image_secondary ON p.id_products = main_image_secondary.product_id 
				AND main_image_secondary.product_details_id = 0 
				AND main_image_secondary.priority = 2 
				AND main_image_secondary.status = '1'

			LEFT JOIN product_images primary_variant_image ON primary_variant.id = primary_variant_image.product_details_id 
				AND primary_variant_image.priority = 1 
				AND primary_variant_image.status = '1'

			LEFT JOIN product_images primary_variant_image_secondary ON primary_variant.id = primary_variant_image_secondary.product_details_id 
				AND primary_variant_image_secondary.priority = 2 
				AND primary_variant_image_secondary.status = '1'

			LEFT JOIN product_images first_variant_image ON first_variant.id = first_variant_image.product_details_id 
				AND first_variant_image.priority = 1 
				AND first_variant_image.status = '1'

			LEFT JOIN product_images first_variant_image_secondary ON first_variant.id = first_variant_image_secondary.product_details_id 
				AND first_variant_image_secondary.priority = 2 
				AND first_variant_image_secondary.status = '1'

			-- Variant Attributes
			LEFT JOIN (
				SELECT 
					pc.product_details_id,
					GROUP_CONCAT(DISTINCT CONCAT_WS(': ', pa.product_attribute, pad.attribute_detail) SEPARATOR '; ') AS variants
				FROM product_combination pc
				JOIN product_attributes pa ON pc.attribute_id = pa.id
				JOIN product_attributes_detail pad ON pc.attribute_detail_id = pad.id
				GROUP BY pc.product_details_id
			) primary_variant_attrs ON primary_variant.id = primary_variant_attrs.product_details_id

			LEFT JOIN (
				SELECT 
					pc.product_details_id,
					GROUP_CONCAT(DISTINCT CONCAT_WS(': ', pa.product_attribute, pad.attribute_detail) SEPARATOR '; ') AS variants
				FROM product_combination pc
				JOIN product_attributes pa ON pc.attribute_id = pa.id
				JOIN product_attributes_detail pad ON pc.attribute_detail_id = pad.id
				GROUP BY pc.product_details_id
			) first_variant_attrs ON first_variant.id = first_variant_attrs.product_details_id

			-- Product Badges (Enhanced but still simple)
			LEFT JOIN (
				SELECT 
					pb.product_id,
					COUNT(pb.badge_id) AS badges_count,
					GROUP_CONCAT(b.name ORDER BY pb.priority ASC SEPARATOR ', ') AS badges_names,
					GROUP_CONCAT(
						CONCAT(
							b.id, ':', 
							b.name, ':', 
							b.slug, ':', 
							IFNULL(b.description, ''), ':', 
							IFNULL(b.background_color, '#FF6B6B'), ':', 
							IFNULL(b.text_color, '#FFFFFF'), ':', 
							IFNULL(b.icon, ''), ':', 
							pb.position, ':', 
							pb.priority
						)
						ORDER BY pb.priority ASC
						SEPARATOR '|'
					) AS badges_data
				FROM product_badges pb
				INNER JOIN badges b ON pb.badge_id = b.id
				WHERE pb.is_active = 1 
					AND b.is_active = 1
					AND (pb.start_date IS NULL OR pb.start_date <= NOW())
					AND (pb.end_date IS NULL OR pb.end_date >= NOW())
				GROUP BY pb.product_id
			) product_badges_data ON p.id_products = product_badges_data.product_id

			-- Additional joins
			LEFT JOIN (
				SELECT item_id, SUM(quantity) AS total_sales 
				FROM orders_detail 
				WHERE warehouse_id = 1 
				GROUP BY item_id
			) total_sales ON COALESCE(primary_variant.id, first_variant.id) = total_sales.item_id

			LEFT JOIN (
				SELECT product_id, COUNT(id) AS total_reviews 
				FROM product_review 
				GROUP BY product_id
			) total_reviews ON p.id_products = total_reviews.product_id

			LEFT JOIN resellers_price reseller_price ON COALESCE(primary_variant.id, first_variant.id) = reseller_price.product_detail_id

			LEFT JOIN brands b ON p.brand_id = b.id_brands

			INNER JOIN category_product cp ON p.id_products = cp.id_product

			WHERE p.product_status = '1'
				AND p.deleted_at IS NULL
			GROUP BY
				p.id_products
			ORDER BY 
				sort_order ASC,
				p.best_seller DESC,
				p.new_arrival DESC,
				p.popular_product DESC,
				p.priority DESC,
				COALESCE(b.priority, 0) DESC,
				p.created_at DESC
		";
	}

	private function prepare_search_products($products)
	{
		$customer = $this->session->userdata('customer');
		$is_reseller = false;
		$reseller_price_map = [];

		// Get reseller information (existing code)
		if (!empty($customer['customer_id'])) {
			$customer_id = $customer['customer_id'];
			$customer_data = $this->db->where('id_customers', $customer_id)->get('customers')->row_array();
			if (!empty($customer_data['reseller_id'])) {
				$reseller = $this->db->where('id_resellers', $customer_data['reseller_id'])->get('resellers')->row_array();
				if ($reseller) {
					$is_reseller = true;
					$reseller_prices = $this->db->where('reseller_id', $reseller['id_resellers'])->get('resellers_price')->result_array();
					foreach ($reseller_prices as $price) {
						$reseller_price_map[$price['product_detail_id']] = $price['price'];
					}
				}
			}
		}

		$formatted_products = [];

		foreach ($products as $product) {
			// Price calculations
			$is_discounted = $product['discounted_price'] > 0;
			$default_price = $product['price'];
			$discounted_price = $product['discounted_price'];
			$current_price = $is_discounted ? $discounted_price : $default_price;
			$savings_amount = ($discounted_price > 0 && $discounted_price < $default_price)
				? ($default_price - $discounted_price)
				: 0;
			$msrp_price = null;

			// Handle reseller pricing
			if ($is_reseller && isset($reseller_price_map[$product['id_detail']])) {
				$msrp_price = $current_price;
				$current_price = $reseller_price_map[$product['id_detail']];
			}

			// Get reviews
			$review_data = $this->Review_m->get_product_reviews($product['id_products']);
			$average_rating = isset($review_data['average_rating']) ? round($review_data['average_rating'], 1) : 0;
			$total_reviews = isset($review_data['total_reviews']) ? $review_data['total_reviews'] : 0;

			// Parse variants
			$variants = !empty($product['variants']) ? explode('; ', $product['variants']) : [];

			$badges = $this->parse_badges_data($product['badges_data'] ?? '');
			$badges_names = $product['badges_names'] ?? '';

			// Stock calculations - all done in SQL now, just ensure non-negative values
			$current_variant_stock_sell = max(0, intval($product['current_variant_stock_sell'] ?? 0));
			$total_stock_sell = max(0, intval($product['total_stock_sell'] ?? 0));

			$formatted_products[] = [
				'id' => $product['id_products'],
				'title' => $product['title'],
				'id_detail' => $product['id_detail'],
				'alias' => $product['alias'],
				'sku' => $product['sku'],
				'current_price' => $current_price,
				'original_price' => $is_discounted ? $default_price : null,
				'msrp_price' => $msrp_price,
				'image' => $product['image'],
				'image_secondary' => $product['image_secondary'],
				'stock' => $product['total_stock'],
				'stock_sell' => $current_variant_stock_sell,
				'total_stock_sell' => $total_stock_sell,
				'average_rating' => $average_rating,
				'total_reviews' => $total_reviews,
				'variants' => $variants,
				'is_wishlisted' => $this->_check_wishlist_status($product['id_products'], $customer['customer_id'] ?? null),
				'created_at' => $product['created_at'],
				'brand_priority' => $product['brand_priority'],
				'savings_amount' => $savings_amount,
				'is_discounted' => $is_discounted,
				'discount_percentage' => $product['discount_percentage'],

				// Stock flags - now calculated in SQL
				'is_completely_sold_out' => (bool) $product['is_completely_sold_out'],
				'current_variant_out_of_stock' => (bool) $product['current_variant_out_of_stock'],
				'has_other_variants_available' => (bool) $product['has_other_variants_available'],

				// Additional stock information
				'total_variants' => (int) $product['total_variants'],
				'available_variants' => (int) $product['available_variants'],

				// Badges
				'badges' => $badges,
				'badges_names' => $badges_names, // Simple comma-separated names for quick display
				'badges_count' => (int) ($product['badges_count'] ?? 0),
				'has_badges' => !empty($badges),

				// New arrivals flag for badges
				'new_arrivals' => ($product['new_arrival'] === 'yes'),
				'best_seller' => ($product['best_seller'] === 'yes'),
				'popular_product' => ($product['popular_product'] === 'yes'),
			];
		}

		return $formatted_products;
	}

	private function parse_badges_data($badges_data)
	{
		$badges = [];

		if (empty($badges_data)) {
			return $badges;
		}

		$badges_raw = explode('|', $badges_data);

		foreach ($badges_raw as $badge_raw) {
			if (empty($badge_raw)) continue;

			$badge_parts = explode(':', $badge_raw);

			if (count($badge_parts) >= 9) {
				$badges[] = [
					'id' => (int) $badge_parts[0],
					'name' => $badge_parts[1],
					'slug' => $badge_parts[2],
					'description' => $badge_parts[3],
					'background_color' => !empty($badge_parts[4]) ? $badge_parts[4] : '#FF6B6B',
					'text_color' => !empty($badge_parts[5]) ? $badge_parts[5] : '#FFFFFF',
					'icon' => $badge_parts[6],
					'position' => $badge_parts[7],
					'priority' => (int) $badge_parts[8],

					// Additional computed properties
					'css_class' => 'badge-' . $badge_parts[2],
					'has_icon' => !empty($badge_parts[6]),
					'style' => sprintf(
						'background-color: %s; color: %s;',
						!empty($badge_parts[4]) ? $badge_parts[4] : '#FF6B6B',
						!empty($badge_parts[5]) ? $badge_parts[5] : '#FFFFFF'
					)
				];
			}
		}

		// Already sorted by priority in SQL, but double check
		usort($badges, function ($a, $b) {
			return $a['priority'] - $b['priority'];
		});

		return $badges;
	}

	private function _check_wishlist_status($product_id, $customer_id)
	{
		if (!$customer_id) return false;

		$exists = $this->db->where([
			'customer_id' => $customer_id,
			'product_id' => $product_id
		])->get('wishlists')->num_rows();

		return $exists > 0;
	}

	public function search_dropdown()
	{
		header('Content-Type: application/json');
		$query = $this->input->get('query', TRUE);

		// Debug query
		if (!$query) {
			echo json_encode(['error' => 'No query provided']);
			return;
		}

		$this->load->model('product_m');
		$this->load->model('brand_m');
		$this->load->model('category_m');

		// Get search results for each type
		$products = $this->product_m->search_products($query);
		$brands = $this->brand_m->search_brands($query);
		$categories = $this->category_m->search_categories($query);

		// Process product results
		foreach ($products as &$product) {
			$product['url'] = base_url('product/' . $product['alias']);
			$product['image'] = base_url('uploads/product/' . $product['image']);
			$product['type'] = 'product';
		}

		// Process brand results
		foreach ($brands as &$brand) {
			$brand['url'] = base_url('brand/' . $brand['alias']);
			$brand['image'] = !empty($brand['logo']) ? base_url('uploads/brand/' . $brand['logo']) : base_url('assets/images/no-image.png');
			$brand['type'] = 'brand';
			// Add a price placeholder for consistency in UI (can be empty)
			$brand['price'] = null;
		}

		// Process category results
		foreach ($categories as &$category) {
			$category['url'] = base_url('category/' . $category['alias']);
			$category['image'] = !empty($category['image']) ? base_url('uploads/category/' . $category['image']) : base_url('assets/images/no-image.png');
			$category['type'] = 'category';
			// Add a price placeholder for consistency in UI (can be empty)
			$category['price'] = null;
		}

		$all_results = [
			'products' => $products,
			'brands' => $brands,
			'categories' => $categories
		];

		// Send the combined results
		echo json_encode(['results' => $all_results]);
	}
}

https://t.me/RX1948 - 2025