setTemplate('item/page', 'listings'); $this->setKey('view'); $this->setTitle(_t('@listings', 'Listings / View')); $this->withSeoSettings('view', 'listings')->seotext(); $this->useBreadcrumbs(); } public static function handleRoute($id) { return (new static())->handle($id); } /** * Handle page request * @param int $id item id */ public function handle($id) { $this->itemId = $id; $this->userId = $this->request->userId(); if (! $id || ! $this->loadItem()) { return $this->errors->error404(); } $this->from = $this->input->get('from', TYPE_STR); $this->moderation = Listings::moderationUrlKey($id, $this->input->get('mod', TYPE_STR)); # Last Modified if (! $this->isDebug() && ! $this->userId && $this->request->isRobot()) { if (! $this->request->lastModified($this->item['modified'])) { return Response::notModified($this->item['modified']); } } # Url correction $this->request->urlCorrection($this->item['link']); return $this; } public function loadItem() { if (! empty($this->item)) { return true; } $this->item = Listings::model()->itemDataView($this->itemId); if (empty($this->item)) { return false; } # Item owner $this->item['owner'] = ($this->item['user_id'] && $this->userId && $this->userId == $this->item['user_id']); # Owner data $this->item['user'] = Users::model()->usersDataSidebar($this->item['user_id']); # Owner company data $this->item['company'] = []; if ($this->item['company_id'] && $this->item['user']['company_id'] && bff::businessEnabled()) { $this->item['company'] = Business::model()->companiesDataSidebar($this->item['user']['company_id']); if ($this->item['company']) { $this->item['name'] = $this->item['company']['title']; } } $this->item['is_company'] = ($this->item['company_id'] && $this->item['company']); # Add contacts from profile if (Listings::getItemContactsFromProfile()) { if ($this->item['is_company']) { $contactsData = &$this->item['company']; } else { $contactsData = &$this->item['user']; $this->item['name'] = ! empty($contactsData['name']) ? $contactsData['name'] : $contactsData['login']; } $contacts = [ 'contacts' => $contactsData['contacts'], 'phones' => [], ]; if (! empty($contactsData['phones'])) { foreach ($contactsData['phones'] as $v) { $contacts['phones'][] = $v['m']; } } $this->item['contacts'] = &$contacts; unset($contactsData); $this->item['contacts']['has'] = !empty($contacts['contacts']) || !empty($contacts['phones']); } # Categories $this->item['categories'] = Listings::categoryCrumbs($this->item['cat_id'], 'view', $this->item['city']['url'] ?? []); # Status $this->item['is_publicated'] = ($this->item['status'] == Listings::STATUS_PUBLICATED) && ! empty($this->item['is_publicated']); $this->item['is_publicated_out'] = ($this->item['status'] == Listings::STATUS_PUBLICATED_OUT); $this->item['is_blocked'] = ($this->item['status'] == Listings::STATUS_BLOCKED && ($this->item['owner'] || $this->moderation)); # Shortcuts $this->item['is_business'] = ($this->item['owner_type'] == Listings::OWNER_BUSINESS); $this->item['is_map'] = ( ! empty($this->item['addr_addr']) && $this->item['addr_lat'] != 0 && $this->item['cat_addr'] ); $this->item['city_title_delivery'] = $this->item['city']['title'] ?? ''; if (!empty($this->item['regions_delivery']) && !empty($this->item['city_title'])) { $region = Geo::filter(); $this->item['city_title_delivery'] = _t('listings', 'Delivery from [city]', [ 'city' => $this->item['city']['title'] ?? '', 'filter_region' => $region['title'] ?? '', ]); } $this->item['is_soon_left'] = ( $this->item['publicated_period'] > 0 && ((strtotime($this->item['publicated_to']) - BFF_NOW) < Listings::PUBLICATION_SOON_LEFT) ); # Category $this->categoryId = $this->item['cat_id'] ?: 0; return true; } /** * Show status message only * @return bff\http\RedirectResponse|false|string */ public function showStatusMessage() { if ($this->item['is_publicated']) { if (! $this->item['moderated'] && Listings::premoderation() && ! $this->moderation && ! $this->item['owner']) { return $this->forbiddenMessage( _t('view', 'This listing is under moderation'), _t('view', 'It will be published after verification') ); } return false; } if ($this->item['status'] == Listings::STATUS_DELETED) { if (! empty($this->item['categories'])) { # возвращаем на список объявлений категории # в которой находилось данное объявление до удаления foreach (array_reverse($this->item['categories']) as $v) { if ($v['id']) { return Redirect::to($v['link']); } } return Redirect::to(Listings::url('items.search', $this->item['city']['url'] ?? [])); } return $this->forbiddenMessage( _t('view', 'View Listing'), _t('view', 'The listing was removed or blocked by the moderator') ); } if (! $this->moderation) { if ($this->item['status'] == Listings::STATUS_BLOCKED && !$this->item['owner']) { return $this->forbiddenMessage( _t('view', 'Listing blocked'), _t('view', 'Reason for blocking:
[reason]', [ 'reason' => nl2br($this->item['blocked_reason']), ]) ); } if ($this->item['status'] == Listings::STATUS_NOTACTIVATED) { return $this->successMessage( _t('view', 'View Listing'), _t('view', 'The listing is not yet activated by the user') ); } if ( $this->item['moderated'] && $this->item['status'] != Listings::STATUS_PUBLICATED_OUT && $this->item['status'] != Listings::STATUS_BLOCKED && !$this->item['owner'] ) { return $this->forbiddenMessage( _t('view', 'This listing is under moderation'), _t('view', 'It will be published again after verification') ); } } # Listings::STATUS_PUBLICATED_OUT => show unpublicated items return false; } public function data() { $data = parent::data(); if (empty($this->item)) { return $this->errors->error404(); } # Publication date if (! $this->publicationDate) { $this->item['created'] = ''; $this->item['publicated'] = ''; $this->item['publicated_last'] = ''; } # Check item status $statusMessage = $this->showStatusMessage(); if ($statusMessage !== false) { return $statusMessage; } # Images $images = Listings::itemImages($this->itemId); $data['images'] = $images->getData($this->item['imgcnt']); if (! empty($data['images'])) { $data['image_view'] = $images->getURL(reset($data['images']), $images::szView); $i = 1; foreach ($data['images'] as &$v) { $v['t'] = _t('view', '[title] [city] - photo [num]', [ 'title' => $this->item['title'], 'city' => $this->item['city_title'], 'num' => $i++, ]); $v['url_small'] = $images->getURL($v, $images::szSmall); $v['url_view'] = $images->getURL($v, $images::szView); $v['url_zoom'] = $images->getURL($v, $images::szZoom); } unset($v); } else { $data['image_view'] = $images->urlDefault($images::szView); } # Video $this->item['video'] = Listings::itemVideo()->viewIframe($this->item['video_embed']); # Dynprops $data['dynprops'] = Listings::dp()->onView($this->item['cat_id'], $this->item, ['dataOnly' => -1]); $data['dynpropsBlock'] = $data['dynprops']['form'] ?: ''; # Is favorite $data['fav'] = Listings::favorites()->isFavorite($this->itemId, $this->userId); # Increment views if not: # - owner # - redirect from admin panel # - page refresh if (!$this->item['owner'] && $this->from != 'adm' && !$this->request->isRefresh()) { if (Listings::model()->itemViewsIncrement($this->itemId, 'item', $this->item['views_today'])) { $this->item['views_total']++; $this->item['views_today']++; } } # Free top up if ($this->input->get('up_free', TYPE_UINT) == 1 && $this->item['owner']) { $up = Listings::itemServices('up'); if ($up) { $msg = $up->upFree($this->itemId); if ($this->errors->no()) { $data['msg_success'] = $msg; } else { $data['msg_error'] = join('
', $this->errors->get()); } } } $data['premoderation'] = Listings::premoderation(); # Share code $data['sharecodeBlock'] = ($this->sharecode ? $this->config('sharecode', '', TYPE_STR) : ''); # Banners query Banners::viewQuery($this->item['title']); # Merge data + item data foreach ($this->item as $key => $value) { $data[$key] = &$this->item[$key]; } # Page data $this->view->setPageData([ 'listings_view_id' => $this->itemId, 'listings_view_data' => &$data, ]); $data['descr'] = nl2br($data['descr']); return $data; } public function blocks() { $this->addMenu('listings.item'); $this->addBlock('contactFormBlock', ContactFormBlock::class, function ($block) { $block->prerenderable(true); }); $this->addBlock('claimBlock', ClaimBlock::class, function (ClaimBlock $block) { $block->itemId = $this->itemId; $block->itemOwner = $this->itemId && $this->item['owner']; }); $this->addBlock('sendfriendBlock', SendfriendBlock::class, function (SendfriendBlock $block) { $block->itemId = $this->itemId; }); $this->addBlock('viewsStatisticBlock', ViewsStatisticBlock::class, function (ViewsStatisticBlock $block) { $block->prerenderable(true); $block->itemId = $this->itemId; $block->itemOwner = $this->itemId && $this->item['owner']; $block->views_total = $this->item['views_total'] ?? 0; $block->views_today = $this->item['views_today'] ?? 0; }); $this->addBlock('commentsBlock', CommentsBlock::class, function (CommentsBlock $block) { if ($this->itemId) { $block->setSettings(Listings::itemComments()->getBlockSettings( $this->itemId, $this->userId, [ 'user_id' => $this->item['user_id'], 'company_id' => $this->item['company_id'], 'status' => $this->item['status'], ], $this->item['company'] ?? [] )); $this->getMenu()->add('comments', _t('comments', 'Comments: [total]', [ 'total' => $this->item['comments_cnt'] ?? 0, ])) ->first() ->addBlock('comments', $block) ->enabled(function () { return $this->comments; }) ->icon(bff::url('/img/icons/page-comments.svg')) ->active(true) ->end(); } }); $this->addBlock('similarBlock', SimilarItemsBlock::class, function (SimilarItemsBlock $block) { $block->prerenderable(true); if ($this->itemId && $this->item['is_publicated'] && ! $this->moderation) { $block->itemId = $this->itemId; $block->categories = array_filter(array_keys($this->item['categories']), function ($v) { return ($v > 0); }); $block->categoryType = $this->item['cat_type']; $block->regionId = Geo::filter('id'); } }); $this->addTemplateBlock('actionsTop', 'item/actions.top', 'listings'); $this->addTemplateBlock('actionsBottom', 'item/actions.bottom', 'listings'); $this->addTemplateBlock('alertsBlock', 'item/alerts', 'listings'); $this->addTemplateBlock('mediaBlock', 'item/media', 'listings'); $this->addTemplateBlock('vendorBlock', 'item/vendor', 'listings'); $this->addTemplateBlock('contactsBlock', 'item/contacts', 'listings'); $this->addBlock('onlineBlock', OnlineBlock::class, function (OnlineBlock $block) { $block->lastActivity = $this->item['user']['last_activity'] ?? false; }); $this->addBlock('controlsBlock', ControlsBlock::class); $this->banners(); } public function banners() { // } public function seo() { $data = &$this->data; $this->seo->canonicalUrl($this->item['link']); $metaCategories = []; $data['breadcrumb'] = []; foreach ($this->item['categories'] as $k => &$v) { if ($k) { $metaCategories[] = $v['title']; } $data['breadcrumb'][] = &$v['breadcrumb']; } unset($v); $this->seo->with([ 'id' => $this->itemId, 'name' => $this->item['name'], 'title' => $this->item['title'], 'description' => tpl::truncate($this->item['descr'], $this->config('listings.view.meta.description.limit', 150, TYPE_UINT)), 'price' => ($this->item['price_on'] ? $this->item['price'] . (!empty($this->item['price_mod']) ? ' ' . $this->item['price_mod'] : '') : ''), 'address' => (!empty($this->item['cat_addr']) && !empty($this->item['addr_addr']) ? $this->item['addr_addr'] : ''), 'district' => (!empty($this->item['district_data']['title']) ? $this->item['district_data']['title'] : ''), 'category' => $this->item['cat_title'], 'categories' => join(', ', $metaCategories), 'categories.reverse' => join(', ', array_reverse($metaCategories, true)), 'category+parent' => join(', ', array_reverse(array_splice($metaCategories, (sizeof($metaCategories) > 2 ? sizeof($metaCategories) - 2 : 0)))), ]); # Region $this->seoMacrosRegionsData($this->item['geo_city']); # Dynprops $dynpropsData = []; foreach ($data['dynprops']['data'] as $v) { $catTypePrefix = ($this->item['cat_type'] == Listings::TYPE_OFFER ? ':offer' : ':seek'); $v['value'] = (is_array($v['value']) ? join(', ', $v['value']) : $v['value']); if (!empty($v['child_to'])) { if (isset($dynprops['data'][$v['child_to']])) { $vp = $dynprops['data'][$v['child_to']]; if (!empty($vp['cache_key'])) { $dynpropsData[$vp['cache_key'] . '.sub'] = $v['value']; } $dynpropsData[$v['child_to'] . '.sub'] = $v['value']; } } else { if (!empty($v['cache_key'])) { $dynpropsData[$v['cache_key']] = $v['value']; $dynpropsData[$v['cache_key'] . $catTypePrefix] = $v['value']; } $dynpropsData[$v['id']] = $v['value']; $dynpropsData[$v['id'] . $catTypePrefix] = $v['value']; } } $this->seo->with($dynpropsData); # View template only (no category template) if (! $data['mcategorytemplate']) { $this->seo->fill($data); } # social images foreach ($data['images'] as $k => $v) { $data['images'][$k]['width'] = 0; $data['images'][$k]['height'] = 0; $data['images'][$k]['social_url'] = $v['url_zoom']; } $this->seo->fieldPlaceholders( 'breadcrumb', ['category'], ['region' => 'city','region.in' => 'city.in'] ); $this->seoApply($data, ['divider' => '|']); $this->breadcrumb = ''; # prevent autoreplace last breadcrumb $this->breadcrumbs->activateLast = false; $this->breadcrumbs->fill($this->item['categories'], function ($crumb) { return [ 'title' => $crumb['breadcrumb'], 'link' => $crumb['link'], ]; }); } public function seoSettings() { $this->seo ->placeholders([ 'id' => _t('listings', 'Listing ID'), 'name' => _t('listings', 'User Name'), 'title' => _t('', 'Title'), 'description' => _t('listings', 'Description (Up to [size] characters)'), 'price' => _t('listings', 'Cost'), 'address' => _t('geo', 'Address'), 'district' => _t('geo', 'City District'), 'category' => _t('listings', 'Current listing category'), 'category+parent' => _t('listings', 'Current category + category above'), 'categories' => _t('listings', 'Title of all categories'), 'categories.reverse' => _t('listings', 'Title of all categories
(reverse order)'), ]) ->social() ->inheritance(); $this->seoMacrosRegions(); } public function settingsForm($form) { $form->checkbox('comments', _t('@listings', 'Listings Commenting'), $this->comments) ->sysAdmin('listings.comments'); $form->select('mediaGalleryImagesWidth', _t('@listings', 'Gallery Images Width')) ->option('auto', _t('@listings', 'Auto')) ->option('default', _t('@listings', 'Default')) ; $form->select('sharecode', _t('@', 'Share Block'), $this->sharecode, function () { return [ ['id' => 1, 'title' => _t('@', 'Enabled'), 'help' => ( ' Site::settingsSystemLink('main', ['sett' => 'sharecode']), 'target' => '_blank']) . '>' . _t('@site', 'block settings') . '' )], ['id' => 0, 'title' => _t('@', 'Disabled')], ]; }, false, ['showHelp' => true]); } }