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]);
}
}