src/Controller/PageController.php line 16

Open in your IDE?
  1. <?php
  2. namespace App\Controller;
  3. use App\Controller\Catalog\CatalogRepository;
  4. use Doctrine\DBAL\Connection;
  5. use Symfony\Component\HttpFoundation\Request;
  6. use Symfony\Component\HttpFoundation\Response;
  7. use Symfony\Component\Routing\Annotation\Route;
  8. class PageController extends BaseController
  9. {
  10.     /**
  11.      * @Route("/", name="home", methods={"GET"})
  12.      */
  13.     public function home(Request $requestConnection $dbCatalogRepository $catalog): Response
  14.     {
  15.         $products $catalog->listProducts(15);
  16.         return $this->render('index.html.twig', [
  17.             'user' => $this->publicUser($this->getAuthorizedUser($request$db)),
  18.             'catalog_products' => $products,
  19.             'catalog_payload_json' => $catalog->payloadJson($products),
  20.         ]);
  21.     }
  22.     /**
  23.      * @Route("/profile", name="profile", methods={"GET"})
  24.      */
  25.     public function profile(Request $requestConnection $dbCatalogRepository $catalog): Response
  26.     {
  27.         $user $this->getAuthorizedUser($request$db);
  28.         if (!$user) {
  29.             return $this->redirectToRoute('home', [
  30.                 'auth' => 'login',
  31.                 'redirect' => $request->getRequestUri(),
  32.             ]);
  33.         }
  34.         $catalog->ensureSchema();
  35.         $orders $this->profileOrders($db$user);
  36.         return $this->render('profile.html.twig', [
  37.             'user' => $this->publicUser($user),
  38.             'profile_orders' => $orders,
  39.             'profile_orders_count' => count($orders),
  40.             'profile_purchase_groups' => $this->profilePurchaseGroups($orders5),
  41.         ]);
  42.     }
  43.     /**
  44.      * @Route("/referral", name="referral", methods={"GET"})
  45.      */
  46.     public function referral(Request $requestConnection $db): Response
  47.     {
  48.         $user $this->getAuthorizedUser($request$db);
  49.         if (!$user) {
  50.             return $this->redirectToRoute('home', [
  51.                 'auth' => 'login',
  52.                 'redirect' => $request->getRequestUri(),
  53.             ]);
  54.         }
  55.         return $this->render('referral.html.twig', [
  56.             'user' => $this->publicUser($user),
  57.             'referral_url' => $this->referralUrl($request$user),
  58.         ]);
  59.     }
  60.     /**
  61.      * @Route("/topup", name="topup", methods={"GET"})
  62.      */
  63.     public function topup(Request $requestConnection $db): Response
  64.     {
  65.         return $this->render('topup.html.twig', [
  66.             'user' => $this->publicUser($this->getAuthorizedUser($request$db)),
  67.         ]);
  68.     }
  69.     private function referralUrl(Request $request, array $user): string
  70.     {
  71.         return $request->getSchemeAndHttpHost() . '/?ref=' rawurlencode((string) $user['id']);
  72.     }
  73.     private function profileOrders(Connection $db, array $user): array
  74.     {
  75.         $userId = (int) ($user['id'] ?? 0);
  76.         $email trim((string) ($user['email'] ?? ''));
  77.         $where = [];
  78.         $params = [];
  79.         if ($userId 0) {
  80.             $where[] = 'o.user_id = ?';
  81.             $params[] = $userId;
  82.         }
  83.         if ($email !== '') {
  84.             $where[] = 'LOWER(o.buyer_email) = LOWER(?)';
  85.             $params[] = $email;
  86.         }
  87.         if (!$where) {
  88.             return [];
  89.         }
  90.         try {
  91.             $rows $db->fetchAllAssociative(
  92.                 'SELECT o.*,
  93.                         p.image_url AS product_image_url,
  94.                         p.slug AS product_slug,
  95.                         cp.public_id AS payment_public_id,
  96.                         cp.pay_url AS payment_pay_url,
  97.                         cp.status AS payment_status,
  98.                         COALESCE(o.amount, cp.amount) AS display_amount,
  99.                         COALESCE(o.currency, cp.currency) AS display_currency
  100.                  FROM catalog_orders o
  101.                  LEFT JOIN catalog_products p ON p.id = o.product_id
  102.                  LEFT JOIN catalog_payments cp ON cp.id = (
  103.                     SELECT cp2.id
  104.                     FROM catalog_payments cp2
  105.                     WHERE cp2.order_public_id = o.public_id
  106.                     ORDER BY cp2.id DESC
  107.                     LIMIT 1
  108.                  )
  109.                  WHERE (' implode(' OR '$where) . ')
  110.                  ORDER BY o.created_at DESC, o.id DESC
  111.                  LIMIT 200',
  112.                 $params
  113.             );
  114.         } catch (\Throwable $error) {
  115.             return [];
  116.         }
  117.         return array_map(function (array $row): array {
  118.             return $this->profileOrderView($row);
  119.         }, $rows);
  120.     }
  121.     private function profilePurchaseGroups(array $ordersint $limit): array
  122.     {
  123.         $groups = [];
  124.         foreach (array_slice($orders0$limit) as $order) {
  125.             $label = (string) ($order['date_group'] ?? '');
  126.             if ($label === '') {
  127.                 $label 'Без даты';
  128.             }
  129.             if (!isset($groups[$label])) {
  130.                 $groups[$label] = [
  131.                     'label' => $label,
  132.                     'orders' => [],
  133.                 ];
  134.             }
  135.             $groups[$label]['orders'][] = $order;
  136.         }
  137.         return array_values($groups);
  138.     }
  139.     private function profileOrderView(array $row): array
  140.     {
  141.         $date $this->profileOrderDate($row['created_at'] ?? null);
  142.         $status strtolower(trim((string) ($row['status'] ?? 'created')));
  143.         $productSlug trim((string) ($row['product_slug'] ?? ''));
  144.         $paymentPublicId trim((string) ($row['payment_public_id'] ?? ''));
  145.         $paymentPayUrl trim((string) ($row['payment_pay_url'] ?? ''));
  146.         $productUrl $productSlug !== '' '/product?slug=' rawurlencode($productSlug) : '#';
  147.         $statusClass $this->profileOrderStatusClass($status);
  148.         return [
  149.             'id' => (string) ($row['public_id'] ?? ''),
  150.             'title' => (string) ($row['product_name'] ?? 'Товар PlayPapa'),
  151.             'date_iso' => $date->format('Y-m-d\TH:i:sP'),
  152.             'date_label' => $this->profileDateLabel($date),
  153.             'date_table_label' => $date->format('d.m.Y'),
  154.             'time_label' => $date->format('H:i'),
  155.             'date_group' => $this->profileDateGroup($date),
  156.             'amount_label' => $this->profileAmountLabel($row['display_amount'] ?? $row['amount'] ?? null, (string) ($row['display_currency'] ?? $row['currency'] ?? 'RUB')),
  157.             'status_label' => $this->profileOrderStatusLabel($status),
  158.             'status_class' => $statusClass,
  159.             'image' => $this->profileOrderImage($row['product_image_url'] ?? ''),
  160.             'product_url' => $productUrl,
  161.             'details_url' => $paymentPublicId !== '' '/pay/' rawurlencode($paymentPublicId) : $productUrl,
  162.             'pay_url' => $paymentPayUrl,
  163.             'payable' => $paymentPayUrl !== '' && in_array($status, ['created''awaiting_payment''payment_pending''pending'], true),
  164.             'completed' => $statusClass === 'history-table__status--success',
  165.         ];
  166.     }
  167.     private function profileOrderDate($value): \DateTimeImmutable
  168.     {
  169.         try {
  170.             return new \DateTimeImmutable((string) $value);
  171.         } catch (\Throwable $error) {
  172.             return new \DateTimeImmutable();
  173.         }
  174.     }
  175.     private function profileDateGroup(\DateTimeImmutable $date): string
  176.     {
  177.         $day $date->setTime(00);
  178.         $today = (new \DateTimeImmutable('today'))->setTime(00);
  179.         $yesterday $today->modify('-1 day');
  180.         if ($day->getTimestamp() === $today->getTimestamp()) {
  181.             return 'Сегодня';
  182.         }
  183.         if ($day->getTimestamp() === $yesterday->getTimestamp()) {
  184.             return 'Вчера';
  185.         }
  186.         return $date->format('d.m.Y');
  187.     }
  188.     private function profileDateLabel(\DateTimeImmutable $date): string
  189.     {
  190.         $months = [
  191.             => 'января',
  192.             => 'февраля',
  193.             => 'марта',
  194.             => 'апреля',
  195.             => 'мая',
  196.             => 'июня',
  197.             => 'июля',
  198.             => 'августа',
  199.             => 'сентября',
  200.             10 => 'октября',
  201.             11 => 'ноября',
  202.             12 => 'декабря',
  203.         ];
  204.         return (int) $date->format('j') . ' ' $months[(int) $date->format('n')] . ' ' $date->format('Y');
  205.     }
  206.     private function profileAmountLabel($amountstring $currency): string
  207.     {
  208.         if ($amount === null || $amount === '') {
  209.             return '—';
  210.         }
  211.         $value = (float) $amount;
  212.         $precision abs($value round($value)) < 0.005 2;
  213.         $currency strtoupper(trim($currency ?: 'RUB'));
  214.         $symbols = [
  215.             'RUB' => '₽',
  216.             'USD' => '$',
  217.             'EUR' => '€',
  218.             'KZT' => '₸',
  219.             'UAH' => '₴',
  220.         ];
  221.         return number_format($value$precision','' ') . ' ' . ($symbols[$currency] ?? $currency);
  222.     }
  223.     private function profileOrderStatusLabel(string $status): string
  224.     {
  225.         $labels = [
  226.             'created' => 'Создан',
  227.             'awaiting_payment' => 'Ожидает оплату',
  228.             'payment_pending' => 'Ожидает оплату',
  229.             'payment_paid' => 'Оплата получена',
  230.             'sending' => 'В обработке',
  231.             'pending' => 'В обработке',
  232.             'completed' => 'Успешно',
  233.             'partial' => 'Частично',
  234.             'paid' => 'Успешно',
  235.             'failed' => 'Ошибка',
  236.             'galaxylink_error' => 'Ошибка',
  237.             'payment_failed' => 'Ошибка оплаты',
  238.             'expired' => 'Истёк',
  239.             'payment_expired' => 'Истёк',
  240.             'cancelled' => 'Отменён',
  241.             'payment_cancelled' => 'Отменён',
  242.             'refunded' => 'Возврат',
  243.             'manual_check' => 'Проверка',
  244.         ];
  245.         return $labels[$status] ?? $status;
  246.     }
  247.     private function profileOrderStatusClass(string $status): string
  248.     {
  249.         if (in_array($status, ['completed''partial''paid'], true)) {
  250.             return 'history-table__status--success';
  251.         }
  252.         if (in_array($status, ['failed''galaxylink_error''payment_failed''expired''payment_expired''cancelled''payment_cancelled''refunded'], true)) {
  253.             return 'history-table__status--cancel';
  254.         }
  255.         return 'history-table__status--pending';
  256.     }
  257.     private function profileOrderImage($value): string
  258.     {
  259.         $image trim((string) $value);
  260.         if ($image === '') {
  261.             return '/assets/product-doom.jpg';
  262.         }
  263.         if (preg_match('~^(?:https?:)?//~i'$image) || strpos($image'/') === 0) {
  264.             return $image;
  265.         }
  266.         return '/' ltrim($image'/');
  267.     }
  268. }