Initial commit - monorepo

This commit is contained in:
Alexander Yakovlev 2024-06-02 12:37:06 +06:00
commit 6ee031045b
Signed by: oreolek
GPG key ID: 8269E24B4008E32A
2041 changed files with 253077 additions and 0 deletions

7
.gitignore vendored Normal file
View file

@ -0,0 +1,7 @@
application/config/config.local.php
application/logs
uploads
application/tmp
application/plugins/admin
application/plugins/
application/install

3
.gitmodules vendored Normal file
View file

@ -0,0 +1,3 @@
[submodule "framework"]
path = framework
url = https://github.com/livestreet/livestreet-framework.git

48
.travis.yml Normal file
View file

@ -0,0 +1,48 @@
language: php
php:
- 5.3
- 5.4
before_script:
# export virtual display
- export DISPLAY=:99
# change application working folders for write access
- chmod -R 0777 ./tmp
- chmod -R 0777 ./uploads
- chmod -R 0777 ./templates/cache/
- chmod -R 0777 ./templates/compiled/
- cp ./install/*.sql tests/fixtures/sql/
- rm -rf ./install
# install required PHP stuff
- sudo apt-get update
- sudo apt-get install php5 php5-cli php5-mysql php5-mcrypt php5-xsl php5-xdebug php-apc php5-gd php5-curl php5-intl mysql-server mysql-client
# launch apache, MySQL and PHPUnit Selenium installers
- ./tests/travis/apache_setup.sh
- ./tests/travis/mysql_setup.sh
- mysql -u root -e "USE social_test; SHOW TABLES;" | wc -l
- cp ./config/config.test.php.dist config/config.test.php
- cp ./config/config.test.php.dist config/config.local.php
- sudo sed -i s/sql-mode/#sql-mode/ /etc/mysql/my.cnf
- sudo /etc/init.d/mysql restart
- sleep 5
# get HTML of main page (for debug)
- firefox --version
- wget -S http://livestreet.test -O /dev/null
# start virtual display
- sh -e /etc/init.d/xvfb start
- sleep 5
# download and launch Selenium
- wget -O /tmp/selenium-server-standalone.jar http://selenium.dev.stfalcon.com/selenium-server-standalone-latest.jar
- java -jar /tmp/selenium-server-standalone.jar > /dev/null &
- sleep 5
script: HTTP_APP_ENV=test php tests/behat/behat.phar -c tests/behat/behat.yml

15
README.md Normal file
View file

@ -0,0 +1,15 @@
Исходный код ifhub.ru
На основе [LiveStreet CMS](http://livestreetcms.ru) 2.0.1.dev
### Лицензия
LiveStreet - open-source проект под лицензией [GPL-2.0](http://opensource.org/licenses/GPL-2.0).
Readme
-------------
* [English README](https://github.com/livestreet/livestreet/blob/master/Readme.EN.txt)
* [Russian README](https://github.com/livestreet/livestreet/blob/master/Readme.RU.txt)

View file

@ -0,0 +1,2 @@
Order Deny,Allow
Deny from all

View file

@ -0,0 +1,171 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Экшен обработки УРЛа вида /admin/
*
* @package application.actions
* @since 1.0
*/
class ActionAdmin extends Action
{
/**
* Текущий пользователь
*
* @var ModuleUser_EntityUser|null
*/
protected $oUserCurrent = null;
/**
* Главное меню
*
* @var string
*/
protected $sMenuHeadItemSelect = 'admin';
/**
* Инициализация
*
* @return string
*/
public function Init()
{
/**
* Если нет прав доступа - перекидываем на 404 страницу
*/
if (!$this->User_IsAuthorization() or !$oUserCurrent = $this->User_GetUserCurrent() or !$oUserCurrent->isAdministrator()) {
return parent::EventNotFound();
}
$this->SetDefaultEvent('index');
$this->oUserCurrent = $oUserCurrent;
}
/**
* Регистрация евентов
*/
protected function RegisterEvent()
{
$this->AddEvent('index', 'EventIndex');
$this->AddEvent('plugins', 'EventPlugins');
}
/**********************************************************************************
************************ РЕАЛИЗАЦИЯ ЭКШЕНА ***************************************
**********************************************************************************
*/
/**
* Отображение главной страницы админки
*/
protected function EventIndex()
{
/**
* Определяем доступность установки расширенной админ-панели
*/
$aPluginsAll = func_list_plugins(true);
if (in_array('admin', $aPluginsAll)) {
$this->Viewer_Assign('availableAdminPlugin', true);
}
}
/**
* Страница со списком плагинов
*
*/
protected function EventPlugins()
{
$this->sMenuHeadItemSelect = 'plugins';
/**
* Получаем название плагина и действие
*/
if ($sPlugin = getRequestStr('plugin', null, 'get') and $sAction = getRequestStr('action', null, 'get')) {
return $this->SubmitManagePlugin($sPlugin, $sAction);
}
/**
* Получаем список блогов
*/
$aPlugins = $this->PluginManager_GetPluginsItems(array('order' => 'name'));
/**
* Загружаем переменные в шаблон
*/
$this->Viewer_Assign('plugins', $aPlugins);
$this->Viewer_AddHtmlTitle($this->Lang_Get('admin.plugins.title'));
/**
* Устанавливаем шаблон вывода
*/
$this->SetTemplateAction('plugins');
}
/**
* Активация\деактивация плагина
*
* @param string $sPlugin Имя плагина
* @param string $sAction Действие
*/
protected function SubmitManagePlugin($sPlugin, $sAction)
{
$this->Security_ValidateSendForm();
if (!in_array($sAction, array('activate', 'deactivate', 'remove', 'apply_update'))) {
$this->Message_AddError($this->Lang_Get('admin.plugins.notices.unknown_action'), $this->Lang_Get('common.error.error'),
true);
Router::Location(Router::GetPath('admin/plugins'));
}
$bResult = false;
/**
* Активируем\деактивируем плагин
*/
if ($sAction == 'activate') {
$bResult = $this->PluginManager_ActivatePlugin($sPlugin);
} elseif ($sAction == 'deactivate') {
$bResult = $this->PluginManager_DeactivatePlugin($sPlugin);
} elseif ($sAction == 'remove') {
$bResult = $this->PluginManager_RemovePlugin($sPlugin);
} elseif ($sAction == 'apply_update') {
$this->PluginManager_ApplyPluginUpdate($sPlugin);
$bResult = true;
}
if ($bResult) {
$this->Message_AddNotice($this->Lang_Get('admin.plugins.notices.action_ok'), $this->Lang_Get('common.attention'),
true);
} else {
if (!($aMessages = $this->Message_GetErrorSession()) or !count($aMessages)) {
$this->Message_AddErrorSingle($this->Lang_Get('common.error.system.base'), $this->Lang_Get('common.error.error'), true);
}
}
/**
* Возвращаем на страницу управления плагинами
*/
Router::Location(Router::GetPath('admin') . 'plugins/');
}
/**
* Выполняется при завершении работы экшена
*
*/
public function EventShutdown()
{
/**
* Загружаем в шаблон необходимые переменные
*/
$this->Viewer_Assign('sMenuHeadItemSelect', $this->sMenuHeadItemSelect);
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,55 @@
<?php
/**
* Страницы с архивами
*
* @package application.actions
* @since 1.0
*/
class ActionArchive extends Action
{
/**
* Инициализация экшена
*
*/
public function Init()
{
/**
* Устанавливаем дефолтный евент
*/
$this->SetDefaultEvent('index');
}
/**
* Регистрируем евенты
*
*/
protected function RegisterEvent()
{
$this->AddEvent('index', 'EventIndex');
$this->AddEvent('wiki', 'EventIfwiki');
}
/**
* Вывод списка архивов
*
*/
protected function EventIndex()
{
/**
* Устанавливаем title страницы
*/
$this->Viewer_AddHtmlTitle('Архивы');
$this->SetTemplateAction('index');
}
/**
* Архивы вики
*/
protected function EventIfwiki()
{
$this->Viewer_AddHtmlTitle('Архивы IFWiki');
$files = array_slice(scandir('./wikidump'), 2);
$this->SetTemplateAction('archive');
$this->Viewer_Assign('files', $files);
}
}

View file

@ -0,0 +1,624 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Обрабатывает авторизацию/регистрацию
*
* @package application.actions
* @since 1.0
*/
class ActionAuth extends Action
{
/**
* Инициализация
*
*/
public function Init()
{
/**
* Если включены инвайты то перенаправляем на страницу регистрации по инвайтам
*/
if (!$this->User_IsAuthorization() and Config::Get('general.reg.invite') and in_array(Router::GetActionEvent(),
array('register', 'ajax-register')) and !$this->CheckInviteRegister()
) {
return Router::Action('auth', 'invite');
}
/**
* Устанавливаем дефолтный евент
*/
$this->SetDefaultEvent('login');
/**
* Отключаем отображение статистики выполнения
*/
Router::SetIsShowStats(false);
}
/**
* Регистрируем евенты
*
*/
protected function RegisterEvent()
{
$this->AddEvent('login', 'EventLogin');
$this->AddEvent('logout', 'EventLogout');
$this->AddEvent('password-reset', 'EventPasswordReset');
$this->AddEvent('register', 'EventRegister');
$this->AddEvent('register-confirm', 'EventRegisterConfirm');
$this->AddEvent('activate', 'EventActivate');
$this->AddEvent('reactivation', 'EventReactivation');
$this->AddEvent('invite', 'EventInvite');
$this->AddEventPreg('/^referral$/i', '/^[\w\-\_]{1,200}$/i', 'EventReferral');
$this->AddEvent('ajax-login', 'EventAjaxLogin');
$this->AddEvent('ajax-password-reset', 'EventAjaxPasswordReset');
$this->AddEvent('ajax-validate-fields', 'EventAjaxValidateFields');
$this->AddEvent('ajax-validate-login', 'EventAjaxValidateLogin');
$this->AddEvent('ajax-validate-email', 'EventAjaxValidateEmail');
$this->AddEvent('ajax-register', 'EventAjaxRegister');
$this->AddEvent('ajax-reactivation', 'EventAjaxReactivation');
}
/**
* Ajax авторизация
*/
protected function EventAjaxLogin()
{
/**
* Устанвливаем формат Ajax ответа
*/
$this->Viewer_SetResponseAjax('json');
/**
* Логин и пароль являются строками?
*/
if (!is_string(getRequest('login')) or !is_string(getRequest('password'))) {
$this->Message_AddErrorSingle($this->Lang_Get('common.error.system.base'));
return;
}
/**
* Проверяем есть ли такой юзер по логину
*/
if ((func_check(getRequest('login'),
'mail') and $oUser = $this->User_GetUserByMail(getRequest('login'))) or $oUser = $this->User_GetUserByLogin(getRequest('login'))
) {
/**
* Выбираем сценарий валидации
*/
$oUser->_setValidateScenario('signIn');
/**
* Заполняем поля (данные)
*/
$oUser->setCaptcha(getRequestStr('captcha'));
/**
* Запускаем валидацию
*/
if ($oUser->_Validate()) {
/**
* Сверяем хеши паролей и проверяем активен ли юзер
*/
if ($this->User_VerifyAccessAuth($oUser) and $oUser->verifyPassword(getRequest('password'))) {
if (!$oUser->getActivate()) {
$this->Message_AddErrorSingle($this->Lang_Get('auth.login.notices.error_not_activated',
array('reactivation_path' => Router::GetPath('auth/reactivation'))));
return;
}
$bRemember = getRequest('remember', false) ? true : false;
/**
* Убиваем каптчу
*/
$this->Session_Drop('captcha_keystring_user_auth');
/**
* Авторизуем
*/
$this->User_Authorization($oUser, $bRemember);
/**
* Определяем редирект
*/
$sUrl = Config::Get('module.user.redirect_after_login');
if (getRequestStr('return-path')) {
$sUrl = getRequestStr('return-path');
}
$this->Viewer_AssignAjax('sUrlRedirect', $sUrl ? $sUrl : Router::GetPath('/'));
return;
}
} else {
/**
* Получаем ошибки
*/
$this->Viewer_AssignAjax('errors', $oUser->_getValidateErrors());
$this->Message_AddErrorSingle(null);
return;
}
}
$this->Message_AddErrorSingle($this->Lang_Get('auth.login.notices.error_login'));
}
/**
* Обрабатываем процесс залогинивания
* По факту только отображение шаблона, дальше вступает в дело Ajax
*
*/
protected function EventLogin()
{
/**
* Если уже авторизирован
*/
if ($this->User_IsAuthorization()) {
Router::Location(Router::GetPath('/'));
}
$this->Viewer_AddHtmlTitle($this->Lang_Get('auth.login.title'));
}
/**
* Обрабатываем процесс разлогинивания
*
*/
protected function EventLogout()
{
$this->Security_ValidateSendForm();
if ($this->User_GetUserCurrent()) {
$this->User_Logout();
}
Router::LocationAction('/');
}
/**
* Ajax запрос на восстановление пароля
*/
protected function EventAjaxPasswordReset()
{
/**
* Устанвливаем формат Ajax ответа
*/
$this->Viewer_SetResponseAjax('json');
/**
* Пользователь с таким емайлом существует?
*/
if ((func_check(getRequestStr('mail'), 'mail') and $oUser = $this->User_GetUserByMail(getRequestStr('mail')))) {
/**
* Формируем и отправляем ссылку на смену пароля
*/
$oReminder = Engine::GetEntity('User_Reminder');
$oReminder->setCode(func_generator(32));
$oReminder->setDateAdd(date("Y-m-d H:i:s"));
$oReminder->setDateExpire(date("Y-m-d H:i:s", time() + 60 * 60 * 24 * 7));
$oReminder->setDateUsed(null);
$oReminder->setIsUsed(0);
$oReminder->setUserId($oUser->getId());
if ($this->User_AddReminder($oReminder)) {
$this->Message_AddNotice($this->Lang_Get('auth.reset.notices.success_send_link'));
$this->User_SendNotifyReminderCode($oUser, $oReminder);
return;
}
}
$this->Message_AddError($this->Lang_Get('auth.notices.error_bad_email'), $this->Lang_Get('common.error.error'));
}
/**
* Обработка напоминания пароля, подтверждение смены пароля
*
*/
protected function EventPasswordReset()
{
if ($this->User_IsAuthorization()) {
Router::LocationAction('/');
}
$this->SetTemplateAction('reset');
/**
* Устанавливаем title страницы
*/
$this->Viewer_AddHtmlTitle($this->Lang_Get('auth.reset.title'));
/**
* Проверка кода на восстановление пароля и генерация нового пароля
*/
if (func_check($this->GetParam(0), 'md5')) {
/**
* Проверка кода подтверждения
*/
if ($oReminder = $this->User_GetReminderByCode($this->GetParam(0))) {
if (!$oReminder->getIsUsed() and strtotime($oReminder->getDateExpire()) > time() and $oUser = $this->User_GetUserById($oReminder->getUserId())) {
$sNewPassword = func_generator(7);
$oUser->setPassword($this->User_MakeHashPassword($sNewPassword));
if ($this->User_Update($oUser)) {
$oReminder->setDateUsed(date("Y-m-d H:i:s"));
$oReminder->setIsUsed(1);
$this->User_UpdateReminder($oReminder);
$this->User_SendNotifyReminderPassword($oUser, $sNewPassword);
$this->SetTemplateAction('reset_confirm');
return;
}
}
}
$this->Message_AddErrorSingle($this->Lang_Get('auth.reset.alerts.error_bad_code'),
$this->Lang_Get('common.error.error'));
return Router::Action('error');
}
}
/**
* Ajax валидация форму регистрации
*/
protected function EventAjaxValidateFields()
{
$this->ValidateFields(getRequest('fields'));
}
/**
* Ajax валидация логина
*/
protected function EventAjaxValidateLogin()
{
$this->ValidateFields(array(array('field' => 'login', 'value' => getRequest('login'))));
}
/**
* Ajax валидация емэйла
*/
protected function EventAjaxValidateEmail()
{
$this->ValidateFields(array(array('field' => 'mail', 'value' => getRequest('mail'))));
}
/**
* Ajax валидация форму регистрации
*/
protected function ValidateFields($aFields)
{
/**
* Устанавливаем формат Ajax ответа
*/
$this->Viewer_SetResponseAjax('json');
/**
* Создаем объект пользователя и устанавливаем сценарий валидации
*/
$oUser = Engine::GetEntity('ModuleUser_EntityUser');
$oUser->_setValidateScenario('registration');
/**
* Пробегаем по переданным полям/значениям и валидируем их каждое в отдельности
*/
if (is_array($aFields)) {
foreach ($aFields as $aField) {
if (isset($aField['field']) and isset($aField['value'])) {
$this->Hook_Run('registration_validate_field', array('aField' => &$aField, 'oUser' => $oUser));
$sField = $aField['field'];
$sValue = $aField['value'];
/**
* Список полей для валидации
*/
switch ($sField) {
case 'login':
$oUser->setLogin($sValue);
break;
case 'mail':
$oUser->setMail($sValue);
break;
case 'captcha':
$oUser->setCaptcha($sValue);
break;
case 'password':
$oUser->setPassword($sValue);
break;
case 'password_confirm':
$oUser->setPasswordConfirm($sValue);
$oUser->setPassword(isset($aField['params']['password']) ? $aField['params']['password'] : null);
break;
default:
continue 2;
break;
}
/**
* Валидируем поле
*/
$oUser->_Validate(array($sField), false);
}
}
}
/**
* Возникли ошибки?
*/
if ($oUser->_hasValidateErrors()) {
/**
* Получаем ошибки
*/
$this->Viewer_AssignAjax('errors', $oUser->_getValidateErrors());
}
}
/**
* Обработка Ajax регистрации
*/
protected function EventAjaxRegister()
{
/**
* Устанавливаем формат Ajax ответа
*/
$this->Viewer_SetResponseAjax('json');
/**
* Создаем объект пользователя и устанавливаем сценарий валидации
*/
$oUser = Engine::GetEntity('ModuleUser_EntityUser');
$oUser->_setValidateScenario('registration');
/**
* Заполняем поля (данные)
*/
$oUser->setLogin(getRequestStr('login'));
$oUser->setMail(getRequestStr('mail'));
$oUser->setPassword(getRequestStr('password'));
$oUser->setPasswordConfirm(getRequestStr('password_confirm'));
$oUser->setCaptcha(getRequestStr('captcha'));
$oUser->setDateRegister(date("Y-m-d H:i:s"));
$oUser->setIpRegister(func_getIp());
/**
* Если используется активация, то генерим код активации
*/
if (Config::Get('general.reg.activation')) {
$oUser->setActivate(0);
$oUser->setActivateKey(md5(func_generator() . time()));
} else {
$oUser->setActivate(1);
$oUser->setActivateKey(null);
}
$this->Hook_Run('registration_validate_before', array('oUser' => $oUser));
/**
* Запускаем валидацию
*/
if ($oUser->_Validate()) {
$this->Hook_Run('registration_validate_after', array('oUser' => $oUser));
$oUser->setPassword($this->User_MakeHashPassword($oUser->getPassword()));
if ($this->User_Add($oUser)) {
$this->Hook_Run('registration_after', array('oUser' => $oUser));
/**
* Убиваем каптчу
*/
$this->Session_Drop('captcha_keystring_user_signup');
/**
* Подписываем пользователя на дефолтные события в ленте активности
*/
$this->Stream_switchUserEventDefaultTypes($oUser->getId());
/**
* Если юзер зарегистрировался по приглашению то обновляем инвайт
*/
if ($sCode = $this->GetInviteRegister()) {
$this->Invite_UseCode($sCode, $oUser);
}
/**
* Если стоит регистрация с активацией то проводим её
*/
if (Config::Get('general.reg.activation')) {
/**
* Отправляем на мыло письмо о подтверждении регистрации
*/
$this->User_SendNotifyRegistrationActivate($oUser, getRequestStr('password'));
$this->Viewer_AssignAjax('sUrlRedirect', Router::GetPath('auth/register-confirm'));
} else {
$this->User_SendNotifyRegistration($oUser, getRequestStr('password'));
$oUser = $this->User_GetUserById($oUser->getId());
/**
* Сразу авторизуем
*/
$this->User_Authorization($oUser, false);
$this->DropInviteRegister();
/**
* Определяем URL для редиректа после авторизации
*/
$sUrl = Config::Get('module.user.redirect_after_registration');
if (getRequestStr('return-path')) {
$sUrl = getRequestStr('return-path');
}
$this->Viewer_AssignAjax('sUrlRedirect', $sUrl ? $sUrl : Router::GetPath('/'));
$this->Message_AddNoticeSingle($this->Lang_Get('auth.registration.notices.success'));
}
} else {
$this->Message_AddErrorSingle($this->Lang_Get('common.error.system.base'));
return;
}
} else {
/**
* Получаем ошибки
*/
$this->Viewer_AssignAjax('errors', $oUser->_getValidateErrors());
$this->Message_AddErrorSingle(null);
}
}
/**
* Показывает страничку регистрации
* Просто вывод шаблона
*/
protected function EventRegister()
{
if ($this->User_IsAuthorization()) {
Router::LocationAction('/');
}
}
/**
* Обработка реферального кода
*/
protected function EventReferral()
{
if ($this->User_IsAuthorization()) {
Router::LocationAction('/');
}
/**
* Смотрим наличие реферального кода и сохраняем его в сессию
*/
if ($sCode = $this->GetParam(0)) {
if ($iType = $this->Invite_GetInviteTypeByCode($sCode)) {
if (!Config::Get('general.reg.invite') or $iType != ModuleInvite::INVITE_TYPE_REFERRAL) {
$this->Session_Set('invite_code', $sCode);
}
}
}
Router::LocationAction('auth/register');
}
/**
* Обрабатывает активацию аккаунта
*/
protected function EventActivate()
{
if ($this->User_IsAuthorization()) {
Router::LocationAction('/');
}
$bError = false;
/**
* Проверяет передан ли код активации
*/
$sActivateKey = $this->GetParam(0);
if (!func_check($sActivateKey, 'md5')) {
$bError = true;
}
/**
* Проверяет верный ли код активации
*/
if (!($oUser = $this->User_GetUserByActivateKey($sActivateKey))) {
$bError = true;
}
/**
*
*/
if ($oUser and $oUser->getActivate()) {
$this->Message_AddErrorSingle($this->Lang_Get('auth.registration.notices.error_reactivate'),
$this->Lang_Get('common.error.error'));
return Router::Action('error');
}
/**
* Если что то не то
*/
if ($bError) {
$this->Message_AddErrorSingle($this->Lang_Get('auth.registration.notices.error_code'),
$this->Lang_Get('common.error.error'));
return Router::Action('error');
}
/**
* Активируем
*/
$oUser->setActivate(1);
$oUser->setDateActivate(date("Y-m-d H:i:s"));
/**
* Сохраняем юзера
*/
if ($this->User_Update($oUser)) {
$this->User_Authorization($oUser, false);
$this->DropInviteRegister();
return;
} else {
$this->Message_AddErrorSingle($this->Lang_Get('common.error.system.base'));
return Router::Action('error');
}
}
/**
* Повторный запрос активации
*/
protected function EventReactivation()
{
if ($this->User_IsAuthorization()) {
Router::LocationAction('/');
}
$this->Viewer_AddHtmlTitle($this->Lang_Get('auth.reactivation.title'));
}
/**
* Ajax повторной активации
*/
protected function EventAjaxReactivation()
{
$this->Viewer_SetResponseAjax('json');
if ((func_check(getRequestStr('mail'), 'mail') and $oUser = $this->User_GetUserByMail(getRequestStr('mail')))) {
if ($oUser->getActivate()) {
$this->Message_AddErrorSingle($this->Lang_Get('auth.registration.notices.error_reactivate'));
return;
} else {
$oUser->setActivateKey(md5(func_generator() . time()));
if ($this->User_Update($oUser)) {
$this->Message_AddNotice($this->Lang_Get('auth.reactivation.notices.success'));
$this->User_SendNotifyReactivationCode($oUser);
return;
}
}
}
$this->Message_AddErrorSingle($this->Lang_Get('auth.notices.error_bad_email'));
}
/**
* Просто выводит шаблон для подтверждения регистрации
*
*/
protected function EventRegisterConfirm()
{
$this->SetTemplateAction('confirm');
}
protected function EventInvite()
{
if ($this->User_IsAuthorization()) {
Router::LocationAction('/');
}
$this->SetTemplateAction('invite');
if (isPost()) {
/**
* Проверяем валидность кода
*/
if ($this->Invite_CheckCode(getRequestStr('invite_code'), ModuleInvite::INVITE_TYPE_CODE)) {
Router::Location($this->Invite_GetReferralLink(null, getRequestStr('invite_code')));
} else {
$this->Message_AddError($this->Lang_Get('auth.invite.alerts.error_code'), $this->Lang_Get('common.error.error'));
}
}
}
/**
* Пытается ли юзер зарегистрироваться с помощью кода приглашения
*
* @return bool
*/
protected function CheckInviteRegister()
{
if ($this->GetInviteRegister()) {
return true;
}
return false;
}
/**
* Вожвращает код приглашения из сессии
*
* @return string
*/
protected function GetInviteRegister()
{
return $this->Session_Get('invite_code');
}
/**
* Удаляет код приглашения из сессии
*/
protected function DropInviteRegister()
{
$this->Session_Drop('invite_code');
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,189 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Экшен обработки УРЛа вида /comments/
*
* @package application.actions
* @since 1.0
*/
class ActionBlogs extends Action
{
/**
* Текущий пользователь
*
* @var ModuleUser_EntityUser|null
*/
protected $oUserCurrent = null;
/**
* Инициализация
*/
public function Init()
{
/**
* Загружаем в шаблон JS текстовки
*/
$this->Lang_AddLangJs(array(
'blog.join.join',
'blog.join.leave'
));
/**
* Получаем текущего пользователя
*/
$this->oUserCurrent = $this->User_GetUserCurrent();
/**
* Устанавливаем title страницы
*/
$this->Viewer_AddHtmlTitle($this->Lang_Get('blog.menu.all_list'));
}
/**
* Регистрируем евенты
*/
protected function RegisterEvent()
{
$this->AddEventPreg('/^(page([1-9]\d{0,5}))?$/i', 'EventShowBlogs');
$this->AddEventPreg('/^ajax-search$/i', 'EventAjaxSearch');
}
/**********************************************************************************
************************ РЕАЛИЗАЦИЯ ЭКШЕНА ***************************************
**********************************************************************************
*/
/**
* Поиск блогов по названию
*/
protected function EventAjaxSearch()
{
/**
* Устанавливаем формат Ajax ответа
*/
$this->Viewer_SetResponseAjax('json');
/**
* Фильтр
*/
$aFilter = array(
'exclude_type' => 'personal',
);
$sOrderWay = in_array(getRequestStr('order'), array('desc', 'asc')) ? getRequestStr('order') : 'desc';
$sOrderField = in_array(getRequestStr('sort_by'), array(
'blog_id',
'blog_title',
'blog_count_user',
'blog_count_topic'
)) ? getRequestStr('sort_by') : 'blog_count_user';
if (is_numeric(getRequestStr('next_page')) and getRequestStr('next_page') > 0) {
$iPage = getRequestStr('next_page');
} else {
$iPage = 1;
}
/**
* Получаем из реквеста первые буквы блога
*/
if ($sTitle = getRequestStr('sText')) {
$sTitle = str_replace('%', '', $sTitle);
} else {
$sTitle = '';
}
if ($sTitle) {
$aFilter['title'] = "%{$sTitle}%";
}
/**
* Категории
*/
if (getRequestStr('category') and $oCategory = $this->Category_GetCategoryById(getRequestStr('category'))) {
/**
* Получаем ID всех блогов
* По сути это костыль, но т.к. блогов обычно не много, то норм
*/
$aBlogIds = $this->Blog_GetTargetIdsByCategory($oCategory, 1, 1000, true);
$aFilter['id'] = $aBlogIds ? $aBlogIds : array(0);
}
/**
* Тип
*/
if (in_array(getRequestStr('type'), array('open', 'close'))) {
$aFilter['type'] = getRequestStr('type');
}
/**
* Принадлежность
*/
if ($this->oUserCurrent) {
if (getRequestStr('relation') == 'my') {
$aFilter['user_owner_id'] = $this->oUserCurrent->getId();
} elseif (getRequestStr('relation') == 'join') {
$aFilter['roles'] = array(ModuleBlog::BLOG_USER_ROLE_USER, ModuleBlog::BLOG_USER_ROLE_ADMINISTRATOR, ModuleBlog::BLOG_USER_ROLE_MODERATOR);
}
}
/**
* Ищем блоги
*/
$aResult = $this->Blog_GetBlogsByFilter($aFilter, array($sOrderField => $sOrderWay), $iPage,
Config::Get('module.blog.per_page'));
$bHideMore = $iPage * Config::Get('module.blog.per_page') >= $aResult['count'];
/**
* Формируем и возвращает ответ
*/
$oViewer = $this->Viewer_GetLocalViewer();
$oViewer->Assign('blogs', $aResult['collection'], true);
$oViewer->Assign('oUserCurrent', $this->User_GetUserCurrent());
$this->Viewer_AssignAjax('html', $oViewer->Fetch("component@blog.list-loop"));
/**
* Для подгрузки
*/
$this->Viewer_AssignAjax('count_loaded', count($aResult['collection']));
$this->Viewer_AssignAjax('next_page', count($aResult['collection']) > 0 ? $iPage + 1 : $iPage);
$this->Viewer_AssignAjax('searchCount', (int)$aResult['count']);
$this->Viewer_AssignAjax('hide', $bHideMore or !$aResult['count'] or !count($aResult['collection']));
$this->Viewer_AssignAjax('textEmpty', $this->Lang_Get('search.alerts.empty'));
}
/**
* Отображение списка блогов
*/
protected function EventShowBlogs()
{
/**
* Фильтр поиска блогов
*/
$aFilter = array(
'exclude_type' => 'personal'
);
/**
* Получаем список блогов
*/
$aResult = $this->Blog_GetBlogsByFilter($aFilter, array('blog_count_user' => 'desc'), 1,
Config::Get('module.blog.per_page'));
$aBlogs = $aResult['collection'];
/**
* Загружаем переменные в шаблон
*/
$this->Viewer_Assign('blogs', $aBlogs);
$this->Viewer_Assign('searchCount', $aResult['count']);
/**
* Устанавливаем шаблон вывода
*/
$this->SetTemplateAction('index');
}
}

View file

@ -0,0 +1,108 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Экшен обработки УРЛа вида /comments/
*
* @package application.actions
* @since 1.0
*/
class ActionComments extends Action
{
/**
* Текущий юзер
*
* @var ModuleUser_EntityUser|null
*/
protected $oUserCurrent = null;
/**
* Главное меню
*
* @var string
*/
protected $sMenuHeadItemSelect = 'blog';
/**
* Инициализация
*/
public function Init()
{
$this->oUserCurrent = $this->User_GetUserCurrent();
}
/**
* Регистрация евентов
*/
protected function RegisterEvent()
{
$this->AddEventPreg('/^\d+$/i', 'EventShowComment');
}
/**********************************************************************************
************************ РЕАЛИЗАЦИЯ ЭКШЕНА ***************************************
**********************************************************************************
*/
/**
* Обрабатывает ссылку на конкретный комментарий, определят к какому топику он относится и перенаправляет на него
* Актуально при использовании постраничности комментариев
*/
protected function EventShowComment()
{
$iCommentId = $this->sCurrentEvent;
/**
* Проверяем к чему относится комментарий
*/
if (!($oComment = $this->Comment_GetCommentById($iCommentId))) {
return parent::EventNotFound();
}
if ($oComment->getTargetType() != 'topic' or !($oTopic = $oComment->getTarget())) {
return parent::EventNotFound();
}
/**
* Определяем необходимую страницу для отображения комментария
*/
if (!Config::Get('module.comment.use_nested') or !Config::Get('module.comment.nested_per_page')) {
Router::Location($oTopic->getUrl() . '#comment' . $oComment->getId());
}
$iPage = $this->Comment_GetPageCommentByTargetId($oComment->getTargetId(), $oComment->getTargetType(),
$oComment);
if ($iPage == 1) {
Router::Location($oTopic->getUrl() . '#comment' . $oComment->getId());
} else {
Router::Location($oTopic->getUrl() . "?cmtpage={$iPage}#comment" . $oComment->getId());
}
exit();
}
/**
* Выполняется при завершении работы экшена
*
*/
public function EventShutdown()
{
/**
* Загружаем в шаблон необходимые переменные
*/
$this->Viewer_Assign('sMenuHeadItemSelect', $this->sMenuHeadItemSelect);
}
}

View file

@ -0,0 +1,745 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Экшен обработки УРЛа вида /content/ - управление своими топиками
*
* @package application.actions
* @since 2.0
*/
class ActionContent extends Action
{
/**
* Главное меню
*
* @var string
*/
protected $sMenuHeadItemSelect = 'blog';
/**
* Меню
*
* @var string
*/
protected $sMenuItemSelect = 'topic';
/**
* СубМеню
*
* @var string
*/
protected $sMenuSubItemSelect = 'topic';
/**
* Текущий юзер
*
* @var ModuleUser_EntityUser|null
*/
protected $oUserCurrent = null;
/**
* Инициализация
*
*/
public function Init()
{
/**
* Проверяем авторизован ли юзер
*/
if (!$this->User_IsAuthorization()) {
return parent::EventNotFound();
}
$this->oUserCurrent = $this->User_GetUserCurrent();
/**
* Усанавливаем дефолтный евент
*/
$this->SetDefaultEvent('add');
/**
* Устанавливаем title страницы
*/
$this->Viewer_AddHtmlTitle($this->Lang_Get('topic.topics'));
}
/**
* Регистрируем евенты
*
*/
protected function RegisterEvent()
{
$this->AddEventPreg('/^add$/i', '/^[a-z_0-9]{1,50}$/i', '/^$/i', 'EventAdd');
$this->AddEventPreg('/^edit$/i', '/^\d{1,10}$/i', '/^$/i', 'EventEdit');
$this->AddEventPreg('/^delete$/i', '/^\d{1,10}$/i', '/^$/i', 'EventDelete');
$this->AddEventPreg('/^published$/i', '/^(page([1-9]\d{0,5}))?$/i', 'EventShowTopics');
$this->AddEventPreg('/^drafts$/i', '/^(page([1-9]\d{0,5}))?$/i', 'EventShowTopics');
$this->AddEventPreg('/^deferred$/i', '/^(page([1-9]\d{0,5}))?$/i', 'EventShowTopics');
$this->AddEventPreg('/^ajax$/i', '/^add$/i', '/^$/i', 'EventAjaxAdd');
$this->AddEventPreg('/^ajax$/i', '/^edit$/i', '/^$/i', 'EventAjaxEdit');
$this->AddEventPreg('/^ajax$/i', '/^preview$/i', '/^$/i', 'EventAjaxPreview');
}
/**********************************************************************************
************************ РЕАЛИЗАЦИЯ ЭКШЕНА ***************************************
**********************************************************************************
*/
/**
* Выводит список топиков
*
*/
protected function EventShowTopics()
{
/**
* Меню
*/
$this->sMenuSubItemSelect = $this->sCurrentEvent;
/**
* Передан ли номер страницы
*/
$iPage = $this->GetParamEventMatch(0, 2) ? $this->GetParamEventMatch(0, 2) : 1;
/**
* Получаем список топиков
*/
if ($this->sCurrentEvent == 'deferred') {
$aResult = $this->Topic_GetTopicsPersonalDeferredByUser($this->oUserCurrent->getId(), $iPage, Config::Get('module.topic.per_page'));
$this->SetTemplateAction('drafts');
} else {
$aResult = $this->Topic_GetTopicsPersonalByUser($this->oUserCurrent->getId(),
$this->sCurrentEvent == 'published' ? 1 : 0, $iPage, Config::Get('module.topic.per_page'));
}
$aTopics = $aResult['collection'];
/**
* Формируем постраничность
*/
$aPaging = $this->Viewer_MakePaging($aResult['count'], $iPage, Config::Get('module.topic.per_page'),
Config::Get('pagination.pages.count'), Router::GetPath('content') . $this->sCurrentEvent);
/**
* Загружаем переменные в шаблон
*/
$this->Viewer_Assign('paging', $aPaging);
$this->Viewer_Assign('topics', $aTopics);
$this->Viewer_AddHtmlTitle($this->Lang_Get('topic.nav.' . $this->sCurrentEvent));
}
protected function EventDelete()
{
$this->Security_ValidateSendForm();
/**
* Получаем номер топика из УРЛ и проверяем существует ли он
*/
$sTopicId = $this->GetParam(0);
if (!($oTopic = $this->Topic_GetTopicById($sTopicId))) {
return parent::EventNotFound();
}
/**
* проверяем есть ли право на удаление топика
*/
if (!$this->ACL_IsAllowDeleteTopic($oTopic, $this->oUserCurrent)) {
$this->Message_AddErrorSingle($this->Rbac_GetMsgLast());
return Router::Action('error');
}
/**
* Удаляем топик
*/
$this->Hook_Run('topic_delete_before', array('oTopic' => $oTopic));
$this->Topic_DeleteTopic($oTopic);
$this->Hook_Run('topic_delete_after', array('oTopic' => $oTopic));
/**
* Перенаправляем на страницу со списком топиков из блога этого топика
*/
Router::Location($oTopic->getBlog()->getUrlFull());
}
protected function EventEdit()
{
/**
* Получаем номер топика из УРЛ и проверяем существует ли он
*/
$sTopicId = $this->GetParam(0);
if (!($oTopic = $this->Topic_GetTopicById($sTopicId))) {
return parent::EventNotFound();
}
/**
* Проверяем тип топика
*/
if (!$oTopicType = $this->Topic_GetTopicType($oTopic->getType())) {
return parent::EventNotFound();
}
/**
* Если права на редактирование
*/
if (!$this->ACL_IsAllowEditTopic($oTopic, $this->oUserCurrent)) {
return parent::EventNotFound();
}
/**
* Получаем доступные блоги по типам
*/
$aBlogs = array();
$aBlogs['open'] = $this->Blog_GetBlogsByType('open');
/**
* Убираем из списка блоги в которые не доступен постинг
*/
$aBlogsCurrent = $oTopic->getBlogIds();
foreach ($aBlogs['open'] as $k => $oBlogOpen) {
if (!$this->ACL_IsAllowBlog($oBlogOpen, $this->oUserCurrent) and !in_array($oBlogOpen->getId(), $aBlogsCurrent)) {
unset($aBlogs['open'][$k]);
}
}
if ($this->oUserCurrent->isAdministrator()) {
$aBlogs['close'] = $this->Blog_GetBlogsByType('close');
} else {
$aBlogs['close'] = $this->Blog_GetBlogsByTypeAndUserId('close', $this->oUserCurrent->getId());
}
/**
* Вызов хуков
*/
$this->Hook_Run('topic_edit_show', array('oTopic' => $oTopic, 'aBlogs' => &$aBlogs));
/**
* Дополнительно загружам превью
*/
$aFilter = array(
'target_type' => 'topic',
'is_preview' => 1,
'target_id' => $sTopicId
);
$aTargetItems = $this->Media_GetTargetItemsByFilter($aFilter);
$this->Viewer_Assign('imagePreviewItems', $aTargetItems);
/**
* Проверяем на отсутствие блогов
*/
$bSkipBlogs = true;
foreach ($aBlogs as $aBlogsType) {
if ($aBlogsType) {
$bSkipBlogs = false;
}
}
/**
* Загружаем переменные в шаблон
*/
$this->Viewer_Assign('blogsAllow', $aBlogs);
$this->Viewer_Assign('skipBlogs', $bSkipBlogs);
$this->Viewer_Assign('topicType', $oTopicType);
$this->Viewer_AddHtmlTitle($this->Lang_Get('topic.add.title.edit'));
$this->Viewer_Assign('topicEdit', $oTopic);
$this->SetTemplateAction('add');
}
/**
* Добавление топика
*
*/
protected function EventAdd()
{
$sTopicType = $this->GetParam(0);
$iBlogId = (int)getRequest('blog_id');
if (!$oTopicType = $this->Topic_GetTopicType($sTopicType)) {
return parent::EventNotFound();
}
/**
* Проверяем права на создание топика
*/
if (!$this->ACL_CanAddTopic($this->oUserCurrent, $oTopicType)) {
$this->Message_AddErrorSingle($this->Rbac_GetMsgLast());
return Router::Action('error');
}
$this->sMenuSubItemSelect = $sTopicType;
/**
* Получаем доступные блоги по типам
*/
$aBlogs = array();
$aBlogs['open'] = $this->Blog_GetBlogsByType('open');
/**
* Убираем из списка блоги в которые не доступен постинг
*/
foreach ($aBlogs['open'] as $k => $oBlogOpen) {
if (!$this->ACL_IsAllowBlog($oBlogOpen, $this->oUserCurrent)) {
unset($aBlogs['open'][$k]);
}
}
if ($this->oUserCurrent->isAdministrator()) {
$aBlogs['close'] = $this->Blog_GetBlogsByType('close');
} else {
$aBlogs['close'] = $this->Blog_GetBlogsByTypeAndUserId('close', $this->oUserCurrent->getId());
}
/**
* Вызов хуков
*/
$this->Hook_Run('topic_add_show', array('aBlogs' => &$aBlogs));
/**
* Проверяем на отсутствие блогов
*/
$bSkipBlogs = true;
foreach ($aBlogs as $aBlogsType) {
if ($aBlogsType) {
$bSkipBlogs = false;
}
}
/**
* Загружаем переменные в шаблон
*/
$this->Viewer_Assign('topicType', $oTopicType);
$this->Viewer_Assign('blogsAllow', $aBlogs);
$this->Viewer_Assign('skipBlogs', $bSkipBlogs);
$this->Viewer_Assign('blogId', $iBlogId);
$this->Viewer_AddHtmlTitle($this->Lang_Get('topic.add.title.add'));
$this->SetTemplateAction('add');
}
protected function EventAjaxEdit()
{
$this->Viewer_SetResponseAjax();
$aTopicRequest = getRequest('topic');
if (!(isset($aTopicRequest['id']) and $oTopic = $this->Topic_GetTopicById($aTopicRequest['id']))) {
return $this->EventErrorDebug();
}
if (!$this->Topic_IsAllowTopicType($oTopic->getType())) {
return $this->EventErrorDebug();
}
/**
* Проверяем разрешено ли постить топик по времени
*/
if (!isPost('is_draft') and !$oTopic->getPublishDraft() and !$this->ACL_CanPostTopicTime($this->oUserCurrent)) {
$this->Message_AddErrorSingle($this->Lang_Get('topic.add.notices.time_limit'), $this->Lang_Get('common.error.error'));
return;
}
/**
* Если права на редактирование
*/
if (!$this->ACL_IsAllowEditTopic($oTopic, $this->oUserCurrent)) {
return $this->EventErrorDebug();
}
/**
* Сохраняем старое значение идентификатора основного блога и всех блогов
*/
$sBlogIdOld = $oTopic->getBlogId();
$aBlogsIdOld = $oTopic->getBlogsId();
$oTopic->_setDataSafe(getRequest('topic'));
$oTopic->setProperties(getRequest('property'));
$oTopic->setUserCreator($this->oUserCurrent);
$oTopic->setUserIp(func_getIp());
if (!$oTopic->getTags() or !$oTopic->getTypeObject()->getParam('allow_tags')) {
$oTopic->setTags('');
}
/**
* Принудительный вывод на главную
*/
if ($this->ACL_IsAllowTopicPublishIndex($this->oUserCurrent)) {
if (isset($_REQUEST['topic']['topic_publish_index'])) {
$oTopic->setPublishIndex(1);
} else {
$oTopic->setPublishIndex(0);
}
}
/**
* Принудительный запрет вывода на главную
*/
if ($this->ACL_IsAllowTopicSkipIndex($this->oUserCurrent)) {
if (isset($_REQUEST['topic']['topic_skip_index'])) {
$oTopic->setSkipIndex(1);
} else {
$oTopic->setSkipIndex(0);
}
}
/**
* Запрет на комментарии к топику
*/
$oTopic->setForbidComment(0);
if (isset($_REQUEST['topic']['topic_forbid_comment'])) {
$oTopic->setForbidComment(1);
}
/**
* Дата редактирования контента
*/
$oTopic->setDateEditContent(date('Y-m-d H:i:s'));
$this->Hook_Run('topic_edit_validate_before', array('oTopic' => $oTopic));
if ($oTopic->_Validate()) {
/**
* Публикуем или сохраняем в черновиках
*/
$bSendNotify = false;
if (!isset($_REQUEST['is_draft'])) {
$oTopic->setPublish(1);
if ($oTopic->getPublishDraft() == 0) {
$oTopic->setPublishDraft(1);
$oTopic->setDatePublish(date("Y-m-d H:i:s"));
$bSendNotify = true;
}
} else {
$oTopic->setPublish(0);
}
/**
* Отложенная публикация
*/
if ($oTopic->getPublishDateRaw()) {
$oTopic->setDatePublish(date("Y-m-d H:i:s", $oTopic->getPublishDateRaw()));
$bSendNotify = false;
} else {
/**
* Снятие даты публикации, только при условии, что была установлена дата в будущем
*/
if ($oTopic->getDatePublish() and strtotime($oTopic->getDatePublish()) > time()) {
$oTopic->setDatePublish(date("Y-m-d H:i:s"));
/**
* Если сохраняем отложенный в черновик, то считаем, что он еще ниразу не публиковался
*/
if (isset($_REQUEST['is_draft'])) {
$oTopic->setPublishDraft(0);
}
}
}
$oBlog = $oTopic->getBlog();
/**
* Получаемый и устанавливаем разрезанный текст по тегу <cut>
*/
if ($oTopic->getTypeObject()->getParam('allow_text')) {
list($sTextShort, $sTextNew, $sTextCut) = $this->Text_Cut($oTopic->getTextSource());
$oTopic->setCutText($sTextCut);
// TODO: передача параметров в Topic_Parser пока не используется - нужно заменить на этот вызов все места с парсингом топика
$oTopic->setText($this->Topic_Parser($sTextNew, $oTopic));
if ($sTextShort != $sTextNew) {
$oTopic->setTextShort($this->Topic_Parser($sTextShort, $oTopic));
} else {
$oTopic->setTextShort('');
}
} else {
$oTopic->setCutText('');
$oTopic->setText('');
$oTopic->setTextShort('');
$oTopic->setTextSource('');
}
$this->Hook_Run('topic_edit_before', array('oTopic' => $oTopic, 'oBlog' => $oBlog));
/**
* Сохраняем топик
*/
if ($this->Topic_UpdateTopic($oTopic)) {
$this->Hook_Run('topic_edit_after',
array('oTopic' => $oTopic, 'oBlog' => $oBlog, 'bSendNotify' => &$bSendNotify));
/**
* Обновляем данные в комментариях, если топик был перенесен в новый блог
*/
if ($sBlogIdOld != $oTopic->getBlogId()) {
$this->Comment_UpdateTargetParentByTargetId($oTopic->getBlogId(), 'topic', $oTopic->getId());
$this->Comment_UpdateTargetParentByTargetIdOnline($oTopic->getBlogId(), 'topic', $oTopic->getId());
}
/**
* Обновляем количество топиков в блоге
*/
if ($aBlogsIdOld != $oTopic->getBlogsId()) {
$this->Blog_RecalculateCountTopicByBlogId($aBlogsIdOld);
}
$this->Blog_RecalculateCountTopicByBlogId($oTopic->getBlogsId());
/**
* Добавляем событие в ленту
*/
$this->Stream_write($oTopic->getUserId(), 'add_topic', $oTopic->getId(),
$oTopic->getPublish() && $oBlog->getType() != 'close', $oTopic->getDatePublish());
/**
* Рассылаем о новом топике подписчикам блога
*/
if ($bSendNotify) {
$this->Topic_SendNotifyTopicNew($oTopic, $oTopic->getUser());
}
if (!$oTopic->getPublish() and !$this->oUserCurrent->isAdministrator() and $this->oUserCurrent->getId() != $oTopic->getUserId()) {
$sUrlRedirect = $oBlog->getUrlFull();
} else {
$sUrlRedirect = $oTopic->getUrl();
}
$this->Viewer_AssignAjax('sUrlRedirect', $sUrlRedirect);
$this->Message_AddNotice($this->Lang_Get('topic.add.notices.update_complete'), $this->Lang_Get('common.attention'));
} else {
$this->Message_AddErrorSingle($this->Lang_Get('common.error.system.base'));
}
} else {
$this->Message_AddError($oTopic->_getValidateError(), $this->Lang_Get('common.error.error'));
}
}
protected function EventAjaxAdd()
{
$this->Viewer_SetResponseAjax();
/**
* Проверяем тип топика
*/
$sTopicType = getRequestStr('topic_type');
if (!$oTopicType = $this->Topic_GetTopicType($sTopicType)) {
return $this->EventErrorDebug();
}
/**
* Проверяем права на создание топика
*/
if (!$this->ACL_CanAddTopic($this->oUserCurrent, $oTopicType)) {
$this->Message_AddErrorSingle($this->Rbac_GetMsgLast());
return false;
}
/**
* Создаем топик
*/
$oTopic = Engine::GetEntity('Topic');
$oTopic->_setDataSafe(getRequest('topic'));
$oTopic->setProperties(getRequest('property'));
$oTopic->setUserCreator($this->oUserCurrent);
$oTopic->setUserId($this->oUserCurrent->getId());
$oTopic->setDateAdd(date("Y-m-d H:i:s"));
$oTopic->setUserIp(func_getIp());
$oTopic->setTopicType($sTopicType);
if (!$oTopic->getTags() or !$oTopic->getTypeObject()->getParam('allow_tags')) {
$oTopic->setTags('');
}
/**
* Публикуем или сохраняем
*/
if (!isset($_REQUEST['is_draft'])) {
$oTopic->setPublish(1);
$oTopic->setPublishDraft(1);
} else {
$oTopic->setPublish(0);
$oTopic->setPublishDraft(0);
}
/**
* Принудительный вывод на главную
*/
$oTopic->setPublishIndex(0);
if ($this->ACL_IsAllowTopicPublishIndex($this->oUserCurrent)) {
if (isset($_REQUEST['topic']['topic_publish_index'])) {
$oTopic->setPublishIndex(1);
}
}
/**
* Принудительный запрет вывода на главную
*/
$oTopic->setSkipIndex(0);
if ($this->ACL_IsAllowTopicSkipIndex($this->oUserCurrent)) {
if (isset($_REQUEST['topic']['topic_skip_index'])) {
$oTopic->setSkipIndex(1);
}
}
/**
* Запрет на комментарии к топику
*/
$oTopic->setForbidComment(0);
if (isset($_REQUEST['topic']['topic_forbid_comment'])) {
$oTopic->setForbidComment(1);
}
$this->Hook_Run('topic_add_validate_before', array('oTopic' => $oTopic));
if ($oTopic->_Validate()) {
if ($oTopic->getPublishDateRaw()) {
$oTopic->setDatePublish(date("Y-m-d H:i:s", $oTopic->getPublishDateRaw()));
}
$oBlog = $oTopic->getBlog();
/**
* Получаем и устанавливаем разрезанный текст по тегу <cut>
*/
if ($oTopic->getTypeObject()->getParam('allow_text')) {
list($sTextShort, $sTextNew, $sTextCut) = $this->Text_Cut($oTopic->getTextSource());
$oTopic->setCutText($sTextCut);
$oTopic->setText($this->Topic_Parser($sTextNew, $oTopic));
if ($sTextShort != $sTextNew) {
$oTopic->setTextShort($this->Topic_Parser($sTextShort, $oTopic));
} else {
$oTopic->setTextShort('');
}
} else {
$oTopic->setCutText('');
$oTopic->setText('');
$oTopic->setTextShort('');
$oTopic->setTextSource('');
}
$this->Hook_Run('topic_add_before', array('oTopic' => $oTopic, 'oBlog' => $oBlog));
if ($this->Topic_AddTopic($oTopic)) {
$this->Hook_Run('topic_add_after', array('oTopic' => $oTopic, 'oBlog' => $oBlog));
/**
* Получаем топик, чтоб подцепить связанные данные
*/
$oTopic = $this->Topic_GetTopicById($oTopic->getId());
/**
* Обновляем количество топиков в блогах
*/
$this->Blog_RecalculateCountTopicByBlogId($oTopic->getBlogsId());
/**
* Фиксируем ID у media файлов топика
*/
$this->Media_ReplaceTargetTmpById('topic', $oTopic->getId());
/**
* Фиксируем ID у опросов
*/
if ($oTopicType->getParam('allow_poll')) {
$this->Poll_ReplaceTargetTmpById('topic', $oTopic->getId());
}
/**
* Добавляем автора топика в подписчики на новые комментарии к этому топику
*/
$oUser = $oTopic->getUser();
if ($oUser) {
$this->Subscribe_AddSubscribeSimple('topic_new_comment', $oTopic->getId(), $oUser->getMail(),
$oUser->getId());
}
/**
* Делаем рассылку спама всем, кто состоит в этом блоге
*/
if ($oTopic->getPublish() == 1 and $oBlog->getType() != 'personal' and strtotime($oTopic->getDatePublish()) <= time()) {
$this->Topic_SendNotifyTopicNew($oTopic, $oUser);
}
/**
* Добавляем событие в ленту
*/
$this->Stream_write($oTopic->getUserId(), 'add_topic', $oTopic->getId(),
$oTopic->getPublish() && $oBlog->getType() != 'close', $oTopic->getDatePublish());
$this->Viewer_AssignAjax('sUrlRedirect', $oTopic->getUrl());
$this->Message_AddNotice($this->Lang_Get('topic.add.notices.create_complete'), $this->Lang_Get('common.attention'));
} else {
$this->Message_AddError($this->Lang_Get('common.error.error'));
}
} else {
$this->Message_AddError($oTopic->_getValidateError(), $this->Lang_Get('common.error.error'));
}
}
public function EventAjaxPreview()
{
$this->Viewer_SetResponseAjax('json');
/**
* Пользователь авторизован?
*/
if (!$this->oUserCurrent) {
$this->Message_AddErrorSingle($this->Lang_Get('common.error.need_authorization'), $this->Lang_Get('common.error.error'));
return;
}
/**
* Допустимый тип топика?
*/
if (!$this->Topic_IsAllowTopicType($sType = getRequestStr('topic_type'))) {
$this->Message_AddErrorSingle($this->Lang_Get('topic.add.notices.error_type'), $this->Lang_Get('common.error.error'));
return;
}
$aTopicRequest = getRequest('topic');
/**
* Проверка на ID при редактировании топика
*/
$iId = isset($aTopicRequest['id']) ? (int)$aTopicRequest['id'] : null;
if ($iId and !($oTopicOriginal = $this->Topic_GetTopicById($iId))) {
return $this->EventErrorDebug();
}
/**
* Если права на редактирование
*/
if ($iId and !$this->ACL_IsAllowEditTopic($oTopicOriginal, $this->oUserCurrent)) {
return parent::EventNotFound();
}
/**
* Создаем объект топика для валидации данных
*/
$oTopic = Engine::GetEntity('ModuleTopic_EntityTopic');
$oTopic->setTitle(isset($aTopicRequest['topic_title']) ? strip_tags($aTopicRequest['topic_title']) : '');
$oTopic->setTextSource(isset($aTopicRequest['topic_text_source']) ? $aTopicRequest['topic_text_source'] : '');
$oTopic->setTags(isset($aTopicRequest['topic_tags']) ? $aTopicRequest['topic_tags'] : '');
$oTopic->setDateAdd(date("Y-m-d H:i:s"));
$oTopic->setDatePublish(date("Y-m-d H:i:s"));
$oTopic->setUserId($this->oUserCurrent->getId());
$oTopic->setType($sType);
$oTopic->setPublish(1);
$oTopic->setProperties(getRequest('property'));
/**
* Перед валидацией аттачим существующие свойста
*/
if ($iId) {
$oTopic->setId($iId);
$a = $oTopic->getPropertyList();
}
/**
* Валидируем необходимые поля топика
*/
$oTopic->_Validate(array('topic_title', 'topic_text', 'topic_tags', 'topic_type', 'properties'), false);
if ($oTopic->_hasValidateErrors()) {
$this->Message_AddErrorSingle($oTopic->_getValidateError());
return false;
}
/**
* Аттачим опросы
*/
if (!$oTopic->getId()) {
$aPolls = array();
if ($sPollTargetTmp = $this->Session_GetCookie('poll_target_tmp_topic')) {
$aPolls = $this->Poll_GetPollItemsByFilter(array(
'target_type' => 'topic',
'target_tmp' => $sPollTargetTmp,
'#order' => array('id' => 'asc')
));
}
$oTopic->setPolls($aPolls);
}
/**
* Аттачим дополнительные поля к топику
*/
$this->Property_AttachPropertiesForTarget($oTopic, $oTopic->getPropertiesObject());
/**
* Формируем текст топика
*/
list($sTextShort, $sTextNew, $sTextCut) = $this->Text_Cut($oTopic->getTextSource());
$oTopic->setCutText($sTextCut);
$oTopic->setText($this->Topic_Parser($sTextNew, $oTopic));
$oTopic->setTextShort($this->Topic_Parser($sTextShort, $oTopic));
/**
* Рендерим шаблон для предпросмотра топика
*/
$oViewer = $this->Viewer_GetLocalViewer();
$aParams = array(
'isPreview' => true,
'topic' => $oTopic,
);
foreach ($aParams as $sName => $mValue) {
$oViewer->Assign($sName, $mValue, true);
}
$oViewer->Assign('params', $aParams); // fix для корректной работы подключения внутренних шаблонов компонента
$sTemplate = 'component@topic.type';
$sTextResult = $oViewer->Fetch($sTemplate);
/**
* Передаем результат в ajax ответ
*/
$this->Viewer_AssignAjax('sText', $sTextResult);
return true;
}
/**
* При завершении экшена загружаем необходимые переменные
*
*/
public function EventShutdown()
{
$this->Viewer_Assign('sMenuHeadItemSelect', $this->sMenuHeadItemSelect);
$this->Viewer_Assign('sMenuItemSelect', $this->sMenuItemSelect);
$this->Viewer_Assign('sMenuSubItemSelect', $this->sMenuSubItemSelect);
}
}

View file

@ -0,0 +1,43 @@
<?php
/**
* Статическая страница доната
*
* @package application.actions
* @since 1.0
*/
class ActionDonate extends Action
{
/**
* Инициализация экшена
*
*/
public function Init()
{
/**
* Устанавливаем дефолтный евент
*/
$this->SetDefaultEvent('index');
}
/**
* Регистрируем евенты
*
*/
protected function RegisterEvent()
{
$this->AddEvent('index', 'EventIndex');
}
/**
* Вывод правил
*
*/
protected function EventIndex()
{
/**
* Устанавливаем title страницы
*/
$this->Viewer_AddHtmlTitle('Поддержать IFHub');
$this->SetTemplateAction('index');
}
}

View file

@ -0,0 +1,103 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Экшен обработки УРЛа вида /error/ т.е. ошибок
*
* @package application.actions
* @since 1.0
*/
class ActionError extends Action
{
/**
* Список специфических HTTP ошибок для которых необходимо отдавать header
*
* @var array
*/
protected $aHttpErrors = array(
'404' => array(
'header' => '404 Not Found',
),
'403' => array(
'header' => '403 Forbidden',
),
'500' => array(
'header' => '500 Internal Server Error',
),
);
/**
* Инициализация экшена
*
*/
public function Init()
{
/**
* Устанавливаем дефолтный евент
*/
$this->SetDefaultEvent('index');
/**
* Запрешаем отображать статистику выполнения
*/
Router::SetIsShowStats(false);
}
/**
* Регистрируем евенты
*
*/
protected function RegisterEvent()
{
$this->AddEvent('index', 'EventError');
$this->AddEventPreg('/^\d{3}$/i', 'EventError');
}
/**
* Вывод ошибки
*
*/
protected function EventError()
{
/**
* Если евент равен одной из ошибок из $aHttpErrors, то шлем браузеру специфичный header
* Например, для 404 в хидере будет послан браузеру заголовок HTTP/1.1 404 Not Found
*/
if (array_key_exists($this->sCurrentEvent, $this->aHttpErrors)) {
/**
* Смотрим есть ли сообщения об ошибках
*/
if (!$this->Message_GetError()) {
$this->Message_AddErrorSingle($this->Lang_Get('common.error.system.code.' . $this->sCurrentEvent),
$this->sCurrentEvent);
}
$aHttpError = $this->aHttpErrors[$this->sCurrentEvent];
if (isset($aHttpError['header'])) {
$sProtocol = isset($_SERVER['SERVER_PROTOCOL']) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.1';
header("{$sProtocol} {$aHttpError['header']}");
}
}
/**
* Устанавливаем title страницы
*/
$this->Viewer_AddHtmlTitle($this->Lang_Get('common.error.error'));
$this->SetTemplateAction('index');
}
}

View file

@ -0,0 +1,372 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Обработка главной страницы, т.е. УРЛа вида /index/
*
* @package application.actions
* @since 1.0
*/
class ActionIndex extends Action
{
/**
* Главное меню
*
* @var string
*/
protected $sMenuHeadItemSelect = 'blog';
/**
* Меню
*
* @var string
*/
protected $sMenuItemSelect = 'index';
/**
* Субменю
*
* @var string
*/
protected $sMenuSubItemSelect = 'good';
/**
* Число новых топиков
*
* @var int
*/
protected $iCountTopicsNew = 0;
/**
* Число новых топиков в коллективных блогах
*
* @var int
*/
protected $iCountTopicsCollectiveNew = 0;
/**
* Число новых топиков в персональных блогах
*
* @var int
*/
protected $iCountTopicsPersonalNew = 0;
/**
* URL-префикс для навигации по топикам
*
* @var string
*/
protected $sNavTopicsSubUrl = '';
/**
* Инициализация
*
*/
public function Init()
{
/**
* Подсчитываем новые топики
*/
$this->iCountTopicsCollectiveNew = $this->Topic_GetCountTopicsCollectiveNew();
$this->iCountTopicsPersonalNew = $this->Topic_GetCountTopicsPersonalNew();
$this->iCountTopicsNew = $this->iCountTopicsCollectiveNew + $this->iCountTopicsPersonalNew;
$this->sNavTopicsSubUrl = Router::GetPath('index');
}
/**
* Регистрация евентов
*
*/
protected function RegisterEvent()
{
$this->AddEventPreg('/^(page([1-9]\d{0,5}))?$/i', 'EventIndex');
$this->AddEventPreg('/^new$/i', '/^(page([1-9]\d{0,5}))?$/i', 'EventNew');
$this->AddEventPreg('/^newall$/i', '/^(page([1-9]\d{0,5}))?$/i', 'EventNewAll');
$this->AddEventPreg('/^discussed$/i', '/^(page([1-9]\d{0,5}))?$/i', 'EventDiscussed');
$this->AddEventPreg('/^top$/i', '/^(page([1-9]\d{0,5}))?$/i', 'EventTop');
}
/**********************************************************************************
************************ РЕАЛИЗАЦИЯ ЭКШЕНА ***************************************
**********************************************************************************
*/
/**
* Вывод рейтинговых топиков
*/
protected function EventTop()
{
$sPeriod = Config::Get('module.topic.default_period_top');
if (in_array(getRequestStr('period'), array(1, 7, 30, 'all'))) {
$sPeriod = getRequestStr('period');
}
if (!$sPeriod) {
$sPeriod = 1;
}
/**
* Меню
*/
$this->sMenuSubItemSelect = 'top';
/**
* Передан ли номер страницы
*/
$iPage = $this->GetParamEventMatch(0, 2) ? $this->GetParamEventMatch(0, 2) : 1;
if ($iPage == 1 and !getRequest('period')) {
$this->Viewer_SetHtmlCanonical(Router::GetPath('index') . 'top/');
}
/**
* Получаем список топиков
*/
$aResult = $this->Topic_GetTopicsTop($iPage, Config::Get('module.topic.per_page'),
$sPeriod == 'all' ? null : $sPeriod * 60 * 60 * 24);
/**
* Если нет топиков за 1 день, то показываем за неделю (7)
*/
if (!$aResult['count'] and $iPage == 1 and !getRequest('period')) {
$sPeriod = 7;
$aResult = $this->Topic_GetTopicsTop($iPage, Config::Get('module.topic.per_page'),
$sPeriod == 'all' ? null : $sPeriod * 60 * 60 * 24);
}
$aTopics = $aResult['collection'];
/**
* Вызов хуков
*/
$this->Hook_Run('topics_list_show', array('aTopics' => &$aTopics));
/**
* Формируем постраничность
*/
$aPaging = $this->Viewer_MakePaging($aResult['count'], $iPage, Config::Get('module.topic.per_page'),
Config::Get('pagination.pages.count'), Router::GetPath('index') . 'top', array('period' => $sPeriod));
/**
* Загружаем переменные в шаблон
*/
$this->Viewer_Assign('topics', $aTopics);
$this->Viewer_Assign('paging', $aPaging);
$this->Viewer_Assign('periodSelectCurrent', $sPeriod);
$this->Viewer_Assign('periodSelectCurrentTitle', $this->Lang_Get('blog.menu.top_period_' . $sPeriod));
$this->Viewer_Assign('periodSelectRoot', Router::GetPath('index') . 'top/');
/**
* Устанавливаем шаблон вывода
*/
$this->SetTemplateAction('index');
$this->Viewer_AddHtmlTitle($this->Lang_Get('blog.menu.all_top'));
$this->Viewer_AddHtmlTitle($this->Lang_Get('blog.menu.top_period_' . $sPeriod));
}
/**
* Вывод обсуждаемых топиков
*/
protected function EventDiscussed()
{
$sPeriod = Config::Get('module.topic.default_period_discussed');
if (in_array(getRequestStr('period'), array(1, 7, 30, 'all'))) {
$sPeriod = getRequestStr('period');
}
if (!$sPeriod) {
$sPeriod = 1;
}
/**
* Меню
*/
$this->sMenuSubItemSelect = 'discussed';
/**
* Передан ли номер страницы
*/
$iPage = $this->GetParamEventMatch(0, 2) ? $this->GetParamEventMatch(0, 2) : 1;
if ($iPage == 1 and !getRequest('period')) {
$this->Viewer_SetHtmlCanonical(Router::GetPath('index') . 'discussed/');
}
/**
* Получаем список топиков
*/
$aResult = $this->Topic_GetTopicsDiscussed($iPage, Config::Get('module.topic.per_page'),
$sPeriod == 'all' ? null : $sPeriod * 60 * 60 * 24);
/**
* Если нет топиков за 1 день, то показываем за неделю (7)
*/
if (!$aResult['count'] and $iPage == 1 and !getRequest('period')) {
$sPeriod = 7;
$aResult = $this->Topic_GetTopicsDiscussed($iPage, Config::Get('module.topic.per_page'),
$sPeriod == 'all' ? null : $sPeriod * 60 * 60 * 24);
}
$aTopics = $aResult['collection'];
/**
* Вызов хуков
*/
$this->Hook_Run('topics_list_show', array('aTopics' => &$aTopics));
/**
* Формируем постраничность
*/
$aPaging = $this->Viewer_MakePaging($aResult['count'], $iPage, Config::Get('module.topic.per_page'),
Config::Get('pagination.pages.count'), Router::GetPath('index') . 'discussed', array('period' => $sPeriod));
/**
* Загружаем переменные в шаблон
*/
$this->Viewer_Assign('topics', $aTopics);
$this->Viewer_Assign('paging', $aPaging);
$this->Viewer_Assign('periodSelectCurrent', $sPeriod);
$this->Viewer_Assign('periodSelectCurrentTitle', $this->Lang_Get('blog.menu.top_period_' . $sPeriod));
$this->Viewer_Assign('periodSelectRoot', Router::GetPath('index') . 'discussed/');
/**
* Устанавливаем шаблон вывода
*/
$this->SetTemplateAction('index');
$this->Viewer_AddHtmlTitle($this->Lang_Get('blog.menu.all_discussed'));
$this->Viewer_AddHtmlTitle($this->Lang_Get('blog.menu.top_period_' . $sPeriod));
}
/**
* Вывод новых топиков
*/
protected function EventNew()
{
$this->Viewer_SetHtmlRssAlternate(Router::GetPath('rss') . 'new/', Config::Get('view.name'));
/**
* Меню
*/
$this->sMenuSubItemSelect = 'new';
/**
* Передан ли номер страницы
*/
$iPage = $this->GetParamEventMatch(0, 2) ? $this->GetParamEventMatch(0, 2) : 1;
/**
* Получаем список топиков
*/
$aResult = $this->Topic_GetTopicsNew($iPage, Config::Get('module.topic.per_page'));
$aTopics = $aResult['collection'];
/**
* Вызов хуков
*/
$this->Hook_Run('topics_list_show', array('aTopics' => &$aTopics));
/**
* Формируем постраничность
*/
$aPaging = $this->Viewer_MakePaging($aResult['count'], $iPage, Config::Get('module.topic.per_page'),
Config::Get('pagination.pages.count'), Router::GetPath('index') . 'new');
/**
* Загружаем переменные в шаблон
*/
$this->Viewer_Assign('topics', $aTopics);
$this->Viewer_Assign('paging', $aPaging);
/**
* Устанавливаем шаблон вывода
*/
$this->SetTemplateAction('index');
$this->Viewer_AddHtmlTitle($this->Lang_Get('blog.menu.all_new'));
}
/**
* Вывод ВСЕХ новых топиков
*/
protected function EventNewAll()
{
$this->Viewer_AddHtmlTitle($this->Lang_Get('blog.menu.all'));
$this->Viewer_SetHtmlRssAlternate(Router::GetPath('rss') . 'new/', Config::Get('view.name'));
/**
* Меню
*/
$this->sMenuSubItemSelect = 'new';
/**
* Передан ли номер страницы
*/
$iPage = $this->GetParamEventMatch(0, 2) ? $this->GetParamEventMatch(0, 2) : 1;
/**
* Получаем список топиков
*/
$aResult = $this->Topic_GetTopicsNewAll($iPage, Config::Get('module.topic.per_page'));
$aTopics = $aResult['collection'];
/**
* Вызов хуков
*/
$this->Hook_Run('topics_list_show', array('aTopics' => &$aTopics));
/**
* Формируем постраничность
*/
$aPaging = $this->Viewer_MakePaging($aResult['count'], $iPage, Config::Get('module.topic.per_page'),
Config::Get('pagination.pages.count'), Router::GetPath('index') . 'newall');
/**
* Загружаем переменные в шаблон
*/
$this->Viewer_Assign('topics', $aTopics);
$this->Viewer_Assign('paging', $aPaging);
/**
* Устанавливаем шаблон вывода
*/
$this->SetTemplateAction('index');
}
/**
* Вывод интересных на главную
*
*/
protected function EventIndex()
{
$this->Viewer_SetHtmlRssAlternate(Router::GetPath('rss') . 'index/', Config::Get('view.name'));
/**
* Меню
*/
$this->sMenuSubItemSelect = 'good';
/**
* Передан ли номер страницы
*/
$iPage = $this->GetEventMatch(2) ? $this->GetEventMatch(2) : 1;
/**
* Устанавливаем основной URL для поисковиков
*/
if ($iPage == 1) {
$this->Viewer_SetHtmlCanonical(Router::GetPath('/'));
}
/**
* Получаем список топиков
*/
$aResult = $this->Topic_GetTopicsGood($iPage, Config::Get('module.topic.per_page'));
$aTopics = $aResult['collection'];
/**
* Вызов хуков
*/
$this->Hook_Run('topics_list_show', array('aTopics' => &$aTopics));
/**
* Формируем постраничность
*/
$aPaging = $this->Viewer_MakePaging($aResult['count'], $iPage, Config::Get('module.topic.per_page'),
Config::Get('pagination.pages.count'), Router::GetPath('index'));
/**
* Загружаем переменные в шаблон
*/
$this->Viewer_Assign('topics', $aTopics);
$this->Viewer_Assign('paging', $aPaging);
/**
* Устанавливаем шаблон вывода
*/
$this->SetTemplateAction('index');
}
/**
* При завершении экшена загружаем переменные в шаблон
*
*/
public function EventShutdown()
{
$this->Viewer_Assign('sMenuHeadItemSelect', $this->sMenuHeadItemSelect);
$this->Viewer_Assign('sMenuItemSelect', $this->sMenuItemSelect);
$this->Viewer_Assign('sMenuSubItemSelect', $this->sMenuSubItemSelect);
$this->Viewer_Assign('iCountTopicsNew', $this->iCountTopicsNew);
$this->Viewer_Assign('iCountTopicsCollectiveNew', $this->iCountTopicsCollectiveNew);
$this->Viewer_Assign('iCountTopicsPersonalNew', $this->iCountTopicsPersonalNew);
$this->Viewer_Assign('iCountTopicsSubNew', $this->iCountTopicsNew);
$this->Viewer_Assign('sNavTopicsSubUrl', $this->sNavTopicsSubUrl);
}
}

View file

@ -0,0 +1,236 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Экшен обработки статистики юзеров, т.е. УРЛа вида /people/
*
* @package application.actions
* @since 1.0
*/
class ActionPeople extends Action
{
/**
* Главное меню
*
* @var string
*/
protected $sMenuHeadItemSelect = 'people';
/**
* Меню
*
* @var string
*/
protected $sMenuItemSelect = 'all';
/**
* Инициализация
*
*/
public function Init()
{
/**
* Устанавливаем title страницы
*/
$this->Viewer_AddHtmlTitle($this->Lang_Get('user.users'));
}
/**
* Регистрируем евенты
*
*/
protected function RegisterEvent()
{
$this->AddEventPreg('/^(index)?$/i', '/^(page([1-9]\d{0,5}))?$/i', '/^$/i', 'EventIndex');
$this->AddEventPreg('/^ajax-search$/i', 'EventAjaxSearch');
}
/**********************************************************************************
************************ РЕАЛИЗАЦИЯ ЭКШЕНА ***************************************
**********************************************************************************
*/
/**
* Поиск пользователей по логину
*/
protected function EventAjaxSearch()
{
/**
* Устанавливаем формат Ajax ответа
*/
$this->Viewer_SetResponseAjax('json');
/**
* Формируем фильтр
*/
$aFilter = array(
'activate' => 1
);
$sOrderWay = in_array(getRequestStr('order'), array('desc', 'asc')) ? getRequestStr('order') : 'desc';
$sOrderField = in_array(getRequestStr('sort_by'), array(
'user_rating',
'user_date_register',
'user_login',
'user_profile_name'
)) ? getRequestStr('sort_by') : 'user_rating';
if (is_numeric(getRequestStr('next_page')) and getRequestStr('next_page') > 0) {
$iPage = getRequestStr('next_page');
} else {
$iPage = 1;
}
/**
* Получаем из реквеста первые буквы для поиска пользователей по логину
*/
$sTitle = getRequest('sText');
if (is_string($sTitle) and mb_strlen($sTitle, 'utf-8')) {
$sTitle = str_replace(array('_', '%'), array('\_', '\%'), $sTitle);
} else {
$sTitle = '';
}
/**
* Как именно искать: совпадение в любой части логина, или только начало или конец логина
*/
if ($sTitle) {
if (getRequest('isPrefix')) {
$sTitle .= '%';
} elseif (getRequest('isPostfix')) {
$sTitle = '%' . $sTitle;
} else {
$sTitle = '%' . $sTitle . '%';
}
}
if ($sTitle) {
$aFilter['name'] = $sTitle;
}
/**
* Пол
*/
if (in_array(getRequestStr('sex'), array('man', 'woman', 'other'))) {
$aFilter['profile_sex'] = getRequestStr('sex');
}
/**
* Онлайн
* date_last
*/
if (getRequest('is_online')) {
$aFilter['date_last_more'] = date('Y-m-d H:i:s', time() - Config::Get('module.user.time_onlive'));
}
/**
* Geo привязка
*/
if (getRequestStr('city')) {
$aFilter['geo_city'] = getRequestStr('city');
} elseif (getRequestStr('region')) {
$aFilter['geo_region'] = getRequestStr('region');
} elseif (getRequestStr('country')) {
$aFilter['geo_country'] = getRequestStr('country');
}
/**
* Ищем пользователей
*/
$aResult = $this->User_GetUsersByFilter($aFilter, array($sOrderField => $sOrderWay), $iPage,
Config::Get('module.user.per_page'));
$bHideMore = $iPage * Config::Get('module.user.per_page') >= $aResult['count'];
/**
* Формируем ответ
*/
$oViewer = $this->Viewer_GetLocalViewer();
$oViewer->Assign('users', $aResult['collection'], true);
$oViewer->Assign('oUserCurrent', $this->User_GetUserCurrent());
$this->Viewer_AssignAjax('html', $oViewer->Fetch("component@user.list-loop"));
/**
* Для подгрузки
*/
$this->Viewer_AssignAjax('count_loaded', count($aResult['collection']));
$this->Viewer_AssignAjax('next_page', count($aResult['collection']) > 0 ? $iPage + 1 : $iPage);
$this->Viewer_AssignAjax('hide', $bHideMore or !$aResult['count'] or !count($aResult['collection']));
$this->Viewer_AssignAjax('searchCount', (int)$aResult['count']);
$this->Viewer_AssignAjax('count_left', (int)($aResult['count'] - ($iPage - 1) * Config::Get('module.user.per_page') - count($aResult['collection'])));
$this->Viewer_AssignAjax('textEmpty', $this->Lang_Get('search.alerts.empty'));
}
/**
* Показываем юзеров
*
*/
protected function EventIndex()
{
/**
* Получаем статистику
*/
$this->GetStats();
$aFilter = array(
'activate' => 1
);
/**
* Получаем список юзеров
*/
$aResult = $this->User_GetUsersByFilter($aFilter, array('user_rating' => 'desc'), 1,
Config::Get('module.user.per_page'));
/**
* Получаем алфавитный указатель на список пользователей
*/
$aPrefixUser = $this->User_GetGroupPrefixUser(1);
/**
* Список используемых стран
*/
$aCountriesUsed = $this->Geo_GetCountriesUsedByTargetType('user');
/**
* Загружаем переменные в шаблон
*/
$this->Viewer_Assign('users', $aResult['collection']);
$this->Viewer_Assign('searchCount', $aResult['count']);
$this->Viewer_Assign('prefixUser', $aPrefixUser);
$this->Viewer_Assign('countriesUsed', $aCountriesUsed);
/**
* Устанавливаем шаблон вывода
*/
$this->SetTemplateAction('index');
}
/**
* Получение статистики
*
*/
protected function GetStats()
{
/**
* Статистика кто, где и т.п.
*/
$aStat = $this->User_GetStatUsers();
/**
* Загружаем переменные в шаблон
*/
$this->Viewer_Assign('usersStat', $aStat);
}
/**
* Выполняется при завершении работы экшена
*
*/
public function EventShutdown()
{
/**
* Загружаем в шаблон необходимые переменные
*/
$this->Viewer_Assign('sMenuHeadItemSelect', $this->sMenuHeadItemSelect);
$this->Viewer_Assign('sMenuItemSelect', $this->sMenuItemSelect);
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,123 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Экшен обработки УРЛа вида /property/
*
* @package application.actions
* @since 2.0
*/
class ActionProperty extends Action
{
/**
* Текущий пользователь
*
* @var ModuleUser_EntityUser|null
*/
protected $oUserCurrent = null;
/**
* Инициализация
*/
public function Init()
{
/**
* Достаём текущего пользователя
*/
$this->oUserCurrent = $this->User_GetUserCurrent();
}
/**
* Регистрируем евенты
*/
protected function RegisterEvent()
{
$this->AddEventPreg('/^download$/i', '/^[\w]{10,32}$/i', '/^$/i', 'EventDownloadFile');
}
/**********************************************************************************
************************ РЕАЛИЗАЦИЯ ЭКШЕНА ***************************************
**********************************************************************************
*/
/**
* Загрузка файла
*/
protected function EventDownloadFile()
{
$sKey = $this->GetParam(0);
/**
* Выполняем проверки
*/
if (!$oValue = $this->Property_GetValueByValueVarchar($sKey)) {
return parent::EventNotFound();
}
if (!$oProperty = $oValue->getProperty()) {
return parent::EventNotFound();
}
if ($oProperty->getType() != ModuleProperty::PROPERTY_TYPE_FILE) {
return parent::EventNotFound();
}
if (!$oTargetRel = $this->Property_GetTargetByType($oValue->getTargetType())) {
return parent::EventNotFound();
}
if ($oTargetRel->getState() != ModuleProperty::TARGET_STATE_ACTIVE) {
return parent::EventNotFound();
}
$bAllowDownload = false;
if (!$this->oUserCurrent) {
if ($oProperty->getParam('access_only_auth')) {
return Router::Action('error', '403');
} else {
$bAllowDownload = true;
}
}
if (!$bAllowDownload) {
/**
* Проверяем доступ пользователя к объекту, которому принадлежит свойство
*/
if ($this->Property_CheckAllowTargetObject($oValue->getTargetType(), $oValue->getTargetId(),
array('user' => $this->oUserCurrent))
) {
$bAllowDownload = true;
}
}
if ($bAllowDownload) {
/**
* Увеличиваем количество загрузок
*/
$aStats = $oValue->getDataOne('stats');
$aStats['count_download'] = (isset($aStats['count_download']) ? $aStats['count_download'] : 0) + 1;
$oValue->setDataOne('stats', $aStats);
$oValue->Update();
$oValueType = $oValue->getValueTypeObject();
if (!$oValueType->DownloadFile()) {
return parent::EventNotFound();
}
} else {
return Router::Action('error', '403');
}
$this->SetTemplate(false);
}
}

View file

@ -0,0 +1,460 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Экшен бработки RSS
* Автор класса vovazol(http://livestreet.ru/profile/vovazol/)
*
* @package application.actions
* @since 1.0
*/
class ActionRss extends Action
{
/**
* Инициализация
*/
public function Init()
{
$this->SetDefaultEvent('index');
Router::SetIsShowStats(false);
}
/**
* Указывает браузеру правильный content type в случае вывода RSS-ленты
*/
protected function InitRss()
{
header('Content-Type: application/rss+xml; charset=utf-8');
}
/**
* Регистрация евентов
*/
protected function RegisterEvent()
{
$this->AddEvent('index', 'RssGood');
$this->AddEvent('full', 'RssFull');
$this->AddEvent('new', 'RssNew');
$this->AddEvent('allcomments', 'RssComments');
$this->AddEvent('comments', 'RssTopicComments');
$this->AddEvent('tag', 'RssTag');
$this->AddEvent('blog', 'RssColectiveBlog');
$this->AddEvent('personal_blog', 'RssPersonalBlog');
}
/**
* Вывод RSS интересных топиков
*/
protected function RssGood()
{
/**
* Получаем топики
*/
$aResult = $this->Topic_GetTopicsGood(1, Config::Get('module.topic.max_rss_count'), false);
$aTopics = $aResult['collection'];
/**
* Формируем данные канала RSS
*/
$aChannel['title'] = Config::Get('view.name');
$aChannel['link'] = Router::GetPath('/');
$aChannel['description'] = Config::Get('view.name') . ' / RSS channel';
$aChannel['language'] = 'ru';
$aChannel['managingEditor'] = Config::Get('general.rss_editor_mail');
$aChannel['generator'] = Config::Get('view.name');
/**
* Формируем записи RSS
*/
$topics = array();
foreach ($aTopics as $oTopic) {
$item['title'] = $oTopic->getTitle();
$item['guid'] = $oTopic->getUrl();
$item['link'] = $oTopic->getUrl();
$item['description'] = $this->getTopicText($oTopic);
$item['pubDate'] = $oTopic->getDatePublish();
$item['author'] = $oTopic->getUser()->getLogin();
$item['category'] = htmlspecialchars($oTopic->getTags());
$topics[] = $item;
}
/**
* Формируем ответ
*/
$this->InitRss();
$this->Viewer_Assign('aChannel', $aChannel);
$this->Viewer_Assign('aItems', $topics);
$this->SetTemplateAction('index');
}
/**
* Вывод RSS новых топиков
*/
protected function RssNew()
{
/**
* Получаем топики
*/
$aResult = $this->Topic_GetTopicsNew(1, Config::Get('module.topic.max_rss_count'), false);
$aTopics = $aResult['collection'];
/**
* Формируем данные канала RSS
*/
$aChannel['title'] = Config::Get('view.name');
$aChannel['link'] = Router::GetPath('/');
$aChannel['description'] = Router::GetPath('/') . ' / RSS channel';
$aChannel['language'] = 'ru';
$aChannel['managingEditor'] = Config::Get('general.rss_editor_mail');
$aChannel['generator'] = Router::GetPath('/');
/**
* Формируем записи RSS
*/
$topics = array();
foreach ($aTopics as $oTopic) {
$item['title'] = $oTopic->getTitle();
$item['guid'] = $oTopic->getUrl();
$item['link'] = $oTopic->getUrl();
$item['description'] = $this->getTopicText($oTopic);
$item['pubDate'] = $oTopic->getDatePublish();
$item['author'] = $oTopic->getUser()->getLogin();
$item['category'] = htmlspecialchars($oTopic->getTags());
$topics[] = $item;
}
/**
* Формируем ответ
*/
$this->InitRss();
$this->Viewer_Assign('aChannel', $aChannel);
$this->Viewer_Assign('aItems', $topics);
$this->SetTemplateAction('index');
}
/**
* Вывод полнотекстового RSS интересных топиков
*/
protected function RssFull()
{
/**
* Получаем топики
*/
$aResult = $this->Topic_GetTopicsNew(1, Config::Get('module.topic.max_rss_count'), false);
$aTopics = $aResult['collection'];
/**
* Формируем данные канала RSS
*/
$aChannel['title'] = Config::Get('view.name');
$aChannel['link'] = Router::GetPath('/');
$aChannel['description'] = Config::Get('view.name') . ' / RSS channel';
$aChannel['language'] = 'ru';
$aChannel['managingEditor'] = Config::Get('general.rss_editor_mail');
$aChannel['generator'] = Config::Get('view.name');
/**
* Формируем записи RSS
*/
$topics = array();
foreach ($aTopics as $oTopic) {
$item['title'] = $oTopic->getTitle();
$item['guid'] = $oTopic->getUrl();
$item['link'] = $oTopic->getUrl();
$item['description'] = $this->getTopicFullText($oTopic);
$item['pubDate'] = $oTopic->getDatePublish();
$item['author'] = $oTopic->getUser()->getLogin();
$item['category'] = htmlspecialchars($oTopic->getTags());
$topics[] = $item;
}
/**
* Формируем ответ
*/
$this->InitRss();
$this->Viewer_Assign('aChannel', $aChannel);
$this->Viewer_Assign('aItems', $topics);
$this->SetTemplateAction('index');
}
/**
* Вывод RSS последних комментариев
*/
protected function RssComments()
{
/**
* Получаем закрытые блоги, чтобы исключить их из выдачи
*/
$aCloseBlogs = $this->Blog_GetInaccessibleBlogsByUser();
/**
* Получаем комментарии
*/
$aResult = $this->Comment_GetCommentsAll('topic', 1, Config::Get('module.comment.max_rss_count'), array(),
$aCloseBlogs);
$aComments = $aResult['collection'];
/**
* Формируем данные канала RSS
*/
$aChannel['title'] = Config::Get('view.name');
$aChannel['link'] = Router::GetPath('/');
$aChannel['description'] = Router::GetPath('/') . ' / RSS channel';
$aChannel['language'] = 'ru';
$aChannel['managingEditor'] = Config::Get('general.rss_editor_mail');
$aChannel['generator'] = Router::GetPath('/');
/**
* Формируем записи RSS
*/
$comments = array();
foreach ($aComments as $oComment) {
$item['title'] = 'Comments: ' . $oComment->getTarget()->getTitle();
$item['guid'] = $oComment->getTarget()->getUrl() . '#comment' . $oComment->getId();
$item['link'] = $oComment->getTarget()->getUrl() . '#comment' . $oComment->getId();
$item['description'] = $oComment->getText();
$item['pubDate'] = $oComment->getDate();
$item['author'] = $oComment->getUser()->getLogin();
$item['category'] = 'comments';
$comments[] = $item;
}
/**
* Формируем ответ
*/
$this->InitRss();
$this->Viewer_Assign('aChannel', $aChannel);
$this->Viewer_Assign('aItems', $comments);
$this->SetTemplateAction('index');
}
/**
* Вывод RSS комментариев конкретного топика
*/
protected function RssTopicComments()
{
$sTopicId = $this->GetParam(0);
/**
* Топик существует?
*/
if (!($oTopic = $this->Topic_GetTopicById($sTopicId)) or !$oTopic->getPublish() or $oTopic->getBlog()->getType() == 'close') {
return parent::EventNotFound();
}
/**
* Получаем комментарии
*/
$aResult = $this->Comment_GetCommentsByFilter(array('target_id' => $oTopic->getId(),
'target_type' => 'topic',
'delete' => 0
), array('comment_id' => 'desc'), 1, 100);
$aComments = $aResult['collection'];
/**
* Формируем данные канала RSS
*/
$aChannel['title'] = Config::Get('view.name');
$aChannel['link'] = Router::GetPath('/');
$aChannel['description'] = Router::GetPath('/') . ' / RSS channel';
$aChannel['language'] = 'ru';
$aChannel['managingEditor'] = Config::Get('general.rss_editor_mail');
$aChannel['generator'] = Router::GetPath('/');
/**
* Формируем записи RSS
*/
$comments = array();
foreach ($aComments as $oComment) {
$item['title'] = 'Comments: ' . $oTopic->getTitle();
$item['guid'] = $oTopic->getUrl() . '#comment' . $oComment->getId();
$item['link'] = $oTopic->getUrl() . '#comment' . $oComment->getId();
$item['description'] = $oComment->getText();
$item['pubDate'] = $oComment->getDate();
$item['author'] = $oComment->getUser()->getLogin();
$item['category'] = 'comments';
$comments[] = $item;
}
/**
* Формируем ответ
*/
$this->InitRss();
$this->Viewer_Assign('aChannel', $aChannel);
$this->Viewer_Assign('aItems', $comments);
$this->SetTemplateAction('index');
}
/**
* Вывод RSS топиков по определенному тегу
*/
protected function RssTag()
{
$sTag = urldecode($this->GetParam(0));
/**
* Получаем топики
*/
$aResult = $this->Topic_GetTopicsByTag($sTag, 1, Config::Get('module.topic.max_rss_count'), false);
$aTopics = $aResult['collection'];
/**
* Формируем данные канала RSS
*/
$aChannel['title'] = Config::Get('view.name');
$aChannel['link'] = Router::GetPath('/');
$aChannel['description'] = Router::GetPath('/') . ' / RSS channel';
$aChannel['language'] = 'ru';
$aChannel['managingEditor'] = Config::Get('general.rss_editor_mail');
$aChannel['generator'] = Router::GetPath('/');
/**
* Формируем записи RSS
*/
$topics = array();
foreach ($aTopics as $oTopic) {
$item['title'] = $oTopic->getTitle();
$item['guid'] = $oTopic->getUrl();
$item['link'] = $oTopic->getUrl();
$item['description'] = $this->getTopicText($oTopic);
$item['pubDate'] = $oTopic->getDatePublish();
$item['author'] = $oTopic->getUser()->getLogin();
$item['category'] = htmlspecialchars($oTopic->getTags());
$topics[] = $item;
}
/**
* Формируем ответ
*/
$this->InitRss();
$this->Viewer_Assign('aChannel', $aChannel);
$this->Viewer_Assign('aItems', $topics);
$this->SetTemplateAction('index');
}
/**
* Вывод RSS топиков из коллективного блога
*/
protected function RssColectiveBlog()
{
$sBlogUrl = $this->GetParam(0);
/**
* Если блог существует, то получаем записи
*/
if (!$sBlogUrl or !($oBlog = $this->Blog_GetBlogByUrl($sBlogUrl)) or $oBlog->getType() == "close") {
return parent::EventNotFound();
} else {
$aResult = $this->Topic_GetTopicsByBlog($oBlog, 1, Config::Get('module.topic.max_rss_count'), 'good');
}
$aTopics = $aResult['collection'];
/**
* Формируем данные канала RSS
*/
$aChannel['title'] = Config::Get('view.name');
$aChannel['link'] = Router::GetPath('/');
$aChannel['description'] = Router::GetPath('/') . ' / ' . $oBlog->getTitle() . ' / RSS channel';
$aChannel['language'] = 'ru';
$aChannel['managingEditor'] = Config::Get('general.rss_editor_mail');
$aChannel['generator'] = Router::GetPath('/');
/**
* Формируем записи RSS
*/
$topics = array();
foreach ($aTopics as $oTopic) {
$item['title'] = $oTopic->getTitle();
$item['guid'] = $oTopic->getUrl();
$item['link'] = $oTopic->getUrl();
$item['description'] = $this->getTopicText($oTopic);
$item['pubDate'] = $oTopic->getDatePublish();
$item['author'] = $oTopic->getUser()->getLogin();
$item['category'] = htmlspecialchars($oTopic->getTags());
$topics[] = $item;
}
/**
* Формируем ответ
*/
$this->InitRss();
$this->Viewer_Assign('aChannel', $aChannel);
$this->Viewer_Assign('aItems', $topics);
$this->SetTemplateAction('index');
}
/**
* Вывод RSS топиков из персонального блога или всех персональных
*/
protected function RssPersonalBlog()
{
$this->sUserLogin = $this->GetParam(0);
if (!$this->sUserLogin) {
/**
* RSS-лента всех записей из персональных блогов
*/
$aResult = $this->Topic_GetTopicsPersonal(1, Config::Get('module.topic.max_rss_count'));
} elseif (!$oUser = $this->User_GetUserByLogin($this->sUserLogin)) {
return parent::EventNotFound();
} else {
/**
* RSS-лента записей персонального блога указанного пользователя
*/
$aResult = $this->Topic_GetTopicsPersonalByUser($oUser->getId(), 1, 1,
Config::Get('module.topic.max_rss_count'));
}
$aTopics = $aResult['collection'];
/**
* Формируем данные канала RSS
*/
$aChannel['title'] = Config::Get('view.name');
$aChannel['link'] = Router::GetPath('/');
$aChannel['description'] = ($this->sUserLogin)
? Router::GetPath('/') . ' / ' . $oUser->getLogin() . ' / RSS channel'
: Router::GetPath('/') . ' / RSS channel';
$aChannel['language'] = 'ru';
$aChannel['managingEditor'] = Config::Get('general.rss_editor_mail');
$aChannel['generator'] = Router::GetPath('/');
/**
* Формируем записи RSS
*/
$topics = array();
foreach ($aTopics as $oTopic) {
$item['title'] = $oTopic->getTitle();
$item['guid'] = $oTopic->getUrl();
$item['link'] = $oTopic->getUrl();
$item['description'] = $this->getTopicText($oTopic);
$item['pubDate'] = $oTopic->getDatePublish();
$item['author'] = $oTopic->getUser()->getLogin();
$item['category'] = htmlspecialchars($oTopic->getTags());
$topics[] = $item;
}
/**
* Формируем ответ
*/
$this->InitRss();
$this->Viewer_Assign('aChannel', $aChannel);
$this->Viewer_Assign('aItems', $topics);
$this->SetTemplateAction('index');
}
/**
* Формирует текст топика для RSS
*
*/
protected function getTopicText($oTopic)
{
$sText = $oTopic->getTextShort();
if ($oTopic->getTextShort() != $oTopic->getText()) {
$sText .= "<br><a href=\"{$oTopic->getUrl()}#cut\" title=\"{$this->Lang_Get('topic.read_more')}\">";
if ($oTopic->getCutText()) {
$sText .= htmlspecialchars($oTopic->getCutText());
} else {
$sText .= $this->Lang_Get('topic.read_more');
}
$sText .= "</a>";
}
return $sText;
}
/**
* Формирует полный текст топика (без ката) для RSS
*
*/
protected function getTopicFullText($oTopic)
{
return $oTopic->getText();
}
}

View file

@ -0,0 +1,43 @@
<?php
/**
* Статическая страница правил
*
* @package application.actions
* @since 1.0
*/
class ActionRules extends Action
{
/**
* Инициализация экшена
*
*/
public function Init()
{
/**
* Устанавливаем дефолтный евент
*/
$this->SetDefaultEvent('index');
}
/**
* Регистрируем евенты
*
*/
protected function RegisterEvent()
{
$this->AddEvent('index', 'EventIndex');
}
/**
* Вывод правил
*
*/
protected function EventIndex()
{
/**
* Устанавливаем title страницы
*/
$this->Viewer_AddHtmlTitle('Правила Ифхаба');
$this->SetTemplateAction('index');
}
}

View file

@ -0,0 +1,172 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Обработка основного поиска
*
* @package application.actions
* @since 1.0
*/
class ActionSearch extends Action
{
public function Init()
{
$this->SetDefaultEvent('index');
$this->Viewer_AddHtmlTitle($this->Lang_Get('search.search'));
}
/**
* Регистрация евентов
*/
protected function RegisterEvent()
{
$this->AddEvent('index', 'EventIndex');
$this->AddEventPreg('/^topics$/i', '/^(page([1-9]\d{0,5}))?$/i', 'EventTopics');
$this->AddEventPreg('/^comments$/i', '/^(page([1-9]\d{0,5}))?$/i', 'EventComments');
$this->AddEvent('opensearch', 'EventOpenSearch');
}
/**
* Главная страница поиска
*/
protected function EventIndex()
{
$this->SetTemplateAction('index');
}
/**
* Обработка стандарта для браузеров Open Search
*/
function EventOpenSearch()
{
Router::SetIsShowStats(false);
header('Content-type: text/xml; charset=utf-8');
}
/**
* Обработка поиска топиков
*/
protected function EventTopics()
{
$this->SetTemplateAction('index');
$sSearchType = $this->sCurrentEvent;
$iPage = $this->GetParamEventMatch(0, 2) ? $this->GetParamEventMatch(0, 2) : 1;
/**
* Получаем список слов для поиска
*/
$aWords = $this->Search_GetWordsForSearch(mb_strtolower(getRequestStr('q'),"utf-8"));
if (!$aWords) {
$this->Message_AddErrorSingle($this->Lang_Get('search.alerts.query_incorrect'));
return;
}
$sQuery = join(' ', $aWords);
/**
* Формируем регулярное выражение для поиска
*/
$sRegexp = $this->Search_GetRegexpForWords($aWords);
/**
* Выполняем поиск
*/
$aResult = $this->Search_SearchTopics($sRegexp, $iPage, Config::Get('module.topic.per_page'));
$aResultItems = $aResult['collection'];
/**
* Конфигурируем парсер jevix
*/
$this->Text_LoadJevixConfig('search');
/**
* Делаем сниппеты
*/
foreach ($aResultItems AS $oItem) {
/**
* Т.к. текст в сниппетах небольшой, то можно прогнать через парсер
*/
$oItem->setTextShort($this->Text_JevixParser($this->Search_BuildExcerpts($oItem->getText(), $aWords)));
}
/**
* Формируем постраничность
*/
$aPaging = $this->Viewer_MakePaging($aResult['count'], $iPage, Config::Get('module.topic.per_page'),
Config::Get('pagination.pages.count'), Router::GetPath('search') . $sSearchType, array('q' => $sQuery));
/**
* Загружаем переменные в шаблон
*/
$this->Viewer_Assign('resultItems', $aResultItems);
$this->Viewer_Assign('paging', $aPaging);
$this->Viewer_Assign('searchType', $sSearchType);
$this->Viewer_Assign('query', $sQuery);
$this->Viewer_Assign('typeCounts', array($sSearchType => $aResult['count']));
}
/**
* Обработка поиска комментариев
*/
protected function EventComments()
{
$this->SetTemplateAction('index');
$sSearchType = $this->sCurrentEvent;
$iPage = $this->GetParamEventMatch(0, 2) ? $this->GetParamEventMatch(0, 2) : 1;
/**
* Получаем список слов для поиска
*/
$aWords = $this->Search_GetWordsForSearch(mb_strtolower(getRequestStr('q'),"utf-8"));
if (!$aWords) {
$this->Message_AddErrorSingle($this->Lang_Get('search.alerts.query_incorrect'));
return;
}
$sQuery = join(' ', $aWords);
/**
* Формируем регулярное выражение для поиска
*/
$sRegexp = $this->Search_GetRegexpForWords($aWords);
/**
* Выполняем поиск
*/
$aResult = $this->Search_SearchComments($sRegexp, $iPage, 4, 'topic');
$aResultItems = $aResult['collection'];
/**
* Конфигурируем парсер jevix
*/
$this->Text_LoadJevixConfig('search');
/**
* Делаем сниппеты
*/
foreach ($aResultItems AS $oItem) {
/**
* Т.к. текст в сниппетах небольшой, то можно прогнать через парсер
*/
$oItem->setText($this->Text_JevixParser($this->Search_BuildExcerpts($oItem->getText(), $aWords)));
}
/**
* Формируем постраничность
*/
$aPaging = $this->Viewer_MakePaging($aResult['count'], $iPage, 4, Config::Get('pagination.pages.count'),
Router::GetPath('search') . $sSearchType, array('q' => $sQuery));
/**
* Загружаем переменные в шаблон
*/
$this->Viewer_Assign('resultItems', $aResultItems);
$this->Viewer_Assign('paging', $aPaging);
$this->Viewer_Assign('searchType', $sSearchType);
$this->Viewer_Assign('query', $sQuery);
$this->Viewer_Assign('typeCounts', array($sSearchType => $aResult['count']));
}
}

View file

@ -0,0 +1,731 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Экшен обрабтки настроек профиля юзера (/settings/)
*
* @package application.actions
* @since 1.0
*/
class ActionSettings extends Action
{
/**
* Какое меню активно
*
* @var string
*/
protected $sMenuItemSelect = 'settings';
/**
* Меню профиля пользователя
*
* @var string
*/
protected $sMenuProfileItemSelect = 'settings';
/**
* Какое подменю активно
*
* @var string
*/
protected $sMenuSubItemSelect = 'profile';
/**
* Текущий юзер
*
* @var ModuleUser_EntityUser|null
*/
protected $oUserCurrent = null;
/**
* Инициализация
*
*/
public function Init()
{
/**
* Проверяем авторизован ли юзер
*/
if (!$this->User_IsAuthorization()) {
$this->Message_AddErrorSingle($this->Lang_Get('common.error.not_access'), $this->Lang_Get('common.error.error'));
return Router::Action('error');
}
/**
* Получаем текущего юзера
*/
$this->oUserCurrent = $this->User_GetUserCurrent();
$this->SetDefaultEvent('profile');
/**
* Устанавливаем title страницы
*/
$this->Viewer_AddHtmlTitle($this->Lang_Get('user.settings.title'));
}
/**
* Регистрация евентов
*/
protected function RegisterEvent()
{
$this->AddEvent('profile', 'EventProfile');
$this->AddEvent('invite', 'EventInvite');
$this->AddEvent('tuning', 'EventTuning');
$this->AddEvent('account', 'EventAccount');
$this->AddEventPreg('/^ajax-upload-photo$/i', '/^$/i', 'EventAjaxUploadPhoto');
$this->AddEventPreg('/^ajax-crop-photo$/i', '/^$/i', 'EventAjaxCropPhoto');
$this->AddEventPreg('/^ajax-crop-cancel-photo$/i', '/^$/i', 'EventAjaxCropCancelPhoto');
$this->AddEventPreg('/^ajax-remove-photo$/i', '/^$/i', 'EventAjaxRemovePhoto');
$this->AddEventPreg('/^ajax-change-avatar$/i', '/^$/i', 'EventAjaxChangeAvatar');
$this->AddEventPreg('/^ajax-modal-crop-photo$/i', '/^$/i', 'EventAjaxModalCropPhoto');
$this->AddEventPreg('/^ajax-modal-crop-avatar$/i', '/^$/i', 'EventAjaxModalCropAvatar');
}
/**********************************************************************************
************************ РЕАЛИЗАЦИЯ ЭКШЕНА ***************************************
**********************************************************************************
*/
/**
* Загрузка фотографии в профиль пользователя
*/
protected function EventAjaxUploadPhoto()
{
/**
* Устанавливаем формат Ajax ответа
*/
$this->Viewer_SetResponseAjax('json');
if (!isset($_FILES['photo']['tmp_name'])) {
return $this->EventErrorDebug();
}
if (!$oUser = $this->User_GetUserById(getRequestStr('target_id'))) {
return $this->EventErrorDebug();
}
if (!$oUser->isAllowEdit()) {
return $this->EventErrorDebug();
}
/**
* Копируем загруженный файл
*/
$sFileTmp = Config::Get('sys.cache.dir') . func_generator();
if (!move_uploaded_file($_FILES['photo']['tmp_name'], $sFileTmp)) {
return false;
}
/**
* Если объект изображения не создан, возвращаем ошибку
*/
if (!$oImage = $this->Image_Open($sFileTmp)) {
$this->Fs_RemoveFileLocal($sFileTmp);
$this->Message_AddError($this->Image_GetLastError());
return;
}
/**
* Ресайзим и сохраняем именьшенную копию
* Храним две копии - мелкую для показа пользователю и крупную в качестве исходной для ресайза
*/
$sDir = Config::Get('path.uploads.images') . "/tmp/userphoto/{$oUser->getId()}";
$aPhotoSizes = $this->Media_ParsedImageSize(Config::Get('module.user.profile_photo_size'));
$sSaveWidth = $aPhotoSizes['w'] > 1000 ? $aPhotoSizes['w'] : 1000;
if ($sFileOriginal = $oImage->resize($sSaveWidth, null)->saveSmart($sDir, 'original', array('skip_watermark' => true))) {
if ($sFilePreview = $oImage->resize(350, null)->saveSmart($sDir, 'preview', array('skip_watermark' => true))) {
list($iOriginalWidth, $iOriginalHeight) = @getimagesize($this->Fs_GetPathServer($sFileOriginal));
list($iWidth, $iHeight) = @getimagesize($this->Fs_GetPathServer($sFilePreview));
/**
* Сохраняем в сессии временный файл с изображением
*/
$this->Session_Set('sPhotoFileTmp', $sFileOriginal);
$this->Session_Set('sPhotoFilePreviewTmp', $sFilePreview);
$this->Viewer_AssignAjax('path', $this->Fs_GetPathWeb($sFilePreview));
$this->Viewer_AssignAjax('original_width', $iOriginalWidth);
$this->Viewer_AssignAjax('original_height', $iOriginalHeight);
$this->Viewer_AssignAjax('width', $iWidth);
$this->Viewer_AssignAjax('height', $iHeight);
$this->Fs_RemoveFileLocal($sFileTmp);
return;
}
}
$this->Message_AddError($this->Image_GetLastError());
$this->Fs_RemoveFileLocal($sFileTmp);
}
/**
* Обрезка фотографии в профиль пользователя
*/
protected function EventAjaxCropPhoto()
{
/**
* Устанавливаем формат Ajax ответа
*/
$this->Viewer_SetResponseAjax('json');
if (!$oUser = $this->User_GetUserById(getRequestStr('target_id'))) {
return $this->EventErrorDebug();
}
if (!$oUser->isAllowEdit()) {
return $this->EventErrorDebug();
}
$sFile = $this->Session_Get('sPhotoFileTmp');
$sFilePreview = $this->Session_Get('sPhotoFilePreviewTmp');
if (!$this->Image_IsExistsFile($sFile)) {
$this->Message_AddErrorSingle($this->Lang_Get('common.error.system.base'));
return;
}
if (true === ($res = $this->User_CreateProfilePhoto($sFile, $oUser, getRequest('size'),
getRequestStr('canvas_width')))
) {
$this->Image_RemoveFile($sFile);
$this->Image_RemoveFile($sFilePreview);
$this->Session_Drop('sPhotoFileTmp');
$this->Session_Drop('sPhotoFilePreviewTmp');
/**
* Создаем аватар на основе фото
*/
$this->User_CreateProfileAvatar($oUser->getProfileFoto(), $oUser);
$this->Viewer_AssignAjax('upload_text', $this->Lang_Get('user.photo.actions.change_photo'));
$this->Viewer_AssignAjax('photo', $oUser->getProfileFotoPath());
} else {
$this->Message_AddError(is_string($res) ? $res : $this->Lang_Get('common.error.error'));
}
}
/**
* Показывает модальное окно с кропом фото
*/
protected function EventAjaxModalCropPhoto()
{
$this->Viewer_SetResponseAjax('json');
$oViewer = $this->Viewer_GetLocalViewer();
$oViewer->Assign('image', getRequestStr('path'), true);
$oViewer->Assign('originalWidth', (int)getRequest('original_width'), true);
$oViewer->Assign('originalHeight', (int)getRequest('original_height'), true);
$oViewer->Assign('width', (int)getRequest('width'), true);
$oViewer->Assign('height', (int)getRequest('height'), true);
$this->Viewer_AssignAjax('sText', $oViewer->Fetch("component@photo.modal-photo"));
}
/**
* Показывает модальное окно с кропом аватарки
*/
protected function EventAjaxModalCropAvatar()
{
$this->Viewer_SetResponseAjax('json');
$oViewer = $this->Viewer_GetLocalViewer();
$oViewer->Assign('image', getRequestStr('path'), true);
$oViewer->Assign('originalWidth', (int)getRequest('original_width'), true);
$oViewer->Assign('originalHeight', (int)getRequest('original_height'), true);
$oViewer->Assign('width', (int)getRequest('width'), true);
$oViewer->Assign('height', (int)getRequest('height'), true);
$oViewer->Assign('usePreview', true, true);
$this->Viewer_AssignAjax('sText', $oViewer->Fetch("component@photo.modal-avatar"));
}
/**
* Удаляет временные файлы кропа фото
*/
protected function EventAjaxCropCancelPhoto()
{
/**
* Устанавливаем формат Ajax ответа
*/
$this->Viewer_SetResponseAjax('json');
if (!$oUser = $this->User_GetUserById(getRequestStr('target_id'))) {
return $this->EventErrorDebug();
}
if (!$oUser->isAllowEdit()) {
return $this->EventErrorDebug();
}
$sFile = $this->Session_Get('sPhotoFileTmp');
$sFilePreview = $this->Session_Get('sPhotoFilePreviewTmp');
$this->Image_RemoveFile($sFile);
$this->Image_RemoveFile($sFilePreview);
$this->Session_Drop('sPhotoFileTmp');
$this->Session_Drop('sPhotoFilePreviewTmp');
}
/**
* Удаление фотографии профиля
*/
protected function EventAjaxRemovePhoto()
{
$this->Viewer_SetResponseAjax('json');
if (!$oUser = $this->User_GetUserById(getRequestStr('target_id'))) {
return $this->EventErrorDebug();
}
if (!$oUser->isAllowEdit()) {
return $this->EventErrorDebug();
}
$this->User_DeleteProfilePhoto($oUser);
$this->User_DeleteProfileAvatar($oUser);
$this->User_Update($oUser);
$this->Viewer_AssignAjax('upload_text', $this->Lang_Get('user.photo.actions.upload_photo'));
$this->Viewer_AssignAjax('photo', $oUser->getProfileFotoPath());
$this->Viewer_AssignAjax('avatars', $oUser->GetProfileAvatarsPath());
}
/**
* Обновление аватара на основе фото профиля
*/
protected function EventAjaxChangeAvatar()
{
$this->Viewer_SetResponseAjax('json');
if (!$oUser = $this->User_GetUserById(getRequestStr('target_id'))) {
return $this->EventErrorDebug();
}
if (!$oUser->isAllowEdit()) {
return $this->EventErrorDebug();
}
if (true === ($res = $this->User_CreateProfileAvatar($oUser->getProfileFoto(), $oUser, getRequest('size'),
getRequestStr('canvas_width')))
) {
// Формируем массив с путями до аватаров
$this->Viewer_AssignAjax('avatars', $oUser->GetProfileAvatarsPath());
} else {
$this->Message_AddError(is_string($res) ? $res : $this->Lang_Get('common.error.error'));
}
}
/**
* Дополнительные настройки сайта
*/
protected function EventTuning()
{
$this->sMenuItemSelect = 'settings';
$this->sMenuSubItemSelect = 'tuning';
$this->Viewer_AddHtmlTitle($this->Lang_Get('user.settings.nav.tuning'));
$aTimezoneList = DateTimeZone::listIdentifiers();
$this->Viewer_Assign('aTimezoneList', $aTimezoneList);
/**
* Если отправили форму с настройками - сохраняем
*/
if (isPost()) {
$this->Security_ValidateSendForm();
if (in_array(getRequestStr('settings_general_timezone'), $aTimezoneList)) {
$this->oUserCurrent->setSettingsTimezone(getRequestStr('settings_general_timezone'));
}
$this->oUserCurrent->setSettingsNoticeNewTopic(getRequest('settings_notice_new_topic') ? 1 : 0);
$this->oUserCurrent->setSettingsNoticeNewComment(getRequest('settings_notice_new_comment') ? 1 : 0);
$this->oUserCurrent->setSettingsNoticeNewTalk(getRequest('settings_notice_new_talk') ? 1 : 0);
$this->oUserCurrent->setSettingsNoticeReplyComment(getRequest('settings_notice_reply_comment') ? 1 : 0);
$this->oUserCurrent->setSettingsNoticeNewFriend(getRequest('settings_notice_new_friend') ? 1 : 0);
$this->oUserCurrent->setProfileDate(date("Y-m-d H:i:s"));
/**
* Запускаем выполнение хуков
*/
$this->Hook_Run('settings_tuning_save_before', array('oUser' => $this->oUserCurrent));
if ($this->User_Update($this->oUserCurrent)) {
$this->Message_AddNoticeSingle($this->Lang_Get('common.success.save'));
$this->Hook_Run('settings_tuning_save_after', array('oUser' => $this->oUserCurrent));
} else {
$this->Message_AddErrorSingle($this->Lang_Get('common.error.system.base'));
}
} else {
if (is_null($this->oUserCurrent->getSettingsTimezone())) {
$_REQUEST['settings_general_timezone'] = date_default_timezone_get();
} else {
$_REQUEST['settings_general_timezone'] = $this->oUserCurrent->getSettingsTimezone();
}
}
}
/**
* Показ и обработка формы приглаешний
*
*/
protected function EventInvite()
{
$this->sMenuSubItemSelect = 'invite';
$this->Viewer_AddHtmlTitle($this->Lang_Get('user.settings.nav.invites'));
$this->Viewer_Assign('iCountInviteAvailable', $this->Invite_GetCountInviteAvailable($this->oUserCurrent));
$this->Viewer_Assign('iCountInviteUsed', $this->Invite_GetCountInviteUsed($this->oUserCurrent->getId()));
$this->Viewer_Assign('sReferralLink', $this->Invite_GetReferralLink($this->oUserCurrent));
/**
* Если отправили форму
*/
if (isPost()) {
$this->Security_ValidateSendForm();
$bError = false;
/**
* Есть права на отправку инвайтов?
*/
if (!$this->ACL_CanSendInvite($this->oUserCurrent)) {
$this->Message_AddErrorSingle($this->Rbac_GetMsgLast());
return;
}
/**
* Емайл корректен?
*/
if (!$this->Validate_Validate('email', getRequestStr('invite_mail'), array('allowEmpty' => false))) {
$this->Message_AddError($this->Validate_GetErrorLast());
return;
}
if (Config::Get('general.reg.invite')) {
if (!($oInvite = $this->Invite_GenerateInvite($this->oUserCurrent))) {
return $this->EventErrorDebug();
}
$sRefCode = $oInvite->getCode();
} else {
if (!($sRefCode = $this->Invite_GetReferralCode($this->oUserCurrent))) {
return $this->EventErrorDebug();
}
}
/**
* Если нет ошибок, то отправляем инвайт
*/
if (!$bError) {
/**
* Запускаем выполнение хуков
*/
$this->Hook_Run('settings_invite_send_before', array('oUser' => $this->oUserCurrent, 'sRefCode' => $sRefCode));
$this->Invite_SendNotifyInvite($this->oUserCurrent, getRequestStr('invite_mail'), $sRefCode);
$this->Message_AddNoticeSingle($this->Lang_Get('user.settings.invites.notices.success'));
$this->Hook_Run('settings_invite_send_after', array('oUser' => $this->oUserCurrent, 'sRefCode' => $sRefCode));
}
}
}
/**
* Форма смены пароля, емайла
*/
protected function EventAccount()
{
/**
* Устанавливаем title страницы
*/
$this->Viewer_AddHtmlTitle($this->Lang_Get('user.settings.nav.account'));
$this->sMenuSubItemSelect = 'account';
/**
* Если нажали кнопку "Сохранить"
*/
if (isPost()) {
$this->Security_ValidateSendForm();
$bError = false;
/**
* Проверка мыла
*/
if (func_check(getRequestStr('mail'), 'mail')) {
if ($oUserMail = $this->User_GetUserByMail(getRequestStr('mail')) and $oUserMail->getId() != $this->oUserCurrent->getId()) {
$this->Message_AddError($this->Lang_Get('user.settings.account.fields.email.notices.error_used'),
$this->Lang_Get('common.error.error'));
$bError = true;
}
} else {
$this->Message_AddError($this->Lang_Get('fields.email.notices.error'), $this->Lang_Get('common.error.error'));
$bError = true;
}
/**
* Проверка на смену пароля
*/
if (getRequestStr('password', '') != '') {
if (func_check(getRequestStr('password'), 'password', 5)) {
if (getRequestStr('password') == getRequestStr('password_confirm')) {
if ($this->oUserCurrent->verifyPassword(getRequestStr('password_now'))) {
$this->oUserCurrent->setPassword($this->User_MakeHashPassword(getRequestStr('password')));
} else {
$bError = true;
$this->Message_AddError($this->Lang_Get('user.settings.account.fields.password.notices.error'),
$this->Lang_Get('common.error.error'));
}
} else {
$bError = true;
$this->Message_AddError($this->Lang_Get('user.settings.account.fields.password_confirm.notices.error'),
$this->Lang_Get('common.error.error'));
}
} else {
$bError = true;
$this->Message_AddError($this->Lang_Get('user.settings.account.fields.password_new.notices.error'),
$this->Lang_Get('common.error.error'));
}
}
/**
* Ставим дату последнего изменения
*/
$this->oUserCurrent->setProfileDate(date("Y-m-d H:i:s"));
/**
* Запускаем выполнение хуков
*/
$this->Hook_Run('settings_account_save_before',
array('oUser' => $this->oUserCurrent, 'bError' => &$bError));
/**
* Сохраняем изменения
*/
if (!$bError) {
if ($this->User_Update($this->oUserCurrent)) {
$this->Message_AddNoticeSingle($this->Lang_Get('common.success.save'));
/**
* Подтверждение смены емайла
*/
if (getRequestStr('mail') and getRequestStr('mail') != $this->oUserCurrent->getMail()) {
if ($oChangemail = $this->User_MakeUserChangemail($this->oUserCurrent, getRequestStr('mail'))) {
if ($oChangemail->getMailFrom()) {
$this->Message_AddNotice($this->Lang_Get('user.settings.account.fields.email.notices.change_from_notice'));
} else {
$this->Message_AddNotice($this->Lang_Get('user.settings.account.fields.email.notices.change_to_notice'));
}
}
}
$this->Hook_Run('settings_account_save_after', array('oUser' => $this->oUserCurrent));
} else {
$this->Message_AddErrorSingle($this->Lang_Get('common.error.system.base'));
}
}
}
}
/**
* Выводит форму для редактирования профиля и обрабатывает её
*
*/
protected function EventProfile()
{
/**
* Устанавливаем title страницы
*/
$this->Viewer_AddHtmlTitle($this->Lang_Get('user.settings.nav.profile'));
$this->Viewer_Assign('aUserFields', $this->User_getUserFields(''));
$this->Viewer_Assign('aUserFieldsContact', $this->User_getUserFields(array('contact', 'social')));
/**
* Загружаем в шаблон JS текстовки
*/
$this->Lang_AddLangJs(array(
'user.settings.profile.notices.error_max_userfields'
));
/**
* Если нажали кнопку "Сохранить"
*/
if (isPost()) {
$this->Security_ValidateSendForm();
$bError = false;
/**
* Заполняем профиль из полей формы
*/
/**
* Определяем гео-объект
*/
$aGeo = getRequest('geo');
if (isset($aGeo['city']) && $aGeo['city']) {
$oGeoObject = $this->Geo_GetGeoObject('city', (int)$aGeo['city']);
} elseif (isset($aGeo['region']) && $aGeo['region']) {
$oGeoObject = $this->Geo_GetGeoObject('region', (int)$aGeo['region']);
} elseif (isset($aGeo['country']) && $aGeo['country']) {
$oGeoObject = $this->Geo_GetGeoObject('country', (int)$aGeo['country']);
} else {
$oGeoObject = null;
}
/**
* Проверяем имя
*/
if (func_check(getRequestStr('profile_name'), 'text', 2, Config::Get('module.user.name_max'))) {
$this->oUserCurrent->setProfileName(getRequestStr('profile_name'));
} else {
$this->oUserCurrent->setProfileName(null);
}
/**
* Проверяем пол
*/
if (in_array(getRequestStr('profile_sex'), array('man', 'woman', 'other'))) {
$this->oUserCurrent->setProfileSex(getRequestStr('profile_sex'));
} else {
$this->oUserCurrent->setProfileSex('other');
}
/**
* Проверяем дату рождения
*/
$this->oUserCurrent->setProfileBirthday(null);
if ($this->Validate_Validate('date', getRequestStr('profile_birthday'),
array('format' => 'dd.MM.yyyy', 'allowEmpty' => false))
) {
$iBirthdayTime = strtotime(getRequestStr('profile_birthday'));
if ($iBirthdayTime < time() and $iBirthdayTime > strtotime('-100 year')) {
$this->oUserCurrent->setProfileBirthday(date("Y-m-d H:i:s", $iBirthdayTime));
}
}
/**
* Проверяем информацию о себе
*/
if (func_check(getRequestStr('profile_about'), 'text', 1, 3000)) {
$this->oUserCurrent->setProfileAbout($this->Text_Parser(getRequestStr('profile_about')));
} else {
$this->oUserCurrent->setProfileAbout(null);
}
/**
* Ставим дату последнего изменения профиля
*/
$this->oUserCurrent->setProfileDate(date("Y-m-d H:i:s"));
/**
* Запускаем выполнение хуков
*/
$this->Hook_Run('settings_profile_save_before',
array('oUser' => $this->oUserCurrent, 'bError' => &$bError));
/**
* Сохраняем изменения профиля
*/
if (!$bError) {
if ($this->User_Update($this->oUserCurrent)) {
/**
* Создаем связь с гео-объектом
*/
if ($oGeoObject) {
$this->Geo_CreateTarget($oGeoObject, 'user', $this->oUserCurrent->getId());
if ($oCountry = $oGeoObject->getCountry()) {
$this->oUserCurrent->setProfileCountry($oCountry->getName());
} else {
$this->oUserCurrent->setProfileCountry(null);
}
if ($oRegion = $oGeoObject->getRegion()) {
$this->oUserCurrent->setProfileRegion($oRegion->getName());
} else {
$this->oUserCurrent->setProfileRegion(null);
}
if ($oCity = $oGeoObject->getCity()) {
$this->oUserCurrent->setProfileCity($oCity->getName());
} else {
$this->oUserCurrent->setProfileCity(null);
}
} else {
$this->Geo_DeleteTargetsByTarget('user', $this->oUserCurrent->getId());
$this->oUserCurrent->setProfileCountry(null);
$this->oUserCurrent->setProfileRegion(null);
$this->oUserCurrent->setProfileCity(null);
}
$this->User_Update($this->oUserCurrent);
/**
* Обрабатываем дополнительные поля, type = ''
*/
$aFields = $this->User_getUserFields('');
$aData = array();
foreach ($aFields as $iId => $aField) {
if (isset($_REQUEST['profile_user_field_' . $iId])) {
$aData[$iId] = getRequestStr('profile_user_field_' . $iId);
}
}
$this->User_setUserFieldsValues($this->oUserCurrent->getId(), $aData);
/**
* Динамические поля контактов, type = array('contact','social')
*/
$aType = array('contact', 'social');
$aFields = $this->User_getUserFields($aType);
/**
* Удаляем все поля с этим типом
*/
$this->User_DeleteUserFieldValues($this->oUserCurrent->getId(), $aType);
$aFieldsContactType = getRequest('profile_user_field_type');
$aFieldsContactValue = getRequest('profile_user_field_value');
if (is_array($aFieldsContactType)) {
foreach ($aFieldsContactType as $k => $v) {
$v = (string)$v;
if (isset($aFields[$v]) and isset($aFieldsContactValue[$k]) and is_string($aFieldsContactValue[$k])) {
$this->User_setUserFieldsValues($this->oUserCurrent->getId(),
array($v => $aFieldsContactValue[$k]),
Config::Get('module.user.userfield_max_identical'));
}
}
}
$this->Message_AddNoticeSingle($this->Lang_Get('common.success.save'));
$this->Hook_Run('settings_profile_save_after', array('oUser' => $this->oUserCurrent));
} else {
$this->Message_AddErrorSingle($this->Lang_Get('common.error.system.base'));
}
}
}
/**
* Загружаем гео-объект привязки
*/
$oGeoTarget = $this->Geo_GetTargetByTarget('user', $this->oUserCurrent->getId());
$this->Viewer_Assign('oGeoTarget', $oGeoTarget);
/**
* Загружаем в шаблон список стран, регионов, городов
*/
$aCountries = $this->Geo_GetCountries(array(), array('sort' => 'asc'), 1, 300);
$this->Viewer_Assign('aGeoCountries', $aCountries['collection']);
if ($oGeoTarget) {
if ($oGeoTarget->getCountryId()) {
$aRegions = $this->Geo_GetRegions(array('country_id' => $oGeoTarget->getCountryId()),
array('sort' => 'asc'), 1, 500);
$this->Viewer_Assign('aGeoRegions', $aRegions['collection']);
}
if ($oGeoTarget->getRegionId()) {
$aCities = $this->Geo_GetCities(array('region_id' => $oGeoTarget->getRegionId()),
array('sort' => 'asc'), 1, 500);
$this->Viewer_Assign('aGeoCities', $aCities['collection']);
}
}
}
/**
* Выполняется при завершении работы экшена
*
*/
public function EventShutdown()
{
$iCountTopicFavourite = $this->Topic_GetCountTopicsFavouriteByUserId($this->oUserCurrent->getId());
$iCountTopicUser = $this->Topic_GetCountTopicsPersonalByUser($this->oUserCurrent->getId(), 1);
$iCountCommentUser = $this->Comment_GetCountCommentsByUserId($this->oUserCurrent->getId(), 'topic');
$iCountCommentFavourite = $this->Comment_GetCountCommentsFavouriteByUserId($this->oUserCurrent->getId());
$iCountNoteUser = $this->User_GetCountUserNotesByUserId($this->oUserCurrent->getId());
$this->Viewer_Assign('oUserProfile', $this->oUserCurrent);
$this->Viewer_Assign('iCountWallUser',
$this->Wall_GetCountWall(array('wall_user_id' => $this->oUserCurrent->getId(), 'pid' => null)));
/**
* Общее число публикация и избранного
*/
$this->Viewer_Assign('iCountCreated', $iCountNoteUser + $iCountTopicUser + $iCountCommentUser);
$this->Viewer_Assign('iCountFavourite', $iCountCommentFavourite + $iCountTopicFavourite);
$this->Viewer_Assign('iCountFriendsUser', $this->User_GetCountUsersFriend($this->oUserCurrent->getId()));
/**
* Загружаем в шаблон необходимые переменные
*/
$this->Viewer_Assign('sMenuItemSelect', $this->sMenuItemSelect);
$this->Viewer_Assign('sMenuProfileItemSelect', $this->sMenuProfileItemSelect);
$this->Viewer_Assign('sMenuSubItemSelect', $this->sMenuSubItemSelect);
$this->Hook_Run('action_shutdown_settings');
}
}

View file

@ -0,0 +1,356 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Экшен обработки ленты активности
*
* @package application.actions
* @since 1.0
*/
class ActionStream extends Action
{
/**
* Текущий пользователь
*
* @var ModuleUser_EntityUser|null
*/
protected $oUserCurrent;
/**
* Какое меню активно
*
* @var string
*/
protected $sMenuItemSelect = 'user';
/**
* Инициализация
*/
public function Init()
{
$this->oUserCurrent = $this->User_getUserCurrent();
// Личная лента доступна только для авторизованных, гостям показываем общую ленту
if ($this->oUserCurrent) {
$this->SetDefaultEvent('personal');
} else {
$this->SetDefaultEvent('all');
}
$this->Viewer_Assign('sMenuHeadItemSelect', 'stream');
/**
* Загружаем в шаблон JS текстовки
*/
$this->Lang_AddLangJs(array(
'activity.notices.error_already_subscribed',
'error'
));
}
/**
* Регистрация евентов
*/
protected function RegisterEvent()
{
$this->AddEvent('personal', 'EventPersonal');
$this->AddEvent('all', 'EventAll');
$this->AddEvent('subscribe', 'EventSubscribe'); // TODO: возможно нужно удалить
$this->AddEvent('ajaxadduser', 'EventAjaxAddUser');
$this->AddEvent('ajaxremoveuser', 'EventAjaxRemoveUser');
$this->AddEvent('switchEventType', 'EventSwitchEventType');
$this->AddEvent('get_more_all', 'EventGetMoreAll');
$this->AddEvent('get_more_personal', 'EventGetMore');
$this->AddEvent('get_more_user', 'EventGetMoreUser');
}
/**
* Персональная активность
*/
protected function EventPersonal()
{
if (!$this->oUserCurrent) {
return parent::EventNotFound();
}
$this->Viewer_AddBlock('right', 'activitySettings');
$this->Viewer_AddBlock('right', 'activityUsers');
$this->Viewer_Assign('activityEvents', $this->Stream_Read());
$this->Viewer_Assign('activityEventsAllCount', $this->Stream_GetCountByReaderId($this->oUserCurrent->getId()));
}
/**
* Общая активность
*/
protected function EventAll()
{
$this->sMenuItemSelect = 'all';
$this->Viewer_Assign('activityEvents', $this->Stream_ReadAll());
$this->Viewer_Assign('activityEventsAllCount', $this->Stream_GetCountAll());
}
/**
* Активаци/деактивация типа события
*/
protected function EventSwitchEventType()
{
$this->Viewer_SetResponseAjax('json');
if (!$this->oUserCurrent) {
return parent::EventNotFound();
}
if (!getRequest('type')) {
$this->Message_AddError($this->Lang_Get('common.error.system.base'), $this->Lang_Get('common.error.error'));
}
/**
* Активируем/деактивируем тип
*/
$this->Stream_switchUserEventType($this->oUserCurrent->getId(), getRequestStr('type'));
$this->Message_AddNotice($this->Lang_Get('common.success.save'), $this->Lang_Get('common.attention'));
}
/**
* Подгрузка событий (замена постраничности)
*/
protected function EventGetMore()
{
if (!$this->oUserCurrent) {
return parent::EventNotFound();
}
$_this = $this;
$this->GetMore(function ($lastId) use ($_this) {
return $_this->Stream_Read(null, $lastId);
});
}
/**
* Подгрузка событий для всего сайта
*/
protected function EventGetMoreAll()
{
$_this = $this;
$this->GetMore(function ($lastId) use ($_this) {
return $_this->Stream_ReadAll(null, $lastId);
});
}
/**
* Подгрузка событий для пользователя
*/
protected function EventGetMoreUser()
{
$_this = $this;
$this->GetMore(function ($lastId) use ($_this) {
if (!($oUser = $_this->User_GetUserById(getRequestStr('target_id')))) {
return false;
}
return $_this->Stream_ReadByUserId($oUser->getId(), null, $lastId);
});
}
/**
* Общий метод подгрузки событий
*
* @param callback $getEvents Метод возвращающий список событий
*/
protected function GetMore($getEvents)
{
$this->Viewer_SetResponseAjax('json');
// Необходимо передать последний просмотренный ID событий
$iLastId = getRequestStr('last_id');
if (!$iLastId) {
$this->Message_AddError($this->Lang_Get('common.error.system.base'), $this->Lang_Get('common.error.error'));
return;
}
// Получаем события
$aEvents = $getEvents($iLastId);
if ($aEvents === false) {
return $this->EventErrorDebug();
}
$oViewer = $this->Viewer_GetLocalViewer();
$oViewer->Assign('events', $aEvents, true);
if (preg_match('#^\d{4}\-\d{1,2}\-\d{1,2}$#', getRequestStr('date_last'))) {
$oViewer->Assign('dateLast', getRequestStr('date_last'), true);
}
if (count($aEvents)) {
$this->Viewer_AssignAjax('last_id', end($aEvents)->getId(), true);
}
$this->Viewer_AssignAjax('count_loaded', count($aEvents));
$this->Viewer_AssignAjax('html', $oViewer->Fetch('component@activity.event-list'));
}
/**
* Подписка на пользователя по ID
*
*/
protected function EventSubscribe()
{
/**
* Устанавливаем формат Ajax ответа
*/
$this->Viewer_SetResponseAjax('json');
/**
* Пользователь авторизован?
*/
if (!$this->oUserCurrent) {
return parent::EventNotFound();
}
/**
* Проверяем существование пользователя
*/
if (!$this->User_getUserById(getRequestStr('id'))) {
$this->Message_AddError($this->Lang_Get('common.error.system.base'), $this->Lang_Get('common.error.error'));
}
if ($this->oUserCurrent->getId() == getRequestStr('id')) {
$this->Message_AddError($this->Lang_Get('user_list_add.notices.error_self'), $this->Lang_Get('common.error.error'));
return;
}
/**
* Подписываем на пользователя
*/
$this->Stream_subscribeUser($this->oUserCurrent->getId(), getRequestStr('id'));
$this->Message_AddNotice($this->Lang_Get('stream_subscribes_updated'), $this->Lang_Get('common.attention'));
}
/**
* Подписка на пользователя по логину
*/
protected function EventAjaxAddUser()
{
/**
* Устанавливаем формат Ajax ответа
*/
$this->Viewer_SetResponseAjax('json');
$aUsers = getRequest('users', null, 'post');
/**
* Валидация
*/
if (!is_array($aUsers)) {
return $this->EventErrorDebug();
}
/**
* Если пользователь не авторизирован, возвращаем ошибку
*/
if (!$this->User_IsAuthorization()) {
$this->Message_AddErrorSingle($this->Lang_Get('common.error.need_authorization'), $this->Lang_Get('common.error.error'));
return;
}
$aResult = array();
/**
* Обрабатываем добавление по каждому из переданных логинов
*/
foreach ($aUsers as $iUserId) {
$iUserId = (int)$iUserId;
if (!$iUserId) {
continue;
}
/**
* Если пользователь не найден или неактивен, возвращаем ошибку
*/
if ($oUser = $this->User_GetUserById($iUserId) and $oUser->getActivate() == 1) {
$this->Stream_subscribeUser($this->oUserCurrent->getId(), $oUser->getId());
$oViewer = $this->Viewer_GetLocalViewer();
$oViewer->Assign('user', $oUser, true);
$oViewer->Assign('showActions', true, true);
$aResult[] = array(
'bStateError' => false,
'sMsgTitle' => $this->Lang_Get('common.attention'),
'sMsg' => $this->Lang_Get('common.success.add', array('login' => $oUser->getLogin())),
'user_id' => $oUser->getId(),
'user_login' => $oUser->getLogin(),
'html' => $oViewer->Fetch("component@user-list-add.item")
);
} else {
$aResult[] = array(
'bStateError' => true,
'sMsgTitle' => $this->Lang_Get('common.error.error'),
'sMsg' => $this->Lang_Get('user.notices.not_found_by_id', array('id' => $iUserId))
);
}
}
/**
* Передаем во вьевер массив с результатами обработки по каждому пользователю
*/
$this->Viewer_AssignAjax('users', $aResult);
}
/**
* Отписка от пользователя
*/
protected function EventAjaxRemoveUser()
{
$iUserId = (int)getRequestStr('user_id');
/**
* Устанавливаем формат Ajax ответа
*/
$this->Viewer_SetResponseAjax('json');
/**
* Пользователь авторизован?
*/
if (!$this->oUserCurrent) {
return $this->EventErrorDebug();
}
/**
* Пользователь с таким ID существует?
*/
if (!$this->User_GetUserById($iUserId)) {
return $this->EventErrorDebug();
}
/**
* Отписываем
*/
$this->Stream_unsubscribeUser($this->oUserCurrent->getId(), $iUserId);
$this->Message_AddNotice($this->Lang_Get('common.success.remove'), $this->Lang_Get('common.attention'));
}
/**
* Выполняется при завершении работы экшена
*/
public function EventShutdown()
{
/**
* Загружаем в шаблон необходимые переменные
*/
$this->Viewer_Assign('sMenuItemSelect', $this->sMenuItemSelect);
}
}

View file

@ -0,0 +1,147 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Экшен обработки подписок пользователей
*
* @package application.actions
* @since 1.0
*/
class ActionSubscribe extends Action
{
/**
* Текущий пользователь
*
* @var ModuleUser_EntityUser|null
*/
protected $oUserCurrent = null;
/**
* Инициализация
*
*/
public function Init()
{
$this->oUserCurrent = $this->User_GetUserCurrent();
}
/**
* Регистрация евентов
*
*/
protected function RegisterEvent()
{
$this->AddEventPreg('/^unsubscribe$/i', '/^\w{32}$/i', 'EventUnsubscribe');
$this->AddEvent('ajax-subscribe-toggle', 'EventAjaxSubscribeToggle');
}
/**********************************************************************************
************************ РЕАЛИЗАЦИЯ ЭКШЕНА ***************************************
**********************************************************************************
*/
/**
* Отписка от подписки
*/
protected function EventUnsubscribe()
{
/**
* Получаем подписку по ключу
*/
if ($oSubscribe = $this->Subscribe_GetSubscribeByKey($this->getParam(0)) and $oSubscribe->getStatus() == 1) {
/**
* Отписываем пользователя
*/
$oSubscribe->setStatus(0);
$oSubscribe->setDateRemove(date("Y-m-d H:i:s"));
$this->Subscribe_UpdateSubscribe($oSubscribe);
$this->Message_AddNotice($this->Lang_Get('common.success.save'), null, true);
}
/**
* Получаем URL для редиректа
*/
if ((!$sUrl = $this->Subscribe_GetUrlTarget($oSubscribe->getTargetType(), $oSubscribe->getTargetId()))) {
$sUrl = Router::GetPath('index');
}
Router::Location($sUrl);
}
/**
* Изменение состояния подписки
*/
protected function EventAjaxSubscribeToggle()
{
/**
* Устанавливаем формат Ajax ответа
*/
$this->Viewer_SetResponseAjax('json');
/**
* Получаем емайл подписки и проверяем его на валидность
*/
$sMail = getRequestStr('mail');
if ($this->oUserCurrent) {
$sMail = $this->oUserCurrent->getMail();
}
if (!func_check($sMail, 'mail')) {
$this->Message_AddError($this->Lang_Get('field.email.notices.error'), $this->Lang_Get('common.error.error'));
return;
}
/**
* Получаем тип объекта подписки
*/
$sTargetType = getRequestStr('target_type');
if (!$this->Subscribe_IsAllowTargetType($sTargetType)) {
return $this->EventErrorDebug();
}
$sTargetId = getRequestStr('target_id') ? getRequestStr('target_id') : null;
$iValue = getRequest('value') ? 1 : 0;
$oSubscribe = null;
/**
* Есть ли доступ к подписке гостям?
*/
if (!$this->oUserCurrent and !$this->Subscribe_IsAllowTargetForGuest($sTargetType)) {
$this->Message_AddError($this->Lang_Get('common.error.need_authorization'), $this->Lang_Get('common.error.error'));
return;
}
/**
* Проверка объекта подписки
*/
if (!$this->Subscribe_CheckTarget($sTargetType, $sTargetId, $iValue)) {
return $this->EventErrorDebug();
}
/**
* Если подписка еще не существовала, то создаем её
*/
if ($oSubscribe = $this->Subscribe_AddSubscribeSimple($sTargetType, $sTargetId, $sMail,
$this->oUserCurrent ? $this->oUserCurrent->getId() : null)
) {
$oSubscribe->setStatus($iValue);
$this->Subscribe_UpdateSubscribe($oSubscribe);
$this->Message_AddNotice($this->Lang_Get('common.success.save'), $this->Lang_Get('common.attention'));
return;
}
return $this->EventErrorDebug();
}
}

View file

@ -0,0 +1,119 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Экшен обработки поиска по тегам
*
* @package application.actions
* @since 1.0
*/
class ActionTag extends Action
{
/**
* Главное меню
*
* @var string
*/
protected $sMenuHeadItemSelect = 'blog';
/**
* Инициализация
*
*/
public function Init()
{
}
/**
* Регистрация евентов
*/
protected function RegisterEvent()
{
$this->AddEventPreg('/^.+$/i', '/^(page([1-9]\d{0,5}))?$/i', 'EventTags');
}
/**********************************************************************************
************************ РЕАЛИЗАЦИЯ ЭКШЕНА ***************************************
**********************************************************************************
*/
/**
* Отображение топиков
*
*/
protected function EventTags()
{
/**
* Получаем тег из УРЛа
*/
$sTag = $this->sCurrentEvent;
/**
* Передан ли номер страницы
*/
$iPage = $this->GetParamEventMatch(0, 2) ? $this->GetParamEventMatch(0, 2) : 1;
/**
* Получаем список топиков
*/
$aResult = $this->Topic_GetTopicsByTag($sTag, $iPage, Config::Get('module.topic.per_page'));
$aTopics = $aResult['collection'];
/**
* Вызов хуков
*/
$this->Hook_Run('topics_list_show', array('aTopics' => $aTopics));
/**
* Формируем постраничность
*/
$aPaging = $this->Viewer_MakePaging($aResult['count'], $iPage, Config::Get('module.topic.per_page'),
Config::Get('pagination.pages.count'), Router::GetPath('tag') . htmlspecialchars($sTag));
/**
* Загружаем переменные в шаблон
*/
$this->Viewer_Assign('paging', $aPaging);
$this->Viewer_Assign('topics', $aTopics);
$this->Viewer_Assign('tag', $sTag);
$this->Viewer_AddHtmlTitle($this->Lang_Get('tag_title'));
$this->Viewer_AddHtmlTitle($sTag);
$this->Viewer_SetHtmlRssAlternate(Router::GetPath('rss') . 'tag/' . $sTag . '/', $sTag);
/**
* Если не удалось найти топиков, то ыставляем 404 заголовок
*/
if (!count($aTopics)) {
header("HTTP/1.1 404 Not Found");
}
/**
* Устанавливаем шаблон вывода
*/
$this->SetTemplateAction('index');
}
/**
* Выполняется при завершении работы экшена
*
*/
public function EventShutdown()
{
/**
* Загружаем в шаблон необходимые переменные
*/
$this->Viewer_Assign('sMenuHeadItemSelect', $this->sMenuHeadItemSelect);
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,281 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Обрабатывает пользовательские ленты контента
*
* @package application.actions
* @since 1.0
*/
class ActionUserfeed extends Action
{
/**
* Текущий пользователь
*
* @var ModuleUser_EntityUser|null
*/
protected $oUserCurrent;
/**
* Инициализация
*
*/
public function Init()
{
/**
* Доступ только у авторизованных пользователей
*/
$this->oUserCurrent = $this->User_getUserCurrent();
if (!$this->oUserCurrent) {
parent::EventNotFound();
}
$this->Viewer_Assign('sMenuItemSelect', 'feed');
}
/**
* Регистрация евентов
*
*/
protected function RegisterEvent()
{
$this->AddEventPreg('/^(page([1-9]\d{0,5}))?$/i', 'EventIndex');
$this->AddEvent('subscribe', 'EventSubscribe');
$this->AddEvent('ajaxadduser', 'EventAjaxAddUser');
$this->AddEvent('unsubscribe', 'EventUnSubscribe');
}
/**
* Выводит ленту контента(топики) для пользователя
*
*/
protected function EventIndex()
{
/**
* Передан ли номер страницы
*/
$iPage = $this->GetEventMatch(2) ? $this->GetEventMatch(2) : 1;
$aResult = $this->Userfeed_read($this->oUserCurrent->getId(),$iPage,Config::Get('module.topic.per_page'));
$aTopics = $aResult['collection'];
// Вызов хуков
$this->Hook_Run('topics_list_show', array('aTopics' => $aTopics));
/**
* Формируем постраничность
*/
$aPaging = $this->Viewer_MakePaging($aResult['count'], $iPage, Config::Get('module.topic.per_page'),
Config::Get('pagination.pages.count'), Router::GetPath('feed'));
/**
* Загружаем переменные в шаблон
*/
$this->Viewer_Assign('topics', $aTopics);
$this->Viewer_Assign('paging', $aPaging);
$this->SetTemplateAction('list');
}
/**
* Подписка на контент блога или пользователя
*
*/
protected function EventSubscribe()
{
/**
* Устанавливаем формат Ajax ответа
*/
$this->Viewer_SetResponseAjax('json');
/**
* Проверяем наличие ID блога или пользователя
*/
if (!getRequest('id')) {
$this->Message_AddError($this->Lang_Get('common.error.system.base'), $this->Lang_Get('common.error.error'));
}
$sType = getRequestStr('type');
$iType = null;
/**
* Определяем тип подписки
*/
switch ($sType) {
case 'blogs':
$iType = ModuleUserfeed::SUBSCRIBE_TYPE_BLOG;
/**
* Проверяем существование блога
*/
if (!($oBlog=$this->Blog_GetBlogById(getRequestStr('id'))) or !$this->ACL_IsAllowShowBlog($oBlog,$this->oUserCurrent)) {
$this->Message_AddError($this->Lang_Get('common.error.system.base'), $this->Lang_Get('common.error.error'));
return;
}
break;
case 'users':
$iType = ModuleUserfeed::SUBSCRIBE_TYPE_USER;
/**
* Проверяем существование пользователя
*/
if (!$this->User_GetUserById(getRequestStr('id'))) {
$this->Message_AddError($this->Lang_Get('common.error.system.base'), $this->Lang_Get('common.error.error'));
return;
}
if ($this->oUserCurrent->getId() == getRequestStr('id')) {
$this->Message_AddError($this->Lang_Get('user_list_add.notices.error_self'),
$this->Lang_Get('common.error.error'));
return;
}
break;
default:
$this->Message_AddError($this->Lang_Get('common.error.system.base'), $this->Lang_Get('common.error.error'));
return;
}
/**
* Подписываем
*/
$this->Userfeed_subscribeUser($this->oUserCurrent->getId(), $iType, getRequestStr('id'));
$this->Message_AddNotice($this->Lang_Get('common.success.save'), $this->Lang_Get('common.attention'));
}
/**
* Подписка на пользвователя по логину
*
*/
protected function EventAjaxAddUser()
{
/**
* Устанавливаем формат Ajax ответа
*/
$this->Viewer_SetResponseAjax('json');
$aUsers = getRequest('users', null, 'post');
/**
* Валидация
*/
if (!is_array($aUsers)) {
return $this->EventErrorDebug();
}
/**
* Если пользователь не авторизирован, возвращаем ошибку
*/
if (!$this->User_IsAuthorization()) {
$this->Message_AddErrorSingle($this->Lang_Get('common.error.need_authorization'), $this->Lang_Get('common.error.error'));
return;
}
$aResult = array();
/**
* Обрабатываем добавление по каждому из переданных логинов
*/
foreach ($aUsers as $iUserId) {
$iUserId = (int) $iUserId;
if (!$iUserId) {
continue;
}
/**
* Если пользователь не найден или неактивен, возвращаем ошибку
*/
if ($oUser = $this->User_GetUserById($iUserId) and $oUser->getActivate() == 1) {
$this->Userfeed_subscribeUser($this->oUserCurrent->getId(), ModuleUserfeed::SUBSCRIBE_TYPE_USER,
$oUser->getId());
$oViewer = $this->Viewer_GetLocalViewer();
$oViewer->Assign('user', $oUser, true);
$oViewer->Assign('showActions', true, true);
$aResult[] = array(
'bStateError' => false,
'sMsgTitle' => $this->Lang_Get('common.attention'),
'sMsg' => $this->Lang_Get('common.success.add', array('login' => $oUser->getLogin())),
'user_id' => $oUser->getId(),
'user_login' => $oUser->getLogin(),
'html' => $oViewer->Fetch("component@user-list-add.item")
);
} else {
$aResult[] = array(
'bStateError' => true,
'sMsgTitle' => $this->Lang_Get('common.error.error'),
'sMsg' => $this->Lang_Get('user.notices.not_found_by_id', array('id' => $iUserId))
);
}
}
/**
* Передаем во вьевер массив с результатами обработки по каждому пользователю
*/
$this->Viewer_AssignAjax('users', $aResult);
}
/**
* Отписка от блога или пользователя
*
*/
protected function EventUnsubscribe()
{
/**
* Устанавливаем формат Ajax ответа
*/
$this->Viewer_SetResponseAjax('json');
$sId = getRequestStr('id');
$sType = getRequestStr('type');
$iType = null;
/**
* Определяем от чего отписываемся
*/
switch ($sType) {
case 'blogs':
$iType = ModuleUserfeed::SUBSCRIBE_TYPE_BLOG;
break;
case 'users':
$iType = ModuleUserfeed::SUBSCRIBE_TYPE_USER;
$sId = getRequestStr('user_id');
break;
default:
$this->Message_AddError($this->Lang_Get('common.error.system.base'), $this->Lang_Get('common.error.error'));
return;
}
if (!$sId) {
$this->Message_AddError($this->Lang_Get('common.error.system.base'), $this->Lang_Get('common.error.error'));
return;
}
/**
* Отписываем пользователя
*/
$this->Userfeed_unsubscribeUser($this->oUserCurrent->getId(), $iType, $sId);
$this->Message_AddNotice($this->Lang_Get('common.success.remove'), $this->Lang_Get('common.attention'));
}
/**
* При завершении экшена загружаем в шаблон необходимые переменные
*
*/
public function EventShutdown()
{
/**
* Подсчитываем новые топики
*/
$iCountTopicsCollectiveNew = $this->Topic_GetCountTopicsCollectiveNew();
$iCountTopicsPersonalNew = $this->Topic_GetCountTopicsPersonalNew();
$iCountTopicsNew = $iCountTopicsCollectiveNew + $iCountTopicsPersonalNew;
/**
* Загружаем переменные в шаблон
*/
$this->Viewer_Assign('iCountTopicsCollectiveNew', $iCountTopicsCollectiveNew);
$this->Viewer_Assign('iCountTopicsPersonalNew', $iCountTopicsPersonalNew);
$this->Viewer_Assign('iCountTopicsNew', $iCountTopicsNew);
}
}

View file

@ -0,0 +1,47 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Обработка блока с топиками (прямой эфир)
*
* @package application.blocks
* @since 1.0
*/
class BlockActivityRecent extends Block
{
/**
* Запуск обработки
*/
public function Exec()
{
/**
* Получаем топики
*/
if ($oTopics = $this->Topic_GetTopicsLast(Config::Get('block.stream.row'))) {
$oViewer = $this->Viewer_GetLocalViewer();
$oViewer->Assign('topics', $oTopics, true);
$sTextResult = $oViewer->Fetch("component@activity.recent-topics");
$this->Viewer_Assign('content', $sTextResult, true);
}
$this->SetTemplate('component@activity.block.recent');
}
}

View file

@ -0,0 +1,45 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Блок настройки ленты активности
*
* @package application.blocks
* @since 1.0
*/
class BlockActivitySettings extends Block
{
/**
* Запуск обработки
*/
public function Exec()
{
/**
* пользователь авторизован?
*/
if ($oUserCurrent = $this->User_getUserCurrent()) {
$this->Viewer_Assign('types', $this->Stream_getEventTypes());
$this->Viewer_Assign('typesActive', $this->Stream_getTypesList($oUserCurrent->getId()));
}
$this->SetTemplate('component@activity.block.settings');
}
}

View file

@ -0,0 +1,44 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Блок выбора пользователей для чтения в ленте активности
*
* @package application.blocks
* @since 1.0
*/
class BlockActivityUsers extends Block
{
/**
* Запуск обработки
*/
public function Exec()
{
/**
* пользователь авторизован?
*/
if ($oUserCurrent = $this->User_getUserCurrent()) {
$this->Viewer_Assign('users', $this->Stream_getUserSubscribes($oUserCurrent->getId()));
}
$this->SetTemplate('component@activity.block.users');
}
}

View file

@ -0,0 +1,51 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Обработка блока с рейтингом блогов
*
* @package application.blocks
* @since 1.0
*/
class BlockBlogs extends Block
{
/**
* Запуск обработки
*/
public function Exec()
{
/**
* Получаем список блогов
*/
if ($aResult = $this->Blog_GetBlogsRating(1, Config::Get('block.blogs.row'))) {
$aBlogs = $aResult['collection'];
$oViewer = $this->Viewer_GetLocalViewer();
$oViewer->Assign('aBlogs', $aBlogs);
/**
* Формируем результат в виде шаблона и возвращаем
*/
$sTextResult = $oViewer->Fetch("component@blog.top");
$this->Viewer_Assign('sBlogsTop', $sTextResult);
}
$this->SetTemplate('component@blog.block.blogs');
}
}

View file

@ -0,0 +1,44 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Обрабатывает блок категорий для блогов
*
* @package application.blocks
* @since 2.0
*/
class BlockBlogsSearch extends Block
{
/**
* Запуск обработки
*/
public function Exec()
{
if (!Config::Get('module.blog.category_allow')) {
return;
}
$aCategories = $this->Blog_GetCategoriesTree();
$aBlogsAll = $this->Blog_GetBlogsByFilter(array('exclude_type' => 'personal'), array(), 1, 1, array());
$this->Viewer_Assign('aBlogCategories', $aCategories);
$this->Viewer_Assign('iCountBlogsAll', $aBlogsAll['count']);
$this->SetTemplate('component@blog.block.search');
}
}

View file

@ -0,0 +1,72 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Обработка блока с редактированием категорий объекта
*
* @package application.blocks
* @since 2.0
*/
class BlockFieldCategory extends Block
{
/**
* Запуск обработки
*/
public function Exec()
{
$sEntity = $this->GetParam('entity');
$oTarget = $this->GetParam('target');
$sTargetType = $this->GetParam('target_type');
if (!$oTarget) {
$oTarget = Engine::GetEntity($sEntity);
}
$aBehaviors = $oTarget->GetBehaviors();
foreach ($aBehaviors as $oBehavior) {
if ($oBehavior instanceof ModuleCategory_BehaviorEntity) {
/**
* Если в параметрах был тип, то переопределяем значение. Это необходимо для корректной работы, когда тип динамический.
*/
if ($sTargetType) {
$oBehavior->setParam('target_type', $sTargetType);
}
/**
* Нужное нам поведение - получаем список текущих категорий
*/
$this->Viewer_Assign('categoriesSelected', $oBehavior->getCategories(), true);
/**
* Загружаем параметры
*/
$aParams = $oBehavior->getParams();
$this->Viewer_Assign('params', $aParams, true);
/**
* Загружаем список доступных категорий
*/
$this->Viewer_Assign('categories',
$this->Category_GetCategoriesTreeByTargetType($oBehavior->getCategoryTargetType()), true);
break;
}
}
$this->SetTemplate('component@field.category');
}
}

View file

@ -0,0 +1,72 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2018 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Oleg Demodov <boxmilo@gmail.com>
*
*/
/**
* Description of BlockMenu
*
* @author oleg
*/
class BlockMenu extends Block {
public function Exec() {
$sNameMenu = $this->GetParam('name');
if(!$oMenu = $this->Menu_Get($sNameMenu)){
return false;
}
$this->Hook_Run('menu_before_prepare', ['menu' => &$oMenu]);
$ItemsTree = $this->prepareItems($oMenu->getItems());
$this->Hook_Run('menu_after_prepare', ['items' => &$ItemsTree['items']]);
$this->Viewer_Assign('activeItem', $this->GetParam('activeItem', null), true);
$this->Viewer_Assign('mods', $this->GetParam('mods', null), true);
$this->Viewer_Assign('classes', $this->GetParam('classes', null), true);
$this->Viewer_Assign('template', $this->GetParam('template', $sNameMenu), true);
$this->Viewer_Assign('params', $ItemsTree);
$this->SetTemplate("component@menu");
}
public function prepareItems($ItemsTree) {
if( !is_array($ItemsTree) or !count($ItemsTree) ){
return null;
}
$aItemsNav = [];
foreach ($ItemsTree as $ItemTree) {
$aChildrens = $ItemTree->getChildren();
$aItemsNav[] = [
'url' => Router::GetPath( $ItemTree->getUrl() ),
'name' => $ItemTree->getName(),
'text' => $this->Lang_Get($ItemTree->getTitle()),
'count' => $ItemTree->getCount(),
'is_enabled' => $ItemTree->getEnable(),
'menu' => $this->prepareItems( $aChildrens )
];
}
return [ 'items' => $aItemsNav];
}
}

View file

@ -0,0 +1,59 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Используется для вывода списка опросов в форме редактирования объекта
*
* @package application.blocks
* @since 2.0
*/
class BlockPollFormItems extends Block
{
/**
* Запуск обработки
*/
public function Exec()
{
$this->SetTemplate('component@poll.manage.list');
$sTargetType = $this->GetParam('target_type');
$sTargetId = $this->GetParam('target_id');
$sTargetTmp = $this->Session_GetCookie('poll_target_tmp_' . $sTargetType) ? $this->Session_GetCookie('poll_target_tmp_' . $sTargetType) : $this->GetParam('target_tmp');
$aFilter = array('target_type' => $sTargetType, '#order' => array('id' => 'asc'));
if ($sTargetId) {
$sTargetTmp = null;
if (!$this->Poll_CheckTarget($sTargetType, $sTargetId)) {
return false;
}
$aFilter['target_id'] = $sTargetId;
} else {
$sTargetId = null;
if (!$sTargetTmp or !$this->Poll_IsAllowTargetType($sTargetType)) {
return true; // показываем список, но пустой
}
$aFilter['target_tmp'] = $sTargetTmp;
}
$aPollItems = $this->Poll_GetPollItemsByFilter($aFilter);
$this->Viewer_Assign('aPollItems', $aPollItems);
}
}

View file

@ -0,0 +1,64 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Обработка блока с редактированием свойств объекта
*
* @package application.blocks
* @since 2.0
*/
class BlockPropertyUpdate extends Block
{
/**
* Запуск обработки
*/
public function Exec()
{
$sEntity = $this->GetParam('entity');
$oTarget = $this->GetParam('target');
$sTargetType = $this->GetParam('target_type');
if (!$oTarget) {
$oTarget = Engine::GetEntity($sEntity);
}
$aBehaviors = $oTarget->GetBehaviors();
foreach ($aBehaviors as $oBehavior) {
/**
* Определяем нужное нам поведение
*/
if ($oBehavior instanceof ModuleProperty_BehaviorEntity) {
/**
* Если в параметрах был тип, то переопределяем значение. Это необходимо для корректной работы, когда тип динамический.
*/
if ($sTargetType) {
$oBehavior->setParam('target_type', $sTargetType);
}
$aProperties = $this->Property_GetPropertiesForUpdate($oBehavior->getPropertyTargetType(),
$oTarget->getId());
$this->Viewer_Assign('properties', $aProperties, true);
break;
}
}
$this->SetTemplate('component@property.input.list');
}
}

View file

@ -0,0 +1,60 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Обрабатывает блок облака тегов для избранного
*
* @package application.blocks
* @since 1.0
*/
class BlockTagsPersonalTopic extends Block
{
/**
* Запуск обработки
*/
public function Exec()
{
/**
* Пользователь авторизован?
*/
if ($oUserCurrent = $this->User_getUserCurrent()) {
if (!($oUser = $this->getParam('user'))) {
$oUser = $oUserCurrent;
}
/**
* Получаем список тегов пользователя
*/
$aTags = $this->Favourite_GetGroupTags($oUser->getId(), 'topic', true, 70);
/**
* Расчитываем логарифмическое облако тегов
*/
$this->Tools_MakeCloud($aTags);
/**
* Устанавливаем шаблон вывода
*/
$this->Viewer_Assign('tags', $aTags, true);
$this->Viewer_Assign('user', $oUser, true);
$this->Viewer_Assign('activeTag', $this->getParam('activeTag'), true);
$this->SetTemplate('component@tags-personal.cloud');
}
}
}

View file

@ -0,0 +1,69 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Обрабатывает блок облака тегов
*
* @package application.blocks
* @since 1.0
*/
class BlockTopicsTags extends Block
{
/**
* Запуск обработки
*/
public function Exec()
{
/**
* Получаем список тегов
*/
$aTags = $this->Topic_GetOpenTopicTags(Config::Get('block.tags.tags_count'));
/**
* Расчитываем логарифмическое облако тегов
*/
if ($aTags) {
$this->Tools_MakeCloud($aTags);
/**
* Устанавливаем шаблон вывода
*/
$this->Viewer_Assign('tags', $aTags, true);
}
/**
* Теги пользователя
*/
if ($oUserCurrent = $this->User_getUserCurrent()) {
$aTags = $this->Topic_GetOpenTopicTags(Config::Get('block.tags.personal_tags_count'),
$oUserCurrent->getId());
/**
* Расчитываем логарифмическое облако тегов
*/
if ($aTags) {
$this->Tools_MakeCloud($aTags);
/**
* Устанавливаем шаблон вывода
*/
$this->Viewer_Assign('tagsUser', $aTags, true);
}
}
$this->SetTemplate('component@topic.block.tags');
}
}

View file

@ -0,0 +1,65 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Блок настройки списка блогов в ленте
*
* @package application.blocks
* @since 1.0
*/
class BlockUserfeedBlogs extends Block
{
/**
* Запуск обработки
*/
public function Exec()
{
/**
* Пользователь авторизован?
*/
if ($oUserCurrent = $this->User_getUserCurrent()) {
$aUserSubscribes = $this->Userfeed_getUserSubscribes($oUserCurrent->getId());
/**
* Получаем список ID блогов, в которых состоит пользователь
*/
$aBlogsId = $this->Blog_GetBlogUsersByUserId($oUserCurrent->getId(), array(
ModuleBlog::BLOG_USER_ROLE_USER,
ModuleBlog::BLOG_USER_ROLE_MODERATOR,
ModuleBlog::BLOG_USER_ROLE_ADMINISTRATOR
), true);
/**
* Получаем список ID блогов, которые создал пользователь
*/
$aBlogsOwnerId = $this->Blog_GetBlogsByOwnerId($oUserCurrent->getId(), true);
$aBlogsId = array_merge($aBlogsId, $aBlogsOwnerId);
$aBlogs = $this->Blog_GetBlogsAdditionalData($aBlogsId, array('owner' => array()),
array('blog_title' => 'asc'));
/**
* Выводим в шаблон
*/
$this->Viewer_Assign('blogsSubscribed', $aUserSubscribes['blogs']);
$this->Viewer_Assign('blogsJoined', $aBlogs);
}
$this->SetTemplate('component@feed.block.blogs');
}
}

View file

@ -0,0 +1,48 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Блок настройки списка пользователей в ленте
*
* @package application.blocks
* @since 1.0
*/
class BlockUserfeedUsers extends Block
{
/**
* Запуск обработки
*/
public function Exec()
{
/**
* Пользователь авторизован?
*/
if ($oUserCurrent = $this->User_getUserCurrent()) {
/**
* Получаем необходимые переменные и прогружаем в шаблон
*/
$aResult = $this->Userfeed_getUserSubscribes($oUserCurrent->getId());
$this->Viewer_Assign('users', $aResult['users']);
}
$this->SetTemplate('component@feed.block.users');
}
}

View file

@ -0,0 +1,51 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Стена
*
* @package application.blocks
* @since 2.0
*/
class BlockWall extends Block
{
/**
* Запуск обработки
*/
public function Exec()
{
$wall = $this->Wall_GetWall(array('wall_user_id' => (int)$this->GetParam('user_id'), 'pid' => null),
array('id' => 'desc'), 1, Config::Get('module.wall.per_page'));
$posts = $wall['collection'];
$this->Viewer_Assign('posts', $posts, true);
$this->Viewer_Assign('count', $wall['count'], true);
$this->Viewer_Assign('classes', $this->GetParam('classes'), true);
$this->Viewer_Assign('attributes', $this->GetParam('attributes'), true);
$this->Viewer_Assign('mods', $this->GetParam('mods'), true);
if (count($posts)) {
$this->Viewer_Assign('lastId', end($posts)->getId(), true);
}
$this->SetTemplate('component@wall.wall');
}
}

View file

@ -0,0 +1,47 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Регистрация хука для вывода ссылки копирайта
*
* @package application.hooks
* @since 1.0
*/
class HookCopyright extends Hook
{
/**
* Регистрируем хуки
*/
public function RegisterHook()
{
$this->AddHook('template_copyright', 'CopyrightLink', __CLASS__, -100);
}
/**
* Обработка хука копирайта
*
* @return string
*/
public function CopyrightLink()
{
return '&copy; Powered by <a href="https://catalog.livestreetcms.com">LiveStreet CMS</a>';
}
}

View file

@ -0,0 +1,150 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Регистрация основных хуков
*
* @package application.hooks
* @since 1.0
*/
class HookMain extends Hook
{
/**
* Регистрируем хуки
*/
public function RegisterHook()
{
$this->AddHook('init_action', 'InitAction', __CLASS__, 1000);
$this->AddHook('start_action', 'StartAction', __CLASS__, 1000);
}
/**
* Обработка хука инициализации экшенов
* Может выполняться несколько раз, например, при использовании внутренних реврайтов
*/
public function InitAction()
{
/**
* Проверка на закрытый режим
*/
$oUserCurrent = $this->User_GetUserCurrent();
if (!$oUserCurrent and Config::Get('general.close') and !Router::CheckIsCurrentAction((array)Config::Get('general.close_exceptions'))) {
Router::Action('auth/login');
}
}
/**
* Обработка запуска экшена
* Выполняется всегда только один раз
*/
public function StartAction()
{
$this->LoadDefaultJsVarAndLang();
/**
* Обработка сайтмапа
*/
$this->Sitemap_AddTargetType('general', array(
'callback_counters' => function () {
return 1;
},
'callback_data' => function () {
return array(
$this->Sitemap_GetDataForSitemapRow(Router::GetPath('/'), time(), Config::Get('module.sitemap.index.priority'),
Config::Get('module.sitemap.index.changefreq')),
$this->Sitemap_GetDataForSitemapRow(Router::GetPath('stream/all'), time(), Config::Get('module.sitemap.stream.priority'),
Config::Get('module.sitemap.stream.changefreq')),
);
}
));
$this->Topic_RegisterSitemap();
$this->Blog_RegisterSitemap();
$this->User_RegisterSitemap();
/**
* Запуск обработки сборщика
*/
$this->Ls_SenderRun();
}
/**
* Загрузка необходимых переменных и текстовок в шаблон
*/
public function LoadDefaultJsVarAndLang()
{
/**
* Загружаем JS переменные
*/
$this->Viewer_AssignJs(
array(
'recaptcha.site_key' => Config::Get('module.validate.recaptcha.site_key'),
'comment_max_tree' => Config::Get('module.comment.max_tree'),
'comment_show_form' => Config::Get('module.comment.show_form'),
'comment_use_paging' => Config::Get('module.comment.use_nested'),
'topic_max_blog_count' => Config::Get('module.topic.max_blog_count'),
'block_stream_show_tip' => Config::Get('block.stream.show_tip'),
'poll_max_answers' => Config::Get('module.poll.max_answers'),
)
);
/**
* Загрузка языковых текстовок
*/
$this->Lang_AddLangJs(array(
'comments.comments_declension',
'comments.unsubscribe',
'comments.subscribe',
'comments.folding.unfold',
'comments.folding.fold',
'comments.folding.unfold_all',
'comments.folding.fold_all',
'poll.notices.error_answers_max',
'favourite.add',
'favourite.remove',
'field.geo.select_city',
'field.geo.select_region',
'blog.blog',
'blog.add.fields.type.note_open',
'blog.add.fields.type.note_close',
'blog.search.result_title',
'blog.blocks.navigator.blog',
'common.success.add',
'common.success.remove',
'common.remove_confirm',
'pagination.notices.first',
'pagination.notices.last',
'user.actions.unfollow',
'user.actions.follow',
'user.friends.status.added',
'user.friends.status.notfriends',
'user.friends.status.pending',
'user.friends.status.rejected',
'user.friends.status.sent',
'user.friends.status.linked',
'user.settings.profile.notices.error_max_userfields',
'user.search.result_title',
'more.text',
'more.text_count',
'more.empty',
'validate.tags.count',
'uploader.attach.count',
'uploader.attach.empty'
));
}
}

View file

@ -0,0 +1,67 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Регистрация хука для вывода статистики производительности
*
* @package application.hooks
* @since 1.0
*/
class HookStatisticsPerformance extends Hook
{
/**
* Регистрируем хуки
*/
public function RegisterHook()
{
$this->AddHook('template_body_end', 'Statistics', __CLASS__, -1000);
}
/**
* Обработка хука перед закрывающим тегом body
*
* @return string
*/
public function Statistics()
{
if (!$this->User_GetIsAdmin()) {
return '';
}
$oEngine = Engine::getInstance();
/**
* Подсчитываем время выполнения
*/
$iTimeInit = $oEngine->GetTimeInit();
$iTimeFull = round(microtime(true) - $iTimeInit, 3);
$this->Viewer_Assign('timeFullPerformance', $iTimeFull, true);
/**
* Получаем статистику по кешу и БД
*/
$aStats = $oEngine->getStats();
$aStats['cache']['time'] = round($aStats['cache']['time'], 5);
$this->Viewer_Assign('stats', $aStats, true);
$this->Viewer_Assign('bIsShowStatsPerformance', Router::GetIsShowStats());
/**
* В ответ рендерим шаблон статистики
*/
return $this->Viewer_Fetch('component@performance.performance');
}
}

View file

@ -0,0 +1,826 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* ACL(Access Control List)
* Модуль для разруливания ограничений по карме/рейтингу юзера
*
* @package application.modules.acl
* @since 1.0
*/
class ModuleACL extends Module
{
/**
* Коды механизма удаления блога
*/
const CAN_DELETE_BLOG_EMPTY_ONLY = 1;
const CAN_DELETE_BLOG_WITH_TOPICS = 2;
/**
* Инициализация модуля
*
*/
public function Init()
{
}
/**
* Проверяет может ли пользователь создавать блоги
*
* @param ModuleUser_EntityUser $oUser Пользователь
* @return bool
*/
public function CanCreateBlog($oUser)
{
$that = $this; // fix for PHP < 5.4
return $this->Rbac_IsAllowUser($oUser, 'create_blog', array(
'callback' => function ($oUser, $aParams) use ($that) {
if (!$oUser) {
return false;
}
if (!$oUser->isAllowCreateBlog()) {
return $that->Lang_Get('blog.add.alerts.acl');
}
return true;
}
));
}
/**
* Проверяет может ли пользователь создавать топики
*
* @param ModuleUser_EntityUser $oUser Пользователь
* @param ModuleTopic_EntityTopicType $oTopicType Объект типа топика
* @return bool
*/
public function CanAddTopic($oUser, $oTopicType)
{
$that = $this; // fix for PHP < 5.4
return $this->Rbac_IsAllowUser($oUser, 'create_topic', array(
'callback' => function ($oUser, $aParams) use ($that) {
if (!$oUser) {
return false;
}
if ($oUser->isAdministrator()) {
return true;
}
/**
* Проверяем хватает ли рейтинга юзеру чтоб создать топик
*/
if ($oUser->getRating() <= Config::Get('acl.create.topic.limit_rating')) {
return $that->Lang_Get('topic.add.notices.rating_limit');
}
/**
* Проверяем лимит по времени
*/
if (!$that->CanPostTopicTime($oUser)) {
return $that->Lang_Get('topic.add.notices.time_limit');
}
return true;
}
));
}
/**
* Проверяет может ли пользователь создавать комментарии
*
* @param ModuleUser_EntityUser $oUser Пользователь
* @param ModuleTopic_EntityTopic|null $oTopic Топик
* @return bool
*/
public function CanPostComment($oUser, $oTopic = null)
{
$that = $this; // fix for PHP < 5.4
return $this->Rbac_IsAllowUser($oUser, 'create_topic_comment', array(
'callback' => function ($oUser, $aParams) use ($that, $oTopic) {
if (!$oUser) {
return false;
}
if ($oUser->isAdministrator()) {
return true;
}
/**
* Проверяем на закрытый блог
*/
if ($oTopic and !$that->IsAllowShowBlog($oTopic->getBlog(), $oUser)) {
return $that->Lang_Get('topic.comments.notices.acl');
}
/**
* Ограничение на рейтинг
*/
if ($oUser->getRating() < Config::Get('acl.create.comment.rating')) {
return $that->Lang_Get('topic.comments.notices.acl');
}
/**
* Ограничение по времени
*/
if (Config::Get('acl.create.comment.limit_time') > 0 and $oUser->getDateCommentLast()) {
$sDateCommentLast = strtotime($oUser->getDateCommentLast());
if ($oUser->getRating() < Config::Get('acl.create.comment.limit_time_rating') and ((time() - $sDateCommentLast) < Config::Get('acl.create.comment.limit_time'))) {
return $that->Lang_Get('topic.comments.notices.limit');
}
}
return true;
}
));
}
/**
* Проверяет может ли пользователь создавать топик по времени
*
* @param ModuleUser_EntityUser $oUser Пользователь
* @return bool
*/
public function CanPostTopicTime($oUser)
{
// Для администраторов ограничение по времени не действует
if ($oUser->isAdministrator()
or Config::Get('acl.create.topic.limit_time') == 0
or $oUser->getRating() >= Config::Get('acl.create.topic.limit_time_rating')
) {
return true;
}
/**
* Проверяем, если топик опубликованный меньше чем acl.create.topic.limit_time секунд назад
*/
$aTopics = $this->Topic_GetLastTopicsByUserId($oUser->getId(), Config::Get('acl.create.topic.limit_time'));
if (isset($aTopics['count']) and $aTopics['count'] > 0) {
return false;
}
return true;
}
/**
* Проверяет возможность отправки личного сообщения
*
* @param ModuleUser_EntityUser $oUser Пользователь
* @return bool
*/
public function CanAddTalk($oUser)
{
$that = $this; // fix for PHP < 5.4
return $this->Rbac_IsAllowUser($oUser, 'create_talk', array(
'callback' => function ($oUser, $aParams) use ($that) {
if (!$oUser) {
return false;
}
if ($oUser->isAdministrator()) {
return true;
}
if (!$that->CanSendTalkTime($oUser)) {
return $that->Lang_Get('talk.notices.time_limit');
}
return true;
}
));
}
/**
* Проверяет может ли пользователь отправить инбокс по времени
*
* @param ModuleUser_EntityUser $oUser Пользователь
* @return bool
*/
public function CanSendTalkTime($oUser)
{
// Для администраторов ограничение по времени не действует
if ($oUser->isAdministrator()
or Config::Get('acl.create.talk.limit_time') == 0
or $oUser->getRating() >= Config::Get('acl.create.talk.limit_time_rating')
) {
return true;
}
/**
* Проверяем, если топик опубликованный меньше чем acl.create.topic.limit_time секунд назад
*/
$aTalks = $this->Talk_GetLastTalksByUserId($oUser->getId(), Config::Get('acl.create.talk.limit_time'));
if (isset($aTalks['count']) and $aTalks['count'] > 0) {
return false;
}
return true;
}
/**
* Проверяет может ли пользователь создавать комментарии к личным сообщениям
*
* @param ModuleUser_EntityUser $oUser Пользователь
* @return bool
*/
public function CanPostTalkComment($oUser)
{
$that = $this; // fix for PHP < 5.4
return $this->Rbac_IsAllowUser($oUser, 'create_talk_comment', array(
'callback' => function ($oUser, $aParams) use ($that) {
if (!$oUser) {
return false;
}
if ($oUser->isAdministrator()) {
return true;
}
$aTalkComments = $that->Comment_GetCommentsByUserId($oUser->getId(), 'talk', 1, 1);
/**
* Если комментариев не было
*/
if (!is_array($aTalkComments) or $aTalkComments['count'] == 0) {
return true;
}
/**
* Достаем последний комментарий
*/
$oComment = array_shift($aTalkComments['collection']);
$sDate = strtotime($oComment->getDate());
if ($sDate and ((time() - $sDate) < Config::Get('acl.create.talk_comment.limit_time'))) {
return $that->Lang_Get('talk.add.notices.time_limit');
}
return true;
}
));
}
/**
* Проверяет может ли пользователь голосовать за конкретный комментарий
*
* @param ModuleUser_EntityUser $oUser Пользователь
* @param ModuleComment_EntityComment $oComment Комментарий
* @return bool
*/
public function CanVoteComment($oUser, $oComment)
{
$that = $this; // fix for PHP < 5.4
return $this->Rbac_IsAllowUser($oUser, 'vote_comment', array(
'callback' => function ($oUser, $aParams) use ($that, $oComment) {
if (!$oUser) {
return false;
}
/**
* Голосует автор комментария?
*/
if ($oComment->getUserId() == $oUser->getId()) {
return $that->Lang_Get('vote.notices.error_self');
}
/**
* Пользователь уже голосовал?
*/
if ($oTopicCommentVote = $that->Vote_GetVote($oComment->getId(), 'comment', $oUser->getId())) {
return $that->Lang_Get('vote.notices.error_already_voted');
}
/**
* Разрешаем админу
*/
if ($oUser->isAdministrator()) {
return true;
}
/**
* Ограничение по рейтингу
*/
if ($oUser->getRating() < Config::Get('acl.vote.comment.rating')) {
return $that->Lang_Get('vote.notices.error_acl');
}
/**
* Время голосования истекло?
*/
if (strtotime($oComment->getDate()) <= time() - Config::Get('acl.vote.comment.limit_time')) {
return $that->Lang_Get('vote.notices.error_time');
}
return true;
}
));
}
/**
* Проверяет может ли пользователь голосовать за конкретный топик
*
* @param ModuleUser_EntityUser $oUser Пользователь
* @param ModuleTopic_EntityTopic $oTopic Топик
* @param int $iValue Направление голосования
* @return bool
*/
public function CanVoteTopic($oUser, $oTopic, $iValue)
{
$that = $this; // fix for PHP < 5.4
return $this->Rbac_IsAllowUser($oUser, 'vote_topic', array(
'callback' => function ($oUser, $aParams) use ($that, $oTopic, $iValue) {
if (!$oUser) {
return false;
}
/**
* Голосует автор топика?
*/
if ($oTopic->getUserId() == $oUser->getId()) {
return $that->Lang_Get('vote.notices.error_self');
}
/**
* Пользователь уже голосовал?
*/
if ($oTopicVote = $that->Vote_GetVote($oTopic->getId(), 'topic', $oUser->getId())) {
return $that->Lang_Get('vote.notices.error_already_voted');
}
/**
* Разрешаем админу
*/
if ($oUser->isAdministrator()) {
return true;
}
/**
* Время голосования истекло?
*/
if (strtotime($oTopic->getDatePublish()) <= time() - Config::Get('acl.vote.topic.limit_time')) {
return $that->Lang_Get('vote.notices.error_time');
}
/**
* Ограничение по рейтингу
*/
if ($iValue != 0 and $oUser->getRating() < Config::Get('acl.vote.topic.rating')) {
return $that->Lang_Get('vote.notices.error_acl');
}
return true;
}
));
}
/**
* Проверяет можно ли юзеру слать инвайты
*
* @param ModuleUser_EntityUser $oUser Пользователь
* @return bool
*/
public function CanSendInvite($oUser)
{
$that = $this; // fix for PHP < 5.4
return $this->Rbac_IsAllowUser($oUser, 'create_invite', array(
'callback' => function ($oUser, $aParams) use ($that) {
if (!$oUser) {
return false;
}
if (!Config::Get('general.reg.invite')) {
// разрешаем приглашения всем, когда сайт открыт
return true;
}
if ($oUser->isAdministrator()) {
return true;
}
if ($that->Invite_GetCountInviteAvailable($oUser) == 0) {
return $that->Lang_Get('user.settings.invites.available_no');
}
return true;
}
));
}
/**
* Проверяет можно или нет юзеру постить в данный блог
*
* @param ModuleBlog_EntityBlog $oBlog Блог
* @param ModuleUser_EntityUser $oUser Пользователь
* @return bool
*/
public function IsAllowBlog($oBlog, $oUser)
{
if (!$oBlog || !$oUser) {
return false;
}
if ($oUser->isAdministrator()) {
return true;
}
if ($oBlog->getOwnerId() == $oUser->getId()) {
return true;
}
if ($oBlog->getType() == 'close') {
/**
* Для закрытых блогов проверяем среди подписчиков
*/
if ($oBlogUser = $this->Blog_GetBlogUserByBlogIdAndUserId($oBlog->getId(), $oUser->getId())) {
if ($oUser->getRating() >= $oBlog->getLimitRatingTopic() or $oBlogUser->getIsAdministrator() or $oBlogUser->getIsModerator()) {
return true;
}
}
} else {
/**
* Иначе смотрим ограничение на рейтинг
*/
if ($oUser->getRating() >= $oBlog->getLimitRatingTopic()) {
return true;
}
}
return false;
}
/**
* Проверяет можно или нет юзеру просматривать блог
*
* @param ModuleBlog_EntityBlog $oBlog Блог
* @param ModuleUser_EntityUser $oUser Пользователь
* @return bool
*/
public function IsAllowShowBlog($oBlog, $oUser)
{
if ($oBlog->getType() != 'close') {
return true;
}
if ($oUser->isAdministrator()) {
return true;
}
if ($oBlog->getOwnerId() == $oUser->getId()) {
return true;
}
if ($oBlogUser = $this->Blog_GetBlogUserByBlogIdAndUserId($oBlog->getId(),
$oUser->getId()) and $oBlogUser->getUserRole() > ModuleBlog::BLOG_USER_ROLE_GUEST
) {
return true;
}
return false;
}
/**
* Проверяет можно или нет пользователю редактировать данный топик
*
* @param ModuleTopic_EntityTopic $oTopic Топик
* @param ModuleUser_EntityUser $oUser Пользователь
* @return bool
*/
public function IsAllowEditTopic($oTopic, $oUser)
{
/**
* Разрешаем если это админ сайта или автор топика
*/
if ($oTopic->getUserId() == $oUser->getId() or $oUser->isAdministrator()) {
return true;
}
/**
* Если автор(смотритель) блога
*/
if ($oTopic->getBlog()->getOwnerId() == $oUser->getId()) {
return true;
}
/**
* Если модер или админ блога
*/
if ($this->User_GetUserCurrent() and $this->User_GetUserCurrent()->getId() == $oUser->getId()) {
/**
* Для авторизованного пользователя данный код будет работать быстрее
*/
if ($oTopic->getBlog()->getUserIsAdministrator() or $oTopic->getBlog()->getUserIsModerator()) {
return true;
}
} else {
$oBlogUser = $this->Blog_GetBlogUserByBlogIdAndUserId($oTopic->getBlogId(), $oUser->getId());
if ($oBlogUser and ($oBlogUser->getIsModerator() or $oBlogUser->getIsAdministrator())) {
return true;
}
}
return false;
}
/**
* Проверка на редактирование комментария
*
* @param ModuleComment_EntityComment $oComment
* @param ModuleUser_EntityUser $oUser
*
* @return bool
*/
public function IsAllowEditComment($oComment, $oUser)
{
if (!$oUser) {
return false;
}
if (!in_array($oComment->getTargetType(), (array)Config::Get('module.comment.edit_target_allow'))) {
return false;
}
if ($oUser->isAdministrator()) {
return true;
}
if ($oComment->getUserId() == $oUser->getId() and $oUser->getRating() >= Config::Get('acl.update.comment.rating')) {
/**
* Проверяем на лимит времени
*/
if (!Config::Get('acl.update.comment.limit_time') or (time() - strtotime($oComment->getDate()) <= Config::Get('acl.update.comment.limit_time'))) {
return true;
}
}
return false;
}
/**
* Проверка на возможность добавления комментария в избранное
*
* @param $oComment
* @param $oUser
*
* @return bool
*/
public function IsAllowFavouriteComment($oComment, $oUser)
{
$that = $this; // fix for PHP < 5.4
return $this->Rbac_IsAllowUser($oUser, 'create_comment_favourite', array(
'callback' => function ($oUser, $aParams) use ($that, $oComment) {
if (!$oUser) {
return false;
}
if (!in_array($oComment->getTargetType(), array('topic'))) {
return false;
}
if (!$oTarget = $oComment->getTarget()) {
return false;
}
if ($oComment->getTargetType() == 'topic') {
/**
* Проверяем права на просмотр топика
*/
if (!$that->IsAllowShowTopic($oTarget, $oUser)) {
return false;
}
}
return true;
}
));
}
/**
* Проверка на удаление комментария
*
* @param ModuleComment_EntityComment $oComment
* @param ModuleUser_EntityUser $oUser
*
* @return bool
*/
public function IsAllowDeleteComment($oComment, $oUser)
{
/**
* Разрешаем если это админ сайта
*/
if ($oUser and $oUser->isAdministrator()) {
return true;
}
return false;
}
/**
* Проверяет можно или нет пользователю удалять данный топик
*
* @param ModuleTopic_EntityTopic $oTopic Топик
* @param ModuleUser_EntityUser $oUser Пользователь
* @return bool
*/
public function IsAllowDeleteTopic($oTopic, $oUser)
{
$that = $this; // fix for PHP < 5.4
return $this->Rbac_IsAllowUser($oUser, 'remove_topic', array(
'callback' => function ($oUser, $aParams) use ($that, $oTopic) {
if (!$oUser) {
return false;
}
/**
* Разрешаем если это админ сайта или автор топика
*/
if ($oTopic->getUserId() == $oUser->getId() or $oUser->isAdministrator()) {
return true;
}
/**
* Если автор(смотритель) блога
*/
if ($oTopic->getBlog()->getOwnerId() == $oUser->getId()) {
return true;
}
/**
* Если модер или админ блога
*/
if ($that->User_GetUserCurrent() and $that->User_GetUserCurrent()->getId() == $oUser->getId()) {
/**
* Для авторизованного пользователя данный код будет работать быстрее
*/
if ($oTopic->getBlog()->getUserIsAdministrator() or $oTopic->getBlog()->getUserIsModerator()) {
return true;
}
} else {
$oBlogUser = $that->Blog_GetBlogUserByBlogIdAndUserId($oTopic->getBlogId(), $oUser->getId());
if ($oBlogUser and ($oBlogUser->getIsModerator() or $oBlogUser->getIsAdministrator())) {
return true;
}
}
return false;
}
));
}
/**
* Проверка на возможность просмотра топика
*
* @param $oTopic
* @param $oUser
*
* @return bool
*/
public function IsAllowShowTopic($oTopic, $oUser)
{
if (!$oTopic) {
return false;
}
/**
* Проверяем права на просмотр топика
*/
if ((!$oTopic->getPublish() or $oTopic->getDatePublish() > date('Y-m-d H:i:s'))
and (!$oUser or ($oUser->getId() != $oTopic->getUserId() and !$oUser->isAdministrator()))
) {
return false;
}
/**
* Определяем права на отображение записи из закрытого блога
*/
if (!$this->IsAllowShowBlog($oTopic->getBlog(), $oUser)) {
return false;
}
return true;
}
/**
* Проверяет можно или нет пользователю удалять данный блог
*
* @param ModuleBlog_EntityBlog $oBlog Блог
* @param ModuleUser_EntityUser $oUser Пользователь
* @return bool
*/
public function IsAllowDeleteBlog($oBlog, $oUser)
{
/**
* Разрешаем если это админ сайта или автор блога
*/
if ($oUser->isAdministrator()) {
return self::CAN_DELETE_BLOG_WITH_TOPICS;
}
/**
* Разрешаем удалять администраторам блога и автору, но только пустой
*/
if ($oBlog->getOwnerId() == $oUser->getId()) {
return self::CAN_DELETE_BLOG_EMPTY_ONLY;
}
$oBlogUser = $this->Blog_GetBlogUserByBlogIdAndUserId($oBlog->getId(), $oUser->getId());
if ($oBlogUser and $oBlogUser->getIsAdministrator()) {
return self::CAN_DELETE_BLOG_EMPTY_ONLY;
}
return false;
}
/**
* Проверяет может ли пользователь удалить комментарий
*
* @param ModuleUser_EntityUser $oUser Пользователь
* @return bool
*/
public function CanDeleteComment($oUser)
{
if (!$oUser || !$oUser->isAdministrator()) {
return false;
}
return true;
}
/**
* Проверяет может ли пользователь публиковать на главной
*
* @param ModuleUser_EntityUser $oUser Пользователь
* @return bool
*/
public function IsAllowTopicPublishIndex(ModuleUser_EntityUser $oUser)
{
if ($oUser->isAdministrator()) {
return true;
}
return false;
}
/**
* Проверяет может ли пользователь блокировать топик на главной
*
* @param ModuleUser_EntityUser $oUser Пользователь
* @return bool
*/
public function IsAllowTopicSkipIndex(ModuleUser_EntityUser $oUser)
{
if ($oUser->isAdministrator()) {
return true;
}
return false;
}
/**
* Проверяет можно или нет пользователю редактировать данный блог
*
* @param ModuleBlog_EntityBlog $oBlog Блог
* @param ModuleUser_EntityUser $oUser Пользователь
* @return bool
*/
public function IsAllowEditBlog($oBlog, $oUser)
{
if ($oUser->isAdministrator()) {
return true;
}
/**
* Разрешаем если это создатель блога
*/
if ($oBlog->getOwnerId() == $oUser->getId()) {
return true;
}
/**
* Явлется ли авторизованный пользователь администратором блога
*/
$oBlogUser = $this->Blog_GetBlogUserByBlogIdAndUserId($oBlog->getId(), $oUser->getId());
if ($oBlogUser && $oBlogUser->getIsAdministrator()) {
return true;
}
return false;
}
/**
* Проверяет можно или нет пользователю управлять пользователями блога
*
* @param ModuleBlog_EntityBlog $oBlog Блог
* @param ModuleUser_EntityUser $oUser Пользователь
* @return bool
*/
public function IsAllowAdminBlog($oBlog, $oUser)
{
if ($oUser->isAdministrator()) {
return true;
}
/**
* Разрешаем если это создатель блога
*/
if ($oBlog->getOwnerId() == $oUser->getId()) {
return true;
}
/**
* Явлется ли авторизованный пользователь администратором блога
*/
$oBlogUser = $this->Blog_GetBlogUserByBlogIdAndUserId($oBlog->getId(), $oUser->getId());
if ($oBlogUser && $oBlogUser->getIsAdministrator()) {
return true;
}
return false;
}
/**
* Проверка на ограничение по времени на постинг на стене
*
* @param ModuleUser_EntityUser $oUser Пользователь
* @param ModuleWall_EntityWall $oWall Объект сообщения на стене
* @return bool
*/
public function CanAddWallTime($oUser, $oWall)
{
/**
* Для администраторов ограничение по времени не действует
*/
if ($oUser->isAdministrator()
or Config::Get('acl.create.wall.limit_time') == 0
or $oUser->getRating() >= Config::Get('acl.create.wall.limit_time_rating')
) {
return true;
}
if ($oWall->getUserId() == $oWall->getWallUserId()) {
return true;
}
/**
* Получаем последнее сообщение
*/
$aWall = $this->Wall_GetWall(array('user_id' => $oWall->getUserId()), array('id' => 'desc'), 1, 1, array());
/**
* Если сообщений нет
*/
if ($aWall['count'] == 0) {
return true;
}
$oWallLast = array_shift($aWall['collection']);
$sDate = strtotime($oWallLast->getDateAdd());
if ($sDate and ((time() - $sDate) < Config::Get('acl.create.wall.limit_time'))) {
return false;
}
return true;
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,517 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Сущность блога
*
* @package application.modules.blog
* @since 1.0
*/
class ModuleBlog_EntityBlog extends Entity
{
protected $sPrimaryKey = 'blog_id';
/**
* Список поведений
*
* @var array
*/
protected $aBehaviors = array(
// Категории
'category' => array(
'class' => 'ModuleCategory_BehaviorEntity',
'target_type' => 'blog',
'form_field' => 'category',
'multiple' => false,
'validate_require' => false,
'validate_only_without_children' => true,
),
);
/**
* Инициализация
*/
public function Init()
{
parent::Init();
$this->aBehaviors['category']['validate_require'] = !Config::Get('module.blog.category_allow_empty');
$this->aBehaviors['category']['validate_only_without_children'] = Config::Get('module.blog.category_only_without_children');
}
/**
* Возвращает ID блога
*
* @return int|null
*/
public function getId()
{
return $this->_getDataOne('blog_id');
}
/**
* Возвращает ID хозяина блога
*
* @return int|null
*/
public function getOwnerId()
{
return $this->_getDataOne('user_owner_id');
}
/**
* Возвращает название блога
*
* @return string|null
*/
public function getTitle()
{
return $this->_getDataOne('blog_title');
}
/**
* Возвращает описание блога
*
* @return string|null
*/
public function getDescription()
{
return $this->_getDataOne('blog_description');
}
/**
* Возвращает тип блога
*
* @return string|null
*/
public function getType()
{
return $this->_getDataOne('blog_type');
}
/**
* Возвращает дату создания блога
*
* @return string|null
*/
public function getDateAdd()
{
return $this->_getDataOne('blog_date_add');
}
/**
* Возвращает дату редактирования блога
*
* @return string|null
*/
public function getDateEdit()
{
return $this->_getDataOne('blog_date_edit');
}
/**
* Возврщает количество проголосовавших за блог
*
* @return int|null
*/
public function getCountVote()
{
return $this->_getDataOne('blog_count_vote');
}
/**
* Возвращает количество пользователей в блоге
*
* @return int|null
*/
public function getCountUser()
{
return $this->_getDataOne('blog_count_user');
}
/**
* Возвращает количество топиков в блоге
*
* @return int|null
*/
public function getCountTopic()
{
return $this->_getDataOne('blog_count_topic');
}
/**
* Возвращает ограничение по рейтингу для постинга в блог
*
* @return int|null
*/
public function getLimitRatingTopic()
{
return $this->_getDataOne('blog_limit_rating_topic');
}
/**
* Возвращает URL блога
*
* @return string|null
*/
public function getUrl()
{
return $this->_getDataOne('blog_url');
}
/**
* Возвращает флаг пропуска топиков на главной
*
* @return int|null
*/
public function getSkipIndex()
{
return $this->_getDataOne('blog_skip_index');
}
/**
* Возвращает полный серверный путь до аватара блога
*
* @return string|null
*/
public function getAvatar()
{
return $this->_getDataOne('blog_avatar');
}
/**
* Возвращает расширения аватра блога
*
* @return string|null
*/
public function getAvatarType()
{
return ($sPath = $this->getAvatarPath()) ? pathinfo($sPath, PATHINFO_EXTENSION) : null;
}
/**
* Возвращает объект пользователя хозяина блога
*
* @return ModuleUser_EntityUser|null
*/
public function getOwner()
{
return $this->_getDataOne('owner');
}
/**
* Возвращает объект голосования за блог
*
* @return ModuleVote_EntityVote|null
*/
public function getVote()
{
return $this->_getDataOne('vote');
}
/**
* Возвращает полный серверный путь до аватара блога определенного размера
*
* @param int $iSize Размер аватара
* @return string
*/
public function getAvatarPath($iSize = 48)
{
if (is_numeric($iSize)) {
$iSize .= 'crop';
}
if ($sPath = $this->getAvatar()) {
return $this->Media_GetImageWebPath($sPath, $iSize);
} else {
return $this->Media_GetImagePathBySize(Router::GetFixPathWeb(Config::Get('path.skin.assets.web')) . '/images/avatars/avatar_blog.png', $iSize);
}
}
/**
* Возвращает путь до большого аватара блога
*
* @return string
*/
public function getAvatarBig()
{
return $this->getAvatarPath(Config::Get('module.blog.avatar_size_big'));
}
/**
* Формирует массив с путями до аватаров
*
* @return array Массив с путями до аватаров
*/
public function getAvatarsPath()
{
$aAvatars = array();
foreach (Config::Get('module.blog.avatar_size') as $sSize) {
$aAvatars[$sSize] = $this->getAvatarPath($sSize);
}
return $aAvatars;
}
/**
* Возвращает факт присоединения пользователя к блогу
*
* @return bool|null
*/
public function getUserIsJoin()
{
return $this->_getDataOne('user_is_join');
}
/**
* Проверяет является ли пользователь администратором блога
*
* @return bool|null
*/
public function getUserIsAdministrator()
{
return $this->_getDataOne('user_is_administrator');
}
/**
* Проверяет является ли пользователь модератором блога
*
* @return bool|null
*/
public function getUserIsModerator()
{
return $this->_getDataOne('user_is_moderator');
}
/**
* Возвращает полный URL блога
*
* @return string
*/
public function getUrlFull()
{
if ($this->getType() == 'personal') {
return $this->getOwner()->getUserWebPath() . 'created/topics/';
} else {
return Router::GetPath('blog') . $this->getUrl() . '/';
}
}
public function isAllowEdit()
{
if ($oUser = $this->User_GetUserCurrent()) {
if ($oUser->getId() == $this->getOwnerId() or $oUser->isAdministrator() or $this->getUserIsAdministrator()) {
return true;
}
}
return false;
}
/**
* Устанавливает ID блога
*
* @param int $data
*/
public function setId($data)
{
$this->_aData['blog_id'] = $data;
}
/**
* Устанавливает ID хозяина блога
*
* @param int $data
*/
public function setOwnerId($data)
{
$this->_aData['user_owner_id'] = $data;
}
/**
* Устанавливает заголовок блога
*
* @param string $data
*/
public function setTitle($data)
{
$this->_aData['blog_title'] = $data;
}
/**
* Устанавливает описание блога
*
* @param string $data
*/
public function setDescription($data)
{
$this->_aData['blog_description'] = $data;
}
/**
* Устанавливает тип блога
*
* @param string $data
*/
public function setType($data)
{
$this->_aData['blog_type'] = $data;
}
/**
* Устанавливает дату создания блога
*
* @param string $data
*/
public function setDateAdd($data)
{
$this->_aData['blog_date_add'] = $data;
}
/**
* Устанавливает дату редактирования топика
*
* @param string $data
*/
public function setDateEdit($data)
{
$this->_aData['blog_date_edit'] = $data;
}
/**
* Устаналивает количество проголосовавших
*
* @param int $data
*/
public function setCountVote($data)
{
$this->_aData['blog_count_vote'] = $data;
}
/**
* Устанавливает количество пользователей блога
*
* @param int $data
*/
public function setCountUser($data)
{
$this->_aData['blog_count_user'] = $data;
}
/**
* Устанавливает количество топиков в блоге
*
* @param int $data
*/
public function setCountTopic($data)
{
$this->_aData['blog_count_topic'] = $data;
}
/**
* Устанавливает ограничение на постинг в блог
*
* @param float $data
*/
public function setLimitRatingTopic($data)
{
$this->_aData['blog_limit_rating_topic'] = $data;
}
/**
* Устанавливает URL блога
*
* @param string $data
*/
public function setUrl($data)
{
$this->_aData['blog_url'] = $data;
}
/**
* Устанавливает флаг пропуска топиков на главной
*
* @param string $data
*/
public function setSkipIndex($data)
{
$this->_aData['blog_skip_index'] = $data;
}
/**
* Устанавливает полный серверный путь до аватара блога
*
* @param string $data
*/
public function setAvatar($data)
{
$this->_aData['blog_avatar'] = $data;
}
/**
* Устанавливает автора блога
*
* @param ModuleUser_EntityUser $data
*/
public function setOwner($data)
{
$this->_aData['owner'] = $data;
}
/**
* Устанавливает статус администратора блога для текущего пользователя
*
* @param bool $data
*/
public function setUserIsAdministrator($data)
{
$this->_aData['user_is_administrator'] = $data;
}
/**
* Устанавливает статус модератора блога для текущего пользователя
*
* @param bool $data
*/
public function setUserIsModerator($data)
{
$this->_aData['user_is_moderator'] = $data;
}
/**
* Устаналивает статус присоединения польователя к блогу
*
* @param bool $data
*/
public function setUserIsJoin($data)
{
$this->_aData['user_is_join'] = $data;
}
/**
* Устанавливает объект голосования за блог
*
* @param ModuleVote_EntityVote $data
*/
public function setVote($data)
{
$this->_aData['vote'] = $data;
}
}

View file

@ -0,0 +1,190 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Сущность связи пользователя и блога
*
* @package application.modules.blog
* @since 1.0
*/
class ModuleBlog_EntityBlogUser extends Entity
{
/**
* Возвращает ID блога
*
* @return int|null
*/
public function getBlogId()
{
return $this->_getDataOne('blog_id');
}
/**
* Возвращает ID пользователя
*
* @return int|null
*/
public function getUserId()
{
return $this->_getDataOne('user_id');
}
/**
* Возвращает статус модератор пользователь или нет
*
* @return bool
*/
public function getIsModerator()
{
return ($this->getUserRole() == ModuleBlog::BLOG_USER_ROLE_MODERATOR);
}
/**
* Возвращает статус администратор пользователь или нет
*
* @return bool
*/
public function getIsAdministrator()
{
return ($this->getUserRole() == ModuleBlog::BLOG_USER_ROLE_ADMINISTRATOR);
}
/**
* Возвращает статус бана пользователя
*
* @return bool
*/
public function getIsBanned()
{
return ($this->getUserRole() == ModuleBlog::BLOG_USER_ROLE_BAN);
}
/**
* Возвращает текущую роль пользователя в блоге
*
* @return int|null
*/
public function getUserRole()
{
return $this->_getDataOne('user_role');
}
/**
* Возвращает объект блога
*
* @return ModuleBlog_EntityBlog|null
*/
public function getBlog()
{
return $this->_getDataOne('blog');
}
/**
* Возвращает объект пользователя
*
* @return ModuleUser_EntityUser|null
*/
public function getUser()
{
return $this->_getDataOne('user');
}
/**
* Устанавливает ID блога
*
* @param int $data
*/
public function setBlogId($data)
{
$this->_aData['blog_id'] = $data;
}
/**
* Устанавливает ID пользователя
*
* @param int $data
*/
public function setUserId($data)
{
$this->_aData['user_id'] = $data;
}
/**
* Устанавливает статус модератора блога
*
* @param bool $data
*/
public function setIsModerator($data)
{
if ($data && !$this->getIsModerator()) {
/**
* Повышаем статус до модератора
*/
$this->setUserRole(ModuleBlog::BLOG_USER_ROLE_MODERATOR);
}
}
/**
* Устанавливает статус администратора блога
*
* @param bool $data
*/
public function setIsAdministrator($data)
{
if ($data && !$this->getIsAdministrator()) {
/**
* Повышаем статус до администратора
*/
$this->setUserRole(ModuleBlog::BLOG_USER_ROLE_ADMINISTRATOR);
}
}
/**
* Устанавливает роль пользователя
*
* @param int $data
*/
public function setUserRole($data)
{
$this->_aData['user_role'] = $data;
}
/**
* Устанавливает блог
*
* @param ModuleBlog_EntityBlog $data
*/
public function setBlog($data)
{
$this->_aData['blog'] = $data;
}
/**
* Устанавливаем пользователя
*
* @param ModuleUser_EntityUser $data
*/
public function setUser($data)
{
$this->_aData['user'] = $data;
}
}

View file

@ -0,0 +1,641 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Маппер для работы с БД по части блогов
*
* @package application.modules.blog
* @since 1.0
*/
class ModuleBlog_MapperBlog extends Mapper
{
/**
* Добавляет блог в БД
*
* @param ModuleBlog_EntityBlog $oBlog Объект блога
* @return int|bool
*/
public function AddBlog(ModuleBlog_EntityBlog $oBlog)
{
$sql = "INSERT INTO " . Config::Get('db.table.blog') . "
(user_owner_id,
blog_title,
blog_description,
blog_type,
blog_date_add,
blog_limit_rating_topic,
blog_url,
blog_skip_index,
blog_avatar
)
VALUES(?d, ?, ?, ?, ?, ?, ?, ?, ?)
";
if ($iId = $this->oDb->query($sql, $oBlog->getOwnerId(), $oBlog->getTitle(), $oBlog->getDescription(),
$oBlog->getType(), $oBlog->getDateAdd(), $oBlog->getLimitRatingTopic(), $oBlog->getUrl(),
$oBlog->getSkipIndex(), $oBlog->getAvatar())
) {
return $iId;
}
return false;
}
/**
* Обновляет блог в БД
*
* @param ModuleBlog_EntityBlog $oBlog Объект блога
* @return bool
*/
public function UpdateBlog(ModuleBlog_EntityBlog $oBlog)
{
$sql = "UPDATE " . Config::Get('db.table.blog') . "
SET
blog_title= ?,
blog_description= ?,
blog_type= ?,
blog_date_edit= ?,
blog_count_vote = ?d,
blog_count_user= ?d,
blog_count_topic= ?d,
blog_limit_rating_topic= ?f ,
blog_url= ?,
blog_skip_index= ?d,
blog_avatar= ?
WHERE
blog_id = ?d
";
$res = $this->oDb->query($sql, $oBlog->getTitle(), $oBlog->getDescription(), $oBlog->getType(),
$oBlog->getDateEdit(), $oBlog->getCountVote(), $oBlog->getCountUser(),
$oBlog->getCountTopic(), $oBlog->getLimitRatingTopic(), $oBlog->getUrl(), $oBlog->getSkipIndex(), $oBlog->getAvatar(),
$oBlog->getId());
return $this->IsSuccessful($res);
}
/**
* Получает список блогов по ID
*
* @param array $aArrayId Список ID блогов
* @param array|null $aOrder Сортировка блогов
* @return array
*/
public function GetBlogsByArrayId($aArrayId, $aOrder = null)
{
if (!is_array($aArrayId) or count($aArrayId) == 0) {
return array();
}
if (!is_array($aOrder)) {
$aOrder = array($aOrder);
}
$sOrder = '';
foreach ($aOrder as $key => $value) {
$value = (string)$value;
if (!in_array($key,
array('blog_id', 'blog_title', 'blog_type', 'blog_count_user', 'blog_date_add'))
) {
unset($aOrder[$key]);
} elseif (in_array($value, array('asc', 'desc'))) {
$sOrder .= " {$key} {$value},";
}
}
$sOrder = trim($sOrder, ',');
$sql = "SELECT
*
FROM
" . Config::Get('db.table.blog') . "
WHERE
blog_id IN(?a)
ORDER BY
{ FIELD(blog_id,?a) } ";
if ($sOrder != '') {
$sql .= $sOrder;
}
$aBlogs = array();
if ($aRows = $this->oDb->select($sql, $aArrayId, $sOrder == '' ? $aArrayId : DBSIMPLE_SKIP)) {
foreach ($aRows as $aBlog) {
$aBlogs[] = Engine::GetEntity('Blog', $aBlog);
}
}
return $aBlogs;
}
/**
* Добавляет связь пользователя с блогом в БД
*
* @param ModuleBlog_EntityBlogUser $oBlogUser Объект отношения пользователя с блогом
* @return bool
*/
public function AddRelationBlogUser(ModuleBlog_EntityBlogUser $oBlogUser)
{
$sql = "INSERT INTO " . Config::Get('db.table.blog_user') . "
(blog_id,
user_id,
user_role
)
VALUES(?d, ?d, ?d)
";
if ($this->oDb->query($sql, $oBlogUser->getBlogId(), $oBlogUser->getUserId(), $oBlogUser->getUserRole()) === 0
) {
return true;
}
return false;
}
/**
* Удаляет отношение пользователя с блогом
*
* @param ModuleBlog_EntityBlogUser $oBlogUser Объект отношения пользователя с блогом
* @return bool
*/
public function DeleteRelationBlogUser(ModuleBlog_EntityBlogUser $oBlogUser)
{
$sql = "DELETE FROM " . Config::Get('db.table.blog_user') . "
WHERE
blog_id = ?d
AND
user_id = ?d
";
$res = $this->oDb->query($sql, $oBlogUser->getBlogId(), $oBlogUser->getUserId());
return $this->IsSuccessful($res);
}
/**
* Обновляет отношение пользователя с блогом
*
* @param ModuleBlog_EntityBlogUser $oBlogUser Объект отношения пользователя с блогом
* @return bool
*/
public function UpdateRelationBlogUser(ModuleBlog_EntityBlogUser $oBlogUser)
{
$sql = "UPDATE " . Config::Get('db.table.blog_user') . "
SET
user_role = ?d
WHERE
blog_id = ?d
AND
user_id = ?d
";
$res = $this->oDb->query($sql, $oBlogUser->getUserRole(), $oBlogUser->getBlogId(), $oBlogUser->getUserId());
return $this->IsSuccessful($res);
}
/**
* Получает список отношений пользователей с блогами
*
* @param array $aFilter Фильтр поиска отношений
* @param int $iCount Возвращает общее количество элементов
* @param int $iCurrPage Номер текущейс страницы
* @param int $iPerPage Количество элементов на одну страницу
* @return array
*/
public function GetBlogUsers($aFilter, &$iCount = null, $iCurrPage = null, $iPerPage = null)
{
if (isset($aFilter['blog_id']) and !is_array($aFilter['blog_id'])) {
$aFilter['blog_id']=array($aFilter['blog_id']);
}
if (isset($aFilter['user_role']) and !is_array($aFilter['user_role'])) {
$aFilter['user_role']=array($aFilter['user_role']);
}
if (is_null($iCurrPage)) {
$iCurrPage=1;
}
if (is_null($iPerPage)) {
$iPerPage=1000;
}
$sql = "SELECT
bu.*
FROM
" . Config::Get('db.table.blog_user') . " as bu
WHERE
1=1
{ AND bu.blog_id IN (?a) }
{ AND bu.user_id = ?d }
{ AND bu.user_role IN (?a) }
{ AND bu.user_role > ?d }
LIMIT ?d, ?d
";
$aResult = array();
if ($aRows = $this->oDb->selectPage($iCount, $sql,
(isset($aFilter['blog_id']) and count($aFilter['blog_id'])) ? $aFilter['blog_id'] : DBSIMPLE_SKIP,
isset($aFilter['user_id']) ? $aFilter['user_id'] : DBSIMPLE_SKIP,
(isset($aFilter['user_role']) and count($aFilter['user_role'])) ? $aFilter['user_role'] : DBSIMPLE_SKIP,
!isset($aFilter['user_role']) ? ModuleBlog::BLOG_USER_ROLE_GUEST : DBSIMPLE_SKIP,
($iCurrPage - 1) * $iPerPage, $iPerPage
)
) {
foreach ($aRows as $aRow) {
$aResult[] = Engine::GetEntity('Blog_BlogUser', $aRow);
}
}
return $aResult;
}
/**
* Получает список отношений пользователя к блогам
*
* @param array $aArrayId Список ID блогов
* @param int $sUserId ID блогов
* @return array
*/
public function GetBlogUsersByArrayBlog($aArrayId, $sUserId)
{
if (!is_array($aArrayId) or count($aArrayId) == 0) {
return array();
}
$sql = "SELECT
bu.*
FROM
" . Config::Get('db.table.blog_user') . " as bu
WHERE
bu.blog_id IN(?a)
AND
bu.user_id = ?d ";
$aBlogUsers = array();
if ($aRows = $this->oDb->select($sql, $aArrayId, $sUserId)) {
foreach ($aRows as $aUser) {
$aBlogUsers[] = Engine::GetEntity('Blog_BlogUser', $aUser);
}
}
return $aBlogUsers;
}
/**
* Получает ID персонального блога пользователя
*
* @param int $sUserId ID пользователя
* @return int|null
*/
public function GetPersonalBlogByUserId($sUserId)
{
$sql = "SELECT blog_id FROM " . Config::Get('db.table.blog') . " WHERE user_owner_id = ?d and blog_type='personal'";
if ($aRow = $this->oDb->selectRow($sql, $sUserId)) {
return $aRow['blog_id'];
}
return null;
}
/**
* Получает блог по названию
*
* @param string $sTitle Нащвание блога
* @return ModuleBlog_EntityBlog|null
*/
public function GetBlogByTitle($sTitle)
{
$sql = "SELECT blog_id FROM " . Config::Get('db.table.blog') . " WHERE blog_title = ? ";
if ($aRow = $this->oDb->selectRow($sql, $sTitle)) {
return $aRow['blog_id'];
}
return null;
}
/**
* Получает блог по URL
*
* @param string $sUrl URL блога
* @return ModuleBlog_EntityBlog|null
*/
public function GetBlogByUrl($sUrl)
{
$sql = "SELECT
b.blog_id
FROM
" . Config::Get('db.table.blog') . " as b
WHERE
b.blog_url = ?
";
if ($aRow = $this->oDb->selectRow($sql, $sUrl)) {
return $aRow['blog_id'];
}
return null;
}
/**
* Получить список блогов по хозяину
*
* @param int $sUserId ID пользователя
* @return array
*/
public function GetBlogsByOwnerId($sUserId)
{
$sql = "SELECT
b.blog_id
FROM
" . Config::Get('db.table.blog') . " as b
WHERE
b.user_owner_id = ?
AND
b.blog_type<>'personal'
";
$aBlogs = array();
if ($aRows = $this->oDb->select($sql, $sUserId)) {
foreach ($aRows as $aBlog) {
$aBlogs[] = $aBlog['blog_id'];
}
}
return $aBlogs;
}
/**
* Возвращает список всех не персональных блогов
*
* @return array
*/
public function GetBlogs()
{
$sql = "SELECT
b.blog_id
FROM
" . Config::Get('db.table.blog') . " as b
WHERE
b.blog_type<>'personal'
";
$aBlogs = array();
if ($aRows = $this->oDb->select($sql)) {
foreach ($aRows as $aBlog) {
$aBlogs[] = $aBlog['blog_id'];
}
}
return $aBlogs;
}
/**
* Возвращает список не персональных блогов с сортировкой по рейтингу
*
* @param int $iCount Возвращает общее количество элементов
* @param int $iCurrPage Номер текущей страницы
* @param int $iPerPage Количество элементов на одну страницу
* @return array
*/
public function GetBlogsRating(&$iCount, $iCurrPage, $iPerPage)
{
$sql = "SELECT
b.blog_id
FROM
" . Config::Get('db.table.blog') . " as b
WHERE
b.blog_type<>'personal'
ORDER by b.blog_count_user desc
LIMIT ?d, ?d ";
$aReturn = array();
if ($aRows = $this->oDb->selectPage($iCount, $sql, ($iCurrPage - 1) * $iPerPage, $iPerPage)) {
foreach ($aRows as $aRow) {
$aReturn[] = $aRow['blog_id'];
}
}
return $aReturn;
}
/**
* Получает список блогов в которых состоит пользователь
*
* @param int $sUserId ID пользователя
* @param int $iLimit Ограничение на выборку элементов
* @return array
*/
public function GetBlogsRatingJoin($sUserId, $iLimit)
{
$sql = "SELECT
b.*
FROM
" . Config::Get('db.table.blog_user') . " as bu,
" . Config::Get('db.table.blog') . " as b
WHERE
bu.user_id = ?d
AND
bu.blog_id = b.blog_id
AND
b.blog_type<>'personal'
ORDER by b.blog_count_user desc
LIMIT 0, ?d
;
";
$aReturn = array();
if ($aRows = $this->oDb->select($sql, $sUserId, $iLimit)) {
foreach ($aRows as $aRow) {
$aReturn[] = Engine::GetEntity('Blog', $aRow);
}
}
return $aReturn;
}
/**
* Получает список блогов, которые создал пользователь
*
* @param int $sUserId ID пользователя
* @param int $iLimit Ограничение на выборку элементов
* @return array
*/
public function GetBlogsRatingSelf($sUserId, $iLimit)
{
$sql = "SELECT
b.*
FROM
" . Config::Get('db.table.blog') . " as b
WHERE
b.user_owner_id = ?d
AND
b.blog_type<>'personal'
ORDER by b.blog_count_user desc
LIMIT 0, ?d
;";
$aReturn = array();
if ($aRows = $this->oDb->select($sql, $sUserId, $iLimit)) {
foreach ($aRows as $aRow) {
$aReturn[] = Engine::GetEntity('Blog', $aRow);
}
}
return $aReturn;
}
/**
* Возвращает полный список закрытых блогов
*
* @return array
*/
public function GetCloseBlogs()
{
$sql = "SELECT b.blog_id
FROM " . Config::Get('db.table.blog') . " as b
WHERE b.blog_type='close'
;";
$aReturn = array();
if ($aRows = $this->oDb->select($sql)) {
foreach ($aRows as $aRow) {
$aReturn[] = $aRow['blog_id'];
}
}
return $aReturn;
}
/**
* Удаление блога из базы данных
*
* @param int $iBlogId ID блога
* @return bool
*/
public function DeleteBlog($iBlogId)
{
$sql = "
DELETE FROM " . Config::Get('db.table.blog') . "
WHERE blog_id = ?d
";
$res = $this->oDb->query($sql, $iBlogId);
return $this->IsSuccessful($res);
}
/**
* Удалить пользователей блога по идентификатору блога
*
* @param int $iBlogId ID блога
* @return bool
*/
public function DeleteBlogUsersByBlogId($iBlogId)
{
$sql = "
DELETE FROM " . Config::Get('db.table.blog_user') . "
WHERE blog_id = ?d
";
$res = $this->oDb->query($sql, $iBlogId);
return $this->IsSuccessful($res);
}
/**
* Пересчитывает число топиков в блогах
*
* @param int|null $iBlogId ID блога
* @return bool
*/
public function RecalculateCountTopic($iBlogId = null)
{
$sql = "
UPDATE " . Config::Get('db.table.blog') . " b
SET b.blog_count_topic = (
SELECT count(*)
FROM " . Config::Get('db.table.topic') . " t
WHERE
(
t.blog_id = b.blog_id OR
t.blog_id2 = b.blog_id OR
t.blog_id3 = b.blog_id OR
t.blog_id4 = b.blog_id OR
t.blog_id5 = b.blog_id
)
AND
t.topic_publish = 1
)
WHERE 1=1
{ and b.blog_id = ?d }
";
$res = $this->oDb->query($sql, is_null($iBlogId) ? DBSIMPLE_SKIP : $iBlogId);
return $this->IsSuccessful($res);
}
/**
* Получает список блогов по фильтру
*
* @param array $aFilter Фильтр выборки
* @param array $aOrder Сортировка
* @param int $iCount Возвращает общее количество элментов
* @param int $iCurrPage Номер текущей страницы
* @param int $iPerPage Количество элементов на одну страницу
* @return array
*/
public function GetBlogsByFilter($aFilter, $aOrder, &$iCount, $iCurrPage, $iPerPage)
{
$aOrderAllow = array('blog_id', 'blog_title', 'blog_count_user', 'blog_count_topic');
$sOrder = '';
foreach ($aOrder as $key => $value) {
if (!in_array($key, $aOrderAllow)) {
unset($aOrder[$key]);
} elseif (in_array($value, array('asc', 'desc'))) {
$sOrder .= " b.{$key} {$value},";
}
}
$sOrder = trim($sOrder, ',');
if ($sOrder == '') {
$sOrder = ' b.blog_id desc ';
}
if (isset($aFilter['exclude_type']) and !is_array($aFilter['exclude_type'])) {
$aFilter['exclude_type'] = array($aFilter['exclude_type']);
}
if (isset($aFilter['type']) and !is_array($aFilter['type'])) {
$aFilter['type'] = array($aFilter['type']);
}
if (isset($aFilter['id']) and !is_array($aFilter['id'])) {
$aFilter['id'] = array($aFilter['id']);
}
$iUserCurrentId=0;
if (isset($aFilter['roles_user_id'])) {
$iUserCurrentId=$aFilter['roles_user_id'];
} elseif ($oUserCurrent=$this->User_GetUserCurrent()) {
$iUserCurrentId=$oUserCurrent->getId();
}
$sql = "SELECT
b.blog_id
FROM
" . Config::Get('db.table.blog') . " as b
{
JOIN " . Config::Get('db.table.blog_user') . " as bu
ON ( bu.blog_id = b.blog_id and bu.user_id = '{$iUserCurrentId}'
and bu.user_role in (?a)
)
}
WHERE
1 = 1
{ AND b.blog_id IN (?a) }
{ AND b.user_owner_id = ?d }
{ AND b.blog_type IN (?a) }
{ AND b.blog_type not IN (?a) }
{ AND b.blog_url = ? }
{ AND b.blog_title LIKE ? }
ORDER by {$sOrder}
LIMIT ?d, ?d ;
";
$aResult = array();
if ($aRows = $this->oDb->selectPage($iCount, $sql,
(isset($aFilter['roles']) and count($aFilter['roles'])) ? $aFilter['roles'] : DBSIMPLE_SKIP,
(isset($aFilter['id']) and count($aFilter['id'])) ? $aFilter['id'] : DBSIMPLE_SKIP,
isset($aFilter['user_owner_id']) ? $aFilter['user_owner_id'] : DBSIMPLE_SKIP,
(isset($aFilter['type']) and count($aFilter['type'])) ? $aFilter['type'] : DBSIMPLE_SKIP,
(isset($aFilter['exclude_type']) and count($aFilter['exclude_type'])) ? $aFilter['exclude_type'] : DBSIMPLE_SKIP,
isset($aFilter['url']) ? $aFilter['url'] : DBSIMPLE_SKIP,
isset($aFilter['title']) ? $aFilter['title'] : DBSIMPLE_SKIP,
($iCurrPage - 1) * $iPerPage, $iPerPage
)
) {
foreach ($aRows as $aRow) {
$aResult[] = $aRow['blog_id'];
}
}
return $aResult;
}
}

View file

@ -0,0 +1,577 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Модуль управления универсальными категориями
*
* @package application.modules.category
* @since 2.0
*/
class ModuleCategory extends ModuleORM
{
/**
* Список состояний типов объектов
*/
const TARGET_STATE_ACTIVE = 1;
const TARGET_STATE_NOT_ACTIVE = 2;
const TARGET_STATE_REMOVE = 3;
/**
* Возвращает список категорий сущности
*
* @param $oTarget
* @param $sTargetType
*
* @return array
*/
public function GetEntityCategories($oTarget, $sTargetType)
{
$aCategories = $oTarget->_getDataOne('_categories');
if (is_null($aCategories)) {
$this->AttachCategoriesForTargetItems($oTarget, $sTargetType);
return $oTarget->_getDataOne('_categories');
}
return $aCategories;
}
/**
* Обработка фильтра ORM запросов
*
* @param array $aFilter
* @param array $sEntityFull
* @param string $sTargetType
*
* @return array
*/
public function RewriteFilter($aFilter, $sEntityFull, $sTargetType)
{
$oEntitySample = Engine::GetEntity($sEntityFull);
if (!isset($aFilter['#join'])) {
$aFilter['#join'] = array();
}
if (!isset($aFilter['#select'])) {
$aFilter['#select'] = array();
}
if (array_key_exists('#category', $aFilter)) {
$aCategoryId = $aFilter['#category'];
if (!is_array($aCategoryId)) {
$aCategoryId = array($aCategoryId);
}
$sJoin = "JOIN " . Config::Get('db.table.category_target') . " category ON
t.`{$oEntitySample->_getPrimaryKey()}` = category.target_id and
category.target_type = '{$sTargetType}' and
category.category_id IN ( ?a ) ";
$aFilter['#join'][$sJoin] = array($aCategoryId);
if (count($aFilter['#select'])) {
$aFilter['#select'][] = "distinct t.`{$oEntitySample->_getPrimaryKey()}`";
} else {
$aFilter['#select'][] = "distinct t.`{$oEntitySample->_getPrimaryKey()}`";
$aFilter['#select'][] = 't.*';
}
}
return $aFilter;
}
/**
* Переопределяем метод для возможности цеплять свои кастомные данные при ORM запросах - свойства
*
* @param array $aResult
* @param array $aFilter
* @param string $sTargetType
*/
public function RewriteGetItemsByFilter($aResult, $aFilter, $sTargetType)
{
if (!$aResult) {
return;
}
/**
* Список на входе может быть двух видов:
* 1 - одномерный массив
* 2 - двумерный, если применялась группировка (использование '#index-group')
*
* Поэтому сначала сформируем линейный список
*/
if (isset($aFilter['#index-group']) and $aFilter['#index-group']) {
$aEntitiesWork = array();
foreach ($aResult as $aItems) {
foreach ($aItems as $oItem) {
$aEntitiesWork[] = $oItem;
}
}
} else {
$aEntitiesWork = $aResult;
}
if (!$aEntitiesWork) {
return;
}
/**
* Проверяем необходимость цеплять категории
*/
if (isset($aFilter['#with']['#category'])) {
$this->AttachCategoriesForTargetItems($aEntitiesWork, $sTargetType);
}
}
/**
* Цепляет для списка объектов категории
*
* @param array $aEntityItems
* @param string $sTargetType
*/
public function AttachCategoriesForTargetItems($aEntityItems, $sTargetType)
{
if (!is_array($aEntityItems)) {
$aEntityItems = array($aEntityItems);
}
$aEntitiesId = array();
foreach ($aEntityItems as $oEntity) {
$aEntitiesId[] = $oEntity->getId();
}
/**
* Получаем категории для всех объектов
*/
$sEntityCategory = $this->_NormalizeEntityRootName('Category');
$sEntityTarget = $this->_NormalizeEntityRootName('Target');
$aCategories = $this->GetCategoryItemsByFilter(array(
'#join' => array(
"JOIN " . Config::Get('db.table.category_target') . " category_target ON
t.id = category_target.category_id and
category_target.target_type = '{$sTargetType}' and
category_target.target_id IN ( ?a )
" => array($aEntitiesId)
),
'#select' => array(
't.*',
'category_target.target_id'
),
'#index-group' => 'target_id',
'#cache' => array(
null,
array(
$sEntityCategory . '_save',
$sEntityCategory . '_delete',
$sEntityTarget . '_save',
$sEntityTarget . '_delete'
)
)
));
/**
* Собираем данные
*/
foreach ($aEntityItems as $oEntity) {
if (isset($aCategories[$oEntity->_getPrimaryKeyValue()])) {
$oEntity->_setData(array('_categories' => $aCategories[$oEntity->_getPrimaryKeyValue()]));
} else {
$oEntity->_setData(array('_categories' => array()));
}
}
}
/**
* Возвращает дерево категорий
*
* @param int $sId Type ID
*
* @return array
*/
public function GetCategoriesTreeByType($sId)
{
$aCategories = $this->LoadTreeOfCategory(array('type_id' => $sId));
return ModuleORM::buildTree($aCategories);
}
/**
* Возвращает дерево категорий
*
* @param string $sCode Type code
*
* @return array
*/
public function GetCategoriesTreeByTargetType($sCode)
{
if ($oType = $this->GetTypeByTargetType($sCode)) {
return $this->GetCategoriesTreeByType($oType->getId());
}
return array();
}
/**
* Валидирует список категория
*
* @param array $aCategoryId
* @param int $iType
* @param bool $bReturnObjects
*
* @return array|bool
*/
public function ValidateCategoryArray($aCategoryId, $iType, $bReturnObjects = false)
{
if (!is_array($aCategoryId)) {
return false;
}
$aIds = array();
foreach ($aCategoryId as $iId) {
$aIds[] = (int)$iId;
}
if ($aIds and $aCategories = $this->GetCategoryItemsByFilter(array(
'id in' => $aIds,
'type_id' => $iType,
'#index-from-primary'
))
) {
if ($bReturnObjects) {
return $aCategories;
} else {
return array_keys($aCategories);
}
}
return false;
}
/**
* Сохраняет категории для объекта
*
* @param $oTarget
* @param $sTargetType
* @param $mCallbackCountTarget
*/
public function SaveCategories($oTarget, $sTargetType, $mCallbackCountTarget = null)
{
$aCategoriesId = $oTarget->_getDataOne('_categories_for_save');
if (!is_array($aCategoriesId)) {
return;
}
/**
* Удаляем текущие связи
*/
$aCategoryIdChanged = $this->RemoveRelation($oTarget->_getPrimaryKeyValue(), $sTargetType);
/**
* Создаем
*/
$this->CreateRelation($aCategoriesId, $oTarget->_getPrimaryKeyValue(), $sTargetType);
/**
* Полный список категорий, которые затронули изменения
*/
$aCategoryIdChanged = array_merge($aCategoryIdChanged, $aCategoriesId);
/**
* Подсчитываем количество новое элементов для каждой категории
*/
$this->UpdateCountTarget($aCategoryIdChanged, $sTargetType, $mCallbackCountTarget);
$oTarget->_setData(array('_categories_for_save' => null));
}
/**
* Обновляет количество элементов у категорий (поле count_target в таблице категорий)
*
* @param $aCategoryId
* @param $sTargetType
* @param null $mCallback
*/
protected function UpdateCountTarget($aCategoryId, $sTargetType, $mCallback = null)
{
if (!is_array($aCategoryId)) {
$aCategoryId = array($aCategoryId);
}
if (!count($aCategoryId)) {
return;
}
$aCategories = $this->GetCategoryItemsByArrayId($aCategoryId);
foreach ($aCategories as $oCategory) {
if ($mCallback) {
if (is_string($mCallback)) {
$mCallback = array($this, $mCallback);
}
$iCount = call_user_func_array($mCallback, array($oCategory, $sTargetType));
} else {
$iCount = $this->GetCountItemsByFilter(array('category_id' => $oCategory->getId()),
'ModuleCategory_EntityTarget');
}
$oCategory->setCountTarget($iCount);
$oCategory->Update();
}
}
/**
* Удаляет категории у объекта
*
* @param $oTarget
* @param $sTargetType
* @param $mCallbackCountTarget
*/
public function RemoveCategories($oTarget, $sTargetType, $mCallbackCountTarget = null)
{
$aCategoryIdChanged = $this->RemoveRelation($oTarget->_getPrimaryKeyValue(), $sTargetType);
/**
* Подсчитываем количество новое элементов для каждой категории
*/
$this->UpdateCountTarget($aCategoryIdChanged, $sTargetType, $mCallbackCountTarget);
}
/**
* Создает новую связь конкретного объекта с категориями
*
* @param array $aCategoryId
* @param int $iTargetId
* @param int|string $iType type_id или target_type
*
* @return bool
*/
public function CreateRelation($aCategoryId, $iTargetId, $iType)
{
if (!$aCategoryId or (is_array($aCategoryId) and !count($aCategoryId))) {
return false;
}
if (!is_array($aCategoryId)) {
$aCategoryId = array($aCategoryId);
}
if (is_numeric($iType)) {
$oType = $this->GetTypeById($iType);
} else {
$oType = $this->GetTypeByTargetType($iType);
}
if (!$oType) {
return false;
}
foreach ($aCategoryId as $iCategoryId) {
if (!$this->GetTargetByCategoryIdAndTargetIdAndTypeId($iCategoryId, $iTargetId, $oType->getId())) {
$oTarget = Engine::GetEntity('ModuleCategory_EntityTarget');
$oTarget->setCategoryId($iCategoryId);
$oTarget->setTargetId($iTargetId);
$oTarget->setTargetType($oType->getTargetType());
$oTarget->setTypeId($oType->getId());
$oTarget->Add();
}
}
return true;
}
/**
* Удаляет связь конкретного объекта с категориями
*
* @param int $iTargetId
* @param int|string $iType type_id или target_type
*
* @return bool|array
*/
public function RemoveRelation($iTargetId, $iType)
{
if (!is_numeric($iType)) {
if ($oType = $this->GetTypeByTargetType($iType)) {
$iType = $oType->getId();
} else {
return false;
}
}
$aRemovedCategory = array();
$aTargets = $this->GetTargetItemsByTargetIdAndTypeId($iTargetId, $iType);
foreach ($aTargets as $oTarget) {
$oTarget->Delete();
$aRemovedCategory[] = $oTarget->getCategoryId();
}
return $aRemovedCategory;
}
/**
* Возвращает список категорий по категории
*
* @param $oCategory
* @param bool $bIncludeChild Возвращать все дочернии категории
*
* @return array|null
*/
public function GetCategoriesIdByCategory($oCategory, $bIncludeChild = false)
{
if (is_object($oCategory)) {
$iCategoryId = $oCategory->getId();
} else {
$iCategoryId = $oCategory;
}
$aCategoryId = array($iCategoryId);
if ($bIncludeChild) {
/**
* Сначала получаем полный список категорий текущего типа
*/
if (!is_object($oCategory)) {
$oCategory = $this->GetCategoryById($iCategoryId);
}
if ($oCategory) {
if ($aChildren = $oCategory->getDescendants()) {
foreach ($aChildren as $oCategoryChild) {
$aCategoryId[] = $oCategoryChild->getId();
}
}
}
}
return $aCategoryId;
}
/**
* Пересобирает полные URL дочерних категорий
*
* @param $oCategoryStart
* @param bool $bStart
*/
public function RebuildCategoryUrlFull($oCategoryStart, $bStart = true)
{
static $aRebuildIds;
if ($bStart) {
$aRebuildIds = array();
}
if (is_null($oCategoryStart->getId())) {
$aCategories = $this->GetCategoryItemsByFilter(array(
'#where' => array('pid is null' => array()),
'type_id' => $oCategoryStart->getTypeId()
));
} else {
$aCategories = $this->GetCategoryItemsByFilter(array(
'pid' => $oCategoryStart->getId(),
'type_id' => $oCategoryStart->getTypeId()
));
}
foreach ($aCategories as $oCategory) {
if ($oCategory->getId() == $oCategoryStart->getId()) {
continue;
}
if (in_array($oCategory->getId(), $aRebuildIds)) {
continue;
}
$aRebuildIds[] = $oCategory->getId();
$oCategory->setUrlFull($oCategoryStart->getUrlFull() . '/' . $oCategory->getUrl());
$oCategory->Update();
$this->RebuildCategoryUrlFull($oCategory, false);
}
}
/**
* Возвращает список ID таргетов по списку категорий
*
* @param $aCategoryId
* @param $sTargetType
* @param $iPage
* @param $iPerPage
*
* @return array
*/
public function GetTargetIdsByCategoriesId($aCategoryId, $sTargetType, $iPage, $iPerPage)
{
if (!is_array($aCategoryId)) {
$aCategoryId = array($aCategoryId);
}
if (!count($aCategoryId)) {
return array();
}
$aTargetItems = $this->GetTargetItemsByFilter(array(
'category_id in' => $aCategoryId,
'target_type' => $sTargetType,
'#page' => array($iPage, $iPerPage),
'#index-from' => 'target_id'
));
return array_keys($aTargetItems['collection']);
}
/**
* Возвращает список ID таргетов по категории
*
* @param $oCategory
* @param $sTargetType
* @param $iPage
* @param $iPerPage
* @param bool $bIncludeChild
*
* @return array
*/
public function GetTargetIdsByCategory($oCategory, $sTargetType, $iPage, $iPerPage, $bIncludeChild = false)
{
$aCategoryId = $this->GetCategoriesIdByCategory($oCategory, $bIncludeChild);
return $this->GetTargetIdsByCategoriesId($aCategoryId, $sTargetType, $iPage, $iPerPage);
}
/**
* Создает новый тип объекта в БД для категорий
*
* @param string $sType
* @param string $sTitle
* @param array $aParams
* @param bool $bRewrite
*
* @return bool|ModuleCategory_EntityType
*/
public function CreateTargetType($sType, $sTitle, $aParams = array(), $bRewrite = false)
{
/**
* Проверяем есть ли уже такой тип
*/
if ($oType = $this->GetTypeByTargetType($sType)) {
if (!$bRewrite) {
return false;
}
} else {
$oType = Engine::GetEntity('ModuleCategory_EntityType');
$oType->setTargetType($sType);
}
$oType->setState(self::TARGET_STATE_ACTIVE);
$oType->setTitle(htmlspecialchars($sTitle));
$oType->setParams($aParams);
if ($oType->Save()) {
return $oType;
}
return false;
}
/**
* Отключает тип объекта для категорий
*
* @param string $sType
* @param int $iState self::TARGET_STATE_NOT_ACTIVE или self::TARGET_STATE_REMOVE
*/
public function RemoveTargetType($sType, $iState = self::TARGET_STATE_NOT_ACTIVE)
{
if ($oType = $this->GetTypeByTargetType($sType)) {
$oType->setState($iState);
$oType->Save();
}
}
/**
* Парсинг текста с учетом конкретной категории
*
* @param string $sText
* @param ModuleCategory_EntityCategory $oCategory
*
* @return string
*/
public function ParserText($sText, $oCategory)
{
$this->Text_AddParams(array('oCategory' => $oCategory));
$sResult = $this->Text_Parser($sText);
$this->Text_RemoveParams(array('oCategory'));
return $sResult;
}
}

View file

@ -0,0 +1,237 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Поведение, которое необходимо добавлять к сущности (entity) у которой добавляются категории
*
* @package application.modules.category
* @since 2.0
*/
class ModuleCategory_BehaviorEntity extends Behavior
{
/**
* Дефолтные параметры
*
* @var array
*/
protected $aParams = array(
// Уникальный код
'target_type' => '',
// Имя инпута (select) на форме, который содержит список категорий
'form_field' => 'categories',
// Автоматически брать текущую категорию из реквеста
'form_fill_current_from_request' => true,
// Возможность выбирать несколько категорий
'multiple' => false,
// Автоматическая валидация категорий (актуально при ORM)
'validate_enable' => true,
// Поле сущности, в котором хранятся категории. Если null, то используется имя из form_field
'validate_field' => null,
// Обязательное заполнение категории
'validate_require' => false,
// Получать значение валидации не из сущности, а из реквеста (используется поле form_field)
'validate_from_request' => false,
// Минимальное количество категорий, доступное для выбора
'validate_min' => 1,
// Максимальное количество категорий, доступное для выбора
'validate_max' => 5,
// Возможность выбрать только те категории, у которых нет дочерних
'validate_only_without_children' => false,
// Колбек для подсчета количества объектов у категории. Необходим, например, если необходимо учитывать объекты только с определенным статусом (доступен для публикации).
// Указывать можно строкой с полным вызовом метода модуля, например, "PluginArticle_Main_GetCountArticle"
// В качестве параметров передается список ID категорий и тип
'callback_count_target' => null,
);
/**
* Список хуков
*
* @var array
*/
protected $aHooks = array(
'validate_after' => 'CallbackValidateAfter',
'after_save' => 'CallbackAfterSave',
'after_delete' => 'CallbackAfterDelete',
);
/**
* Инициализация
*/
protected function Init()
{
parent::Init();
if (!$this->getParam('validate_field')) {
$this->aParams['validate_field'] = $this->getParam('form_field');
}
}
/**
* Коллбэк
* Выполняется при инициализации сущности
*
* @param $aParams
*/
public function CallbackValidateAfter($aParams)
{
if ($aParams['bResult'] and $this->getParam('validate_enable')) {
$aFields = $aParams['aFields'];
if (is_null($aFields) or in_array($this->getParam('validate_field'), $aFields)) {
$oValidator = $this->Validate_CreateValidator('categories_check', $this,
$this->getParam('validate_field'));
$oValidator->validateEntity($this->oObject, $aFields);
$aParams['bResult'] = !$this->oObject->_hasValidateErrors();
}
}
}
/**
* Коллбэк
* Выполняется после сохранения сущности
*/
public function CallbackAfterSave()
{
$this->Category_SaveCategories($this->oObject, $this->getParam('target_type'),
$this->getParam('callback_count_target'));
}
/**
* Коллбэк
* Выполняется после удаления сущности
*/
public function CallbackAfterDelete()
{
$this->Category_RemoveCategories($this->oObject, $this->getParam('target_type'),
$this->getParam('callback_count_target'));
}
/**
* Дополнительный метод для сущности
* Запускает валидацию дополнительных полей
*
* @param $mValue
*
* @return bool|string
*/
public function ValidateCategoriesCheck($mValue)
{
/**
* Проверяем тип категрий
*/
if (!$oTypeCategory = $this->Category_GetTypeByTargetType($this->getParam('target_type'))) {
return 'Неверный тип категорий';
}
if ($this->getParam('validate_from_request')) {
$mValue = getRequest($this->getParam('form_field'));
}
/**
* Значение может быть числом, массивом, строкой с разделением через запятую
*/
if (!is_array($mValue)) {
if ($this->getParam('multiple')) {
$mValue = explode(',', $mValue);
} else {
$mValue = array($mValue);
}
}
/**
* Проверяем наличие категорий в БД
*/
$aCategories = $this->Category_ValidateCategoryArray($mValue, $oTypeCategory->getId(), true);
if (!$aCategories) {
$aCategories = array();
}
if ($this->getParam('validate_require') and !$aCategories) {
return $this->Lang_Get('category.notices.validate_require');
}
if (!$this->getParam('multiple') and count($aCategories) > 1) {
$aCategories = array_slice($aCategories, 0, 1);
}
if ($this->getParam('multiple') and $aCategories and (count($aCategories) < $this->getParam('validate_min') or count($aCategories) > $this->getParam('validate_max'))) {
return $this->Lang_Get('category.notices.validate_count',
array('min' => $this->getParam('validate_min'), 'max' => $this->getParam('validate_max')));
}
if ($this->getParam('validate_only_without_children')) {
foreach ($aCategories as $oCategory) {
if ($oCategory->getChildren()) {
return $this->Lang_Get('category.notices.validate_children');
}
}
}
/**
* Сохраняем необходимый список категорий для последующего сохранения в БД
*/
$this->oObject->_setData(array('_categories_for_save' => array_keys($aCategories)));
return true;
}
/**
* Возвращает список категорий сущности
*
* @return array
*/
public function getCategories()
{
return $this->Category_GetEntityCategories($this->oObject, $this->getCategoryTargetType());
}
/**
* Возвращает количество категорий
*
* @return array
*/
public function getCountCategories()
{
return count($this->getCategories());
}
/**
* Возвращает одну категорию сущности
* Если объект может иметь несколько категорий, то вернется первая
*
* @return ModuleCategory_EntityCategory|null
*/
public function getCategory()
{
$aCategories = $this->getCategories();
$oCategory = reset($aCategories);
return $oCategory ? $oCategory : null;
}
/**
* Возвращает тип объекта для категорий
*
* @return string
*/
public function getCategoryTargetType()
{
if ($sType = $this->getParam('target_type')) {
return $sType;
}
/**
* Иначе дополнительно смотрим на наличие данного метода у сущности
* Это необходимо, если тип вычисляется динамически по какой-то своей логике
*/
if (func_method_exists($this->oObject, 'getCategoryTargetType', 'public')) {
return call_user_func(array($this->oObject, 'getCategoryTargetType'));
}
}
}

View file

@ -0,0 +1,107 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Поведение, которое необходимо добавлять к ORM модулю сущности у которой добавляются категории
*
* @package application.modules.category
* @since 2.0
*/
class ModuleCategory_BehaviorModule extends Behavior
{
/**
* Дефолтные параметры
*
* @var array
*/
protected $aParams = array(
'target_type' => '',
);
/**
* Список хуков
*
* @var array
*/
protected $aHooks = array(
'module_orm_GetItemsByFilter_after' => array(
'CallbackGetItemsByFilterAfter',
1000
),
'module_orm_GetItemsByFilter_before' => array(
'CallbackGetItemsByFilterBefore',
1000
),
'module_orm_GetByFilter_before' => array(
'CallbackGetItemsByFilterBefore',
1000
),
);
/**
* Модифицирует фильтр в ORM запросе
*
* @param $aParams
*/
public function CallbackGetItemsByFilterAfter($aParams)
{
$aEntities = $aParams['aEntities'];
$aFilter = $aParams['aFilter'];
$this->Category_RewriteGetItemsByFilter($aEntities, $aFilter, $this->getParam('target_type'));
}
/**
* Модифицирует результат ORM запроса
*
* @param $aParams
*/
public function CallbackGetItemsByFilterBefore($aParams)
{
$aFilter = $this->Category_RewriteFilter($aParams['aFilter'], $aParams['sEntityFull'],
$this->getParam('target_type'));
$aParams['aFilter'] = $aFilter;
}
/**
* Возвращает дерево категорий
*
* @return mixed
*/
public function GetCategoriesTree()
{
return $this->Category_GetCategoriesTreeByTargetType($this->getParam('target_type'));
}
/**
* Возвращает список ID объектов (элементов), которые принадлежат категории
*
* @param $oCategory
* @param $iPage
* @param $iPerPage
* @param bool $bIncludeChild
*
* @return mixed
*/
public function GetTargetIdsByCategory($oCategory, $iPage, $iPerPage, $bIncludeChild = false)
{
return $this->Category_GetTargetIdsByCategory($oCategory, $this->getParam('target_type'), $iPage, $iPerPage,
$bIncludeChild);
}
}

View file

@ -0,0 +1,280 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Сущность категории
*
* @package application.modules.category
* @since 2.0
*/
class ModuleCategory_EntityCategory extends EntityORM
{
/**
* Определяем правила валидации
*
* @var array
*/
protected $aValidateRules = array(
array('title', 'string', 'max' => 200, 'min' => 1, 'allowEmpty' => false),
array('description', 'string', 'max' => 5000, 'min' => 1, 'allowEmpty' => true),
array('url', 'regexp', 'pattern' => '/^[\w\-_]+$/i', 'allowEmpty' => false),
array('order', 'number', 'integerOnly' => true),
array('pid', 'parent_category'),
array('order', 'order_check'),
);
protected $aRelations = array(
'type' => array(self::RELATION_TYPE_BELONGS_TO, 'ModuleCategory_EntityType', 'type_id'),
self::RELATION_TYPE_TREE
);
/**
* Проверка родительской категории
*
* @param string $sValue Валидируемое значение
* @param array $aParams Параметры
* @return bool
*/
public function ValidateParentCategory($sValue, $aParams)
{
if ($this->getPid()) {
if ($oCategory = $this->Category_GetCategoryById($this->getPid())) {
if ($oCategory->getId() == $this->getId()) {
return $this->Lang_Get('category.notices.validate_recursion');
}
if ($oCategory->getTypeId() != $this->getTypeId()) {
return $this->Lang_Get('category.notices.validate_parent');
}
$this->setUrlFull($oCategory->getUrlFull() . '/' . $this->getUrl());
} else {
return $this->Lang_Get('category.notices.validate_wrong');
}
} else {
$this->setPid(null);
$this->setUrlFull($this->getUrl());
}
return true;
}
/**
* Установка дефолтной сортировки
*
* @param string $sValue Валидируемое значение
* @param array $aParams Параметры
* @return bool
*/
public function ValidateOrderCheck($sValue, $aParams)
{
if (!$this->getSort()) {
$this->setSort(100);
}
return true;
}
/**
* Выполняется перед удалением
*
* @return bool
*/
protected function beforeDelete()
{
if ($bResult = parent::beforeDelete()) {
/**
* Запускаем удаление дочерних категорий
*/
if ($aCildren = $this->getChildren()) {
foreach ($aCildren as $oChildren) {
$oChildren->Delete();
}
}
/**
* Удаляем связь с таргетом
*/
if ($aTargets = $this->Category_GetTargetItemsByCategoryId($this->getId())) {
foreach ($aTargets as $oTarget) {
$oTarget->Delete();
/**
* TODO: Нужно запустить хук, что мы удалили такую-то связь
*/
}
}
}
return $bResult;
}
/**
* Переопределяем имя поля с родителем
* Т.к. по дефолту в деревьях используется поле parent_id
*
* @return string
*/
public function _getTreeParentKey()
{
return 'pid';
}
/**
* Выполняется перед сохранением
*
* @return bool
*/
protected function beforeSave()
{
if ($bResult = parent::beforeSave()) {
if ($this->_isNew()) {
$this->setDateCreate(date("Y-m-d H:i:s"));
}
}
return $bResult;
}
/**
* Возвращает URL категории
* Этот метод необходимо переопределить из плагина и возвращать свой URL для нужного типа категорий
*
* @return string
*/
public function getWebUrl()
{
return null;
}
/**
* Возвращает объект типа категории с использованием кеширования на время сессии
*
* @return ModuleCategory_EntityType
*/
public function getTypeByCacheLife()
{
$sKey = 'category_type_' . (string)$this->getTypeId();
if (false === ($oType = $this->Cache_GetLife($sKey))) {
$oType = $this->getType();
$this->Cache_SetLife($oType, $sKey);
}
return $oType;
}
/**
* Возвращает URL админки для редактирования
*
* @return string
*/
public function getUrlAdminUpdate()
{
return Router::GetPath('admin/categories/' . $this->getTypeByCacheLife()->getTargetType() . '/update/' . $this->getId());
}
/**
* Возвращает URL админки для удаления
*
* @return string
*/
public function getUrlAdminRemove()
{
return Router::GetPath('admin/categories/' . $this->getTypeByCacheLife()->getTargetType() . '/remove/' . $this->getId());
}
/**
* Возвращает список дополнительных данных
*
* @return array|mixed
*/
public function getData()
{
$aData = @unserialize($this->_getDataOne('data'));
if (!$aData) {
$aData = array();
}
return $aData;
}
/**
* Устанавливает список дополнительня данных
*
* @param $aRules
*/
public function setData($aRules)
{
$this->_aData['data'] = @serialize($aRules);
}
/**
* Возвращает данные по конкретному ключу
*
* @param $sKey
*
* @return null
*/
public function getDataOne($sKey)
{
$aData = $this->getData();
if (isset($aData[$sKey])) {
return $aData[$sKey];
}
return null;
}
/**
* Устанваливает данные для конкретного ключа
*
* @param $sKey
* @param $mValue
*/
public function setDataOne($sKey, $mValue)
{
$aData = $this->getData();
$aData[$sKey] = $mValue;
$this->setData($aData);
}
/**
* Возвращает сумму значений по ключу для всех потомков, включая себя
*
* @param $sKey
*
* @return null
*/
public function getDataOneSumDescendants($sKey)
{
$iResult = $this->getDataOne($sKey);
$aChildren = $this->getDescendants();
foreach ($aChildren as $oItem) {
$iResult += $oItem->getDataOne($sKey);
}
return $iResult;
}
/**
* Возвращает количество таргетов (объектов) для всех потомков, включая себя
*
* @return mixed
*/
public function getCountTargetOfDescendants()
{
$iCount = $this->getCountTarget();
$aChildren = $this->getDescendants();
foreach ($aChildren as $oItem) {
$iCount += $oItem->getCountTarget();
}
return $iCount;
}
}

View file

@ -0,0 +1,47 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Сущность связи категории с объектами
*
* @package application.modules.category
* @since 2.0
*/
class ModuleCategory_EntityTarget extends EntityORM
{
protected $aRelations = array();
/**
* Выполняется перед сохранением
*
* @return bool
*/
protected function beforeSave()
{
if ($bResult = parent::beforeSave()) {
if ($this->_isNew()) {
$this->setDateCreate(date("Y-m-d H:i:s"));
}
}
return $bResult;
}
}

View file

@ -0,0 +1,86 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Сущность типа категории
*
* @package application.modules.category
* @since 2.0
*/
class ModuleCategory_EntityType extends EntityORM
{
protected $aRelations = array();
/**
* Выполняется перед сохранением
*
* @return bool
*/
protected function beforeSave()
{
if ($bResult = parent::beforeSave()) {
if ($this->_isNew()) {
$this->setDateCreate(date("Y-m-d H:i:s"));
} else {
$this->setDateUpdate(date("Y-m-d H:i:s"));
}
}
return $bResult;
}
/**
* Возвращает список дополнительных параметров
*
* @return array|mixed
*/
public function getParams()
{
$aData = @unserialize($this->_getDataOne('params'));
if (!$aData) {
$aData = array();
}
return $aData;
}
/**
* Устанавливает список дополнительных параметров
*
* @param $aParams
*/
public function setParams($aParams)
{
$this->_aData['params'] = @serialize($aParams);
}
/**
* Возвращает конкретный параметр
*
* @param $sName
*
* @return null
*/
public function getParam($sName)
{
$aParams = $this->getParams();
return isset($aParams[$sName]) ? $aParams[$sName] : null;
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,578 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Объект сущности комментариев
*
* @package application.modules.comment
* @since 1.0
*/
class ModuleComment_EntityComment extends Entity
{
/**
* Возвращает ID коммента
*
* @return int|null
*/
public function getId()
{
return $this->_getDataOne('comment_id');
}
/**
* Возвращает ID родительского коммента
*
* @return int|null
*/
public function getPid()
{
return $this->_getDataOne('comment_pid');
}
/**
* Возвращает значение left для дерева nested set
*
* @return int|null
*/
public function getLeft()
{
return $this->_getDataOne('comment_left');
}
/**
* Возвращает значение right для дерева nested set
*
* @return int|null
*/
public function getRight()
{
return $this->_getDataOne('comment_right');
}
/**
* Возвращает ID владельца
*
* @return int|null
*/
public function getTargetId()
{
return $this->_getDataOne('target_id');
}
/**
* Возвращает тип владельца
*
* @return string|null
*/
public function getTargetType()
{
return $this->_getDataOne('target_type');
}
/**
* Возвращет ID родителя владельца
*
* @return int|null
*/
public function getTargetParentId()
{
return $this->_getDataOne('target_parent_id') ? $this->_getDataOne('target_parent_id') : 0;
}
/**
* Возвращает ID пользователя, автора комментария
*
* @return int|null
*/
public function getUserId()
{
return $this->_getDataOne('user_id');
}
/**
* Возвращает текст комментария
*
* @return string|null
*/
public function getText()
{
return $this->_getDataOne('comment_text');
}
/**
* Возвращает исходный текст комментария
*
* @return string|null
*/
public function getTextSource()
{
return $this->_getDataOne('comment_text_source') ? $this->_getDataOne('comment_text_source') : '';
}
/**
* Возвращает дату комментария
*
* @return string|null
*/
public function getDate()
{
return $this->_getDataOne('comment_date');
}
/**
* Возвращает дату последнего редактирования комментария
*
* @return string|null
*/
public function getDateEdit()
{
return $this->_getDataOne('comment_date_edit');
}
/**
* Возвращает IP пользователя
*
* @return string|null
*/
public function getUserIp()
{
return $this->_getDataOne('comment_user_ip');
}
/**
* Возвращает рейтинг комментария
*
* @return string
*/
public function getRating()
{
return number_format(round($this->_getDataOne('comment_rating'), 2), 0, '.', '');
}
/**
* Возвращает количество проголосовавших
*
* @return int|null
*/
public function getCountVote()
{
return $this->_getDataOne('comment_count_vote');
}
/**
* Возвращает количество редактирований комментария
*
* @return int|null
*/
public function getCountEdit()
{
return $this->_getDataOne('comment_count_edit');
}
/**
* Возвращает флаг удаленного комментария
*
* @return int|null
*/
public function getDelete()
{
return $this->_getDataOne('comment_delete');
}
/**
* Возвращает флаг опубликованного комментария
*
* @return int
*/
public function getPublish()
{
return $this->_getDataOne('comment_publish') ? 1 : 0;
}
/**
* Возвращает хеш комментария
*
* @return string|null
*/
public function getTextHash()
{
return $this->_getDataOne('comment_text_hash');
}
/**
* Возвращает уровень вложенности комментария
*
* @return int|null
*/
public function getLevel()
{
return $this->_getDataOne('comment_level');
}
/**
* Проверяет является ли комментарий плохим
*
* @return bool
*/
public function isBad()
{
if ($this->getRating() <= Config::Get('module.comment.bad')) {
return true;
}
return false;
}
/**
* Возвращает объект пользователя
*
* @return ModuleUser_EntityUser|null
*/
public function getUser()
{
return $this->_getDataOne('user');
}
/**
* Возвращает объект владельца
*
* @return mixed|null
*/
public function getTarget()
{
return $this->_getDataOne('target');
}
/**
* Возвращает объект голосования
*
* @return ModuleVote_EntityVote|null
*/
public function getVote()
{
return $this->_getDataOne('vote');
}
/**
* Проверяет является ли комментарий избранным у текущего пользователя
*
* @return bool|null
*/
public function getIsFavourite()
{
return $this->_getDataOne('comment_is_favourite');
}
/**
* Возвращает количество избранного
*
* @return int|null
*/
public function getCountFavourite()
{
return $this->_getDataOne('comment_count_favourite');
}
/**
* Проверка на разрешение редактировать комментарий
*
* @return mixed
*/
public function isAllowEdit()
{
return $this->ACL_IsAllowEditComment($this, $this->User_GetUserCurrent());
}
/**
* Возвращает количество секунд в течении которых возможно редактирование
*
* @return int
*/
public function getEditTimeRemaining()
{
$oUser = $this->User_GetUserCurrent();
if (($oUser and $oUser->isAdministrator()) or !Config::Get('acl.update.comment.limit_time')) {
return 0;
}
$iTime = Config::Get('acl.update.comment.limit_time') - (time() - strtotime($this->getDate()));
return $iTime > 0 ? $iTime : 0;
}
/**
* Проверка на разрешение удалить комментарий
*
* @return mixed
*/
public function isAllowDelete()
{
return $this->ACL_IsAllowDeleteComment($this, $this->User_GetUserCurrent());
}
/**
* Устанавливает ID комментария
*
* @param int $data
*/
public function setId($data)
{
$this->_aData['comment_id'] = $data;
}
/**
* Устанавливает ID родительского комментария
*
* @param int $data
*/
public function setPid($data)
{
$this->_aData['comment_pid'] = $data;
}
/**
* Устанавливает значени left для дерева nested set
*
* @param int $data
*/
public function setLeft($data)
{
$this->_aData['comment_left'] = $data;
}
/**
* Устанавливает значени right для дерева nested set
*
* @param int $data
*/
public function setRight($data)
{
$this->_aData['comment_right'] = $data;
}
/**
* Устанавливает ID владельца
*
* @param int $data
*/
public function setTargetId($data)
{
$this->_aData['target_id'] = $data;
}
/**
* Устанавливает тип владельца
*
* @param string $data
*/
public function setTargetType($data)
{
$this->_aData['target_type'] = $data;
}
/**
* Устанавливает ID родителя владельца
*
* @param int $data
*/
public function setTargetParentId($data)
{
$this->_aData['target_parent_id'] = $data;
}
/**
* Устанавливает ID пользователя
*
* @param int $data
*/
public function setUserId($data)
{
$this->_aData['user_id'] = $data;
}
/**
* Устанавливает текст комментария
*
* @param string $data
*/
public function setText($data)
{
$this->_aData['comment_text'] = $data;
}
/**
* Устанавливает исходный текст комментария
*
* @param string $data
*/
public function setTextSource($data)
{
$this->_aData['comment_text_source'] = $data;
}
/**
* Устанавливает дату комментария
*
* @param string $data
*/
public function setDate($data)
{
$this->_aData['comment_date'] = $data;
}
/**
* Устанавливает дату последнего редактирования комментария
*
* @param string $data
*/
public function setDateEdit($data)
{
$this->_aData['comment_date_edit'] = $data;
}
/**
* Устанавливает IP пользователя
*
* @param string $data
*/
public function setUserIp($data)
{
$this->_aData['comment_user_ip'] = $data;
}
/**
* Устанавливает рейтинг комментария
*
* @param float $data
*/
public function setRating($data)
{
$this->_aData['comment_rating'] = $data;
}
/**
* Устанавливает количество проголосавших
*
* @param int $data
*/
public function setCountVote($data)
{
$this->_aData['comment_count_vote'] = $data;
}
/**
* Устанавливает количество редактирований комментария
*
* @param int $data
*/
public function setCountEdit($data)
{
$this->_aData['comment_count_edit'] = $data;
}
/**
* Устанавливает флаг удаленности комментария
*
* @param int $data
*/
public function setDelete($data)
{
$this->_aData['comment_delete'] = $data;
}
/**
* Устанавливает флаг публикации
*
* @param int $data
*/
public function setPublish($data)
{
$this->_aData['comment_publish'] = $data;
}
/**
* Устанавливает хеш комментария
*
* @param strign $data
*/
public function setTextHash($data)
{
$this->_aData['comment_text_hash'] = $data;
}
/**
* Устанавливает уровень вложенности комментария
*
* @param int $data
*/
public function setLevel($data)
{
$this->_aData['comment_level'] = $data;
}
/**
* Устаналвает объект пользователя
*
* @param ModuleUser_EntityUser $data
*/
public function setUser($data)
{
$this->_aData['user'] = $data;
}
/**
* Устанавливает объект владельца
*
* @param mixed $data
*/
public function setTarget($data)
{
$this->_aData['target'] = $data;
}
/**
* Устанавливает объект голосования
*
* @param ModuleVote_EntityVote $data
*/
public function setVote($data)
{
$this->_aData['vote'] = $data;
}
/**
* Устанавливает факт нахождения комментария в избранном у текущего пользователя
*
* @param bool $data
*/
public function setIsFavourite($data)
{
$this->_aData['comment_is_favourite'] = $data;
}
/**
* Устанавливает количество избранного
*
* @param int $data
*/
public function setCountFavourite($data)
{
$this->_aData['comment_count_favourite'] = $data;
}
}

View file

@ -0,0 +1,109 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Объект сущности прямого эфира
*
* @package application.modules.comment
* @since 1.0
*/
class ModuleComment_EntityCommentOnline extends Entity
{
/**
* Возвращает ID владельца
*
* @return int|null
*/
public function getTargetId()
{
return $this->_getDataOne('target_id');
}
/**
* Возвращает тип владельца
*
* @return string|null
*/
public function getTargetType()
{
return $this->_getDataOne('target_type');
}
/**
* Возвращает ID комментария
*
* @return int|null
*/
public function getCommentId()
{
return $this->_getDataOne('comment_id');
}
/**
* Возвращает ID родителя владельца
*
* @return int
*/
public function getTargetParentId()
{
return $this->_getDataOne('target_parent_id') ? $this->_getDataOne('target_parent_id') : 0;
}
/**
* Устанавливает ID владельца
*
* @param int $data
*/
public function setTargetId($data)
{
$this->_aData['target_id'] = $data;
}
/**
* Устанавливает тип владельца
*
* @param string $data
*/
public function setTargetType($data)
{
$this->_aData['target_type'] = $data;
}
/**
* Устанавливает ID комментария
*
* @param int $data
*/
public function setCommentId($data)
{
$this->_aData['comment_id'] = $data;
}
/**
* Устанавливает ID родителя владельца
*
* @param int $data
*/
public function setTargetParentId($data)
{
$this->_aData['target_parent_id'] = $data;
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,534 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Модуль для работы с избранным
*
* @package application.modules.favourite
* @since 1.0
*/
class ModuleFavourite extends Module
{
/**
* Объект маппера
*
* @var ModuleFavourite_MapperFavourite
*/
protected $oMapper;
/**
* Инициализация
*
*/
public function Init()
{
$this->oMapper = Engine::GetMapper(__CLASS__);
}
/**
* Получает информацию о том, найден ли таргет в избранном или нет
*
* @param int $sTargetId ID владельца
* @param string $sTargetType Тип владельца
* @param int $sUserId ID пользователя
* @return ModuleFavourite_EntityFavourite|null
*/
public function GetFavourite($sTargetId, $sTargetType, $sUserId)
{
if (!is_numeric($sTargetId) or !is_string($sTargetType)) {
return null;
}
$data = $this->GetFavouritesByArray($sTargetId, $sTargetType, $sUserId);
return (isset($data[$sTargetId]))
? $data[$sTargetId]
: null;
}
/**
* Получить список избранного по списку айдишников
*
* @param array $aTargetId Список ID владельцев
* @param string $sTargetType Тип владельца
* @param int $sUserId ID пользователя
* @return array
*/
public function GetFavouritesByArray($aTargetId, $sTargetType, $sUserId)
{
if (!$aTargetId) {
return array();
}
if (Config::Get('sys.cache.solid')) {
return $this->GetFavouritesByArraySolid($aTargetId, $sTargetType, $sUserId);
}
if (!is_array($aTargetId)) {
$aTargetId = array($aTargetId);
}
$aTargetId = array_unique($aTargetId);
$aFavourite = array();
$aIdNotNeedQuery = array();
/**
* Делаем мульти-запрос к кешу
*/
$aCacheKeys = func_build_cache_keys($aTargetId, "favourite_{$sTargetType}_", '_' . $sUserId);
if (false !== ($data = $this->Cache_Get($aCacheKeys))) {
/**
* проверяем что досталось из кеша
*/
foreach ($aCacheKeys as $sValue => $sKey) {
if (array_key_exists($sKey, $data)) {
if ($data[$sKey]) {
$aFavourite[$data[$sKey]->getTargetId()] = $data[$sKey];
} else {
$aIdNotNeedQuery[] = $sValue;
}
}
}
}
/**
* Смотрим чего не было в кеше и делаем запрос в БД
*/
$aIdNeedQuery = array_diff($aTargetId, array_keys($aFavourite));
$aIdNeedQuery = array_diff($aIdNeedQuery, $aIdNotNeedQuery);
$aIdNeedStore = $aIdNeedQuery;
if ($data = $this->oMapper->GetFavouritesByArray($aIdNeedQuery, $sTargetType, $sUserId)) {
foreach ($data as $oFavourite) {
/**
* Добавляем к результату и сохраняем в кеш
*/
$aFavourite[$oFavourite->getTargetId()] = $oFavourite;
$this->Cache_Set($oFavourite,
"favourite_{$oFavourite->getTargetType()}_{$oFavourite->getTargetId()}_{$sUserId}", array(),
60 * 60 * 24 * 7);
$aIdNeedStore = array_diff($aIdNeedStore, array($oFavourite->getTargetId()));
}
}
/**
* Сохраняем в кеш запросы не вернувшие результата
*/
foreach ($aIdNeedStore as $sId) {
$this->Cache_Set(null, "favourite_{$sTargetType}_{$sId}_{$sUserId}", array(), 60 * 60 * 24 * 7);
}
/**
* Сортируем результат согласно входящему массиву
*/
$aFavourite = func_array_sort_by_keys($aFavourite, $aTargetId);
return $aFavourite;
}
/**
* Получить список избранного по списку айдишников, но используя единый кеш
*
* @param array $aTargetId Список ID владельцев
* @param string $sTargetType Тип владельца
* @param int $sUserId ID пользователя
* @return array
*/
public function GetFavouritesByArraySolid($aTargetId, $sTargetType, $sUserId)
{
if (!is_array($aTargetId)) {
$aTargetId = array($aTargetId);
}
$aTargetId = array_unique($aTargetId);
$aFavourites = array();
$s = join(',', $aTargetId);
if (false === ($data = $this->Cache_Get("favourite_{$sTargetType}_{$sUserId}_id_{$s}"))) {
$data = $this->oMapper->GetFavouritesByArray($aTargetId, $sTargetType, $sUserId);
foreach ($data as $oFavourite) {
$aFavourites[$oFavourite->getTargetId()] = $oFavourite;
}
$this->Cache_Set($aFavourites, "favourite_{$sTargetType}_{$sUserId}_id_{$s}",
array("favourite_{$sTargetType}_change_user_{$sUserId}"), 60 * 60 * 24 * 1);
return $aFavourites;
}
return $data;
}
/**
* Получает список таргетов из избранного
*
* @param int $sUserId ID пользователя
* @param string $sTargetType Тип владельца
* @param int $iCurrPage Номер страницы
* @param int $iPerPage Количество элементов на страницу
* @param array $aExcludeTarget Список ID владельцев для исклчения
* @return array
*/
public function GetFavouritesByUserId($sUserId, $sTargetType, $iCurrPage, $iPerPage, $aExcludeTarget = array())
{
$s = serialize($aExcludeTarget);
if (false === ($data = $this->Cache_Get("{$sTargetType}_favourite_user_{$sUserId}_{$iCurrPage}_{$iPerPage}_{$s}"))) {
$data = array(
'collection' => $this->oMapper->GetFavouritesByUserId($sUserId, $sTargetType, $iCount, $iCurrPage,
$iPerPage, $aExcludeTarget),
'count' => $iCount
);
$this->Cache_Set(
$data,
"{$sTargetType}_favourite_user_{$sUserId}_{$iCurrPage}_{$iPerPage}_{$s}",
array(
"favourite_{$sTargetType}_change",
"favourite_{$sTargetType}_change_user_{$sUserId}"
),
60 * 60 * 24 * 1
);
}
return $data;
}
/**
* Возвращает число таргетов определенного типа в избранном по ID пользователя
*
* @param int $sUserId ID пользователя
* @param string $sTargetType Тип владельца
* @param array $aExcludeTarget Список ID владельцев для исклчения
* @return array
*/
public function GetCountFavouritesByUserId($sUserId, $sTargetType, $aExcludeTarget = array())
{
$s = serialize($aExcludeTarget);
if (false === ($data = $this->Cache_Get("{$sTargetType}_count_favourite_user_{$sUserId}_{$s}"))) {
$data = $this->oMapper->GetCountFavouritesByUserId($sUserId, $sTargetType, $aExcludeTarget);
$this->Cache_Set(
$data,
"{$sTargetType}_count_favourite_user_{$sUserId}_{$s}",
array(
"favourite_{$sTargetType}_change",
"favourite_{$sTargetType}_change_user_{$sUserId}"
),
60 * 60 * 24 * 1
);
}
return $data;
}
/**
* Получает список комментариев к записям открытых блогов
* из избранного указанного пользователя
*
* @param int $sUserId ID пользователя
* @param int $iCurrPage Номер страницы
* @param int $iPerPage Количество элементов на страницу
* @return array
*/
public function GetFavouriteOpenCommentsByUserId($sUserId, $iCurrPage, $iPerPage)
{
if (false === ($data = $this->Cache_Get("comment_favourite_user_{$sUserId}_{$iCurrPage}_{$iPerPage}_open"))) {
$data = array(
'collection' => $this->oMapper->GetFavouriteOpenCommentsByUserId($sUserId, $iCount, $iCurrPage,
$iPerPage),
'count' => $iCount
);
$this->Cache_Set(
$data,
"comment_favourite_user_{$sUserId}_{$iCurrPage}_{$iPerPage}_open",
array(
"favourite_comment_change",
"favourite_comment_change_user_{$sUserId}"
),
60 * 60 * 24 * 1
);
}
return $data;
}
/**
* Возвращает число комментариев к открытым блогам в избранном по ID пользователя
*
* @param int $sUserId ID пользователя
* @return array
*/
public function GetCountFavouriteOpenCommentsByUserId($sUserId)
{
if (false === ($data = $this->Cache_Get("comment_count_favourite_user_{$sUserId}_open"))) {
$data = $this->oMapper->GetCountFavouriteOpenCommentsByUserId($sUserId);
$this->Cache_Set(
$data,
"comment_count_favourite_user_{$sUserId}_open",
array(
"favourite_comment_change",
"favourite_comment_change_user_{$sUserId}"
),
60 * 60 * 24 * 1
);
}
return $data;
}
/**
* Получает список топиков из открытых блогов
* из избранного указанного пользователя
*
* @param int $sUserId ID пользователя
* @param int $iCurrPage Номер страницы
* @param int $iPerPage Количество элементов на страницу
* @return array
*/
public function GetFavouriteOpenTopicsByUserId($sUserId, $iCurrPage, $iPerPage)
{
if (false === ($data = $this->Cache_Get("topic_favourite_user_{$sUserId}_{$iCurrPage}_{$iPerPage}_open"))) {
$data = array(
'collection' => $this->oMapper->GetFavouriteOpenTopicsByUserId($sUserId, $iCount, $iCurrPage,
$iPerPage),
'count' => $iCount
);
$this->Cache_Set(
$data,
"topic_favourite_user_{$sUserId}_{$iCurrPage}_{$iPerPage}_open",
array(
"favourite_topic_change",
"favourite_topic_change_user_{$sUserId}"
),
60 * 60 * 24 * 1
);
}
return $data;
}
/**
* Возвращает число топиков в открытых блогах из избранного по ID пользователя
*
* @param string $sUserId ID пользователя
* @return array
*/
public function GetCountFavouriteOpenTopicsByUserId($sUserId)
{
if (false === ($data = $this->Cache_Get("topic_count_favourite_user_{$sUserId}_open"))) {
$data = $this->oMapper->GetCountFavouriteOpenTopicsByUserId($sUserId);
$this->Cache_Set(
$data,
"topic_count_favourite_user_{$sUserId}_open",
array(
"favourite_topic_change",
"favourite_topic_change_user_{$sUserId}"
),
60 * 60 * 24 * 1
);
}
return $data;
}
/**
* Добавляет таргет в избранное
*
* @param ModuleFavourite_EntityFavourite $oFavourite Объект избранного
* @return bool
*/
public function AddFavourite(ModuleFavourite_EntityFavourite $oFavourite)
{
if (!$oFavourite->getTags()) {
$oFavourite->setTags('');
}
$this->SetFavouriteTags($oFavourite);
//чистим зависимые кеши
$this->Cache_Clean(Zend_Cache::CLEANING_MODE_MATCHING_TAG,
array("favourite_{$oFavourite->getTargetType()}_change_user_{$oFavourite->getUserId()}"));
$this->Cache_Delete("favourite_{$oFavourite->getTargetType()}_{$oFavourite->getTargetId()}_{$oFavourite->getUserId()}");
return $this->oMapper->AddFavourite($oFavourite);
}
/**
* Обновляет запись об избранном
*
* @param ModuleFavourite_EntityFavourite $oFavourite Объект избранного
* @return bool
*/
public function UpdateFavourite(ModuleFavourite_EntityFavourite $oFavourite)
{
if (!$oFavourite->getTags()) {
$oFavourite->setTags('');
}
$this->SetFavouriteTags($oFavourite);
$this->Cache_Clean(Zend_Cache::CLEANING_MODE_MATCHING_TAG,
array("favourite_{$oFavourite->getTargetType()}_change_user_{$oFavourite->getUserId()}"));
$this->Cache_Delete("favourite_{$oFavourite->getTargetType()}_{$oFavourite->getTargetId()}_{$oFavourite->getUserId()}");
return $this->oMapper->UpdateFavourite($oFavourite);
}
/**
* Устанавливает список тегов для избранного
*
* @param ModuleFavourite_EntityFavourite $oFavourite Объект избранного
* @param bool $bAddNew Добавлять новые теги или нет
*/
public function SetFavouriteTags($oFavourite, $bAddNew = true)
{
/**
* Удаляем все теги
*/
$this->oMapper->DeleteTags($oFavourite);
/**
* Добавляем новые
*/
if ($bAddNew) {
/**
* Добавляем теги объекта избранного, если есть
*/
if ($aTags = $this->GetTagsTarget($oFavourite->getTargetType(), $oFavourite->getTargetId())) {
foreach ($aTags as $sTag) {
$oTag = Engine::GetEntity('ModuleFavourite_EntityTag', $oFavourite->_getData());
$oTag->setText(htmlspecialchars($sTag));
$oTag->setIsUser(0);
$this->oMapper->AddTag($oTag);
}
}
if ($oFavourite->getTags()) {
/**
* Добавляем пользовательские теги
*/
$aTags = $oFavourite->getTagsArray();
foreach ($aTags as $sTag) {
$oTag = Engine::GetEntity('ModuleFavourite_EntityTag', $oFavourite->_getData());
$oTag->setText($sTag); // htmlspecialchars уже используется при установке тегов
$oTag->setIsUser(1);
$this->oMapper->AddTag($oTag);
}
}
}
}
/**
* Удаляет таргет из избранного
*
* @param ModuleFavourite_EntityFavourite $oFavourite Объект избранного
* @return bool
*/
public function DeleteFavourite(ModuleFavourite_EntityFavourite $oFavourite)
{
$this->SetFavouriteTags($oFavourite, false);
//чистим зависимые кеши
$this->Cache_Clean(Zend_Cache::CLEANING_MODE_MATCHING_TAG,
array("favourite_{$oFavourite->getTargetType()}_change_user_{$oFavourite->getUserId()}"));
$this->Cache_Delete("favourite_{$oFavourite->getTargetType()}_{$oFavourite->getTargetId()}_{$oFavourite->getUserId()}");
return $this->oMapper->DeleteFavourite($oFavourite);
}
/**
* Меняет параметры публикации у таргета
*
* @param array|int $aTargetId Список ID владельцев
* @param string $sTargetType Тип владельца
* @param int $iPublish Флаг публикации
* @return bool
*/
public function SetFavouriteTargetPublish($aTargetId, $sTargetType, $iPublish)
{
if (!is_array($aTargetId)) {
$aTargetId = array($aTargetId);
}
$this->Cache_Clean(Zend_Cache::CLEANING_MODE_MATCHING_TAG, array("favourite_{$sTargetType}_change"));
return $this->oMapper->SetFavouriteTargetPublish($aTargetId, $sTargetType, $iPublish);
}
/**
* Удаляет избранное по списку идентификаторов таргетов
*
* @param array|int $aTargetId Список ID владельцев
* @param string $sTargetType Тип владельца
* @return bool
*/
public function DeleteFavouriteByTargetId($aTargetId, $sTargetType)
{
if (!is_array($aTargetId)) {
$aTargetId = array($aTargetId);
}
/**
* Чистим зависимые кеши
*/
$this->Cache_Clean(Zend_Cache::CLEANING_MODE_MATCHING_TAG, array("favourite_{$sTargetType}_change"));
$this->DeleteTagByTarget($aTargetId, $sTargetType);
return $this->oMapper->DeleteFavouriteByTargetId($aTargetId, $sTargetType);
}
/**
* Удаление тегов по таргету
*
* @param array $aTargetId Список ID владельцев
* @param string $sTargetType Тип владельца
* @return bool
*/
public function DeleteTagByTarget($aTargetId, $sTargetType)
{
return $this->oMapper->DeleteTagByTarget($aTargetId, $sTargetType);
}
/**
* Возвращает список тегов для объекта избранного
*
* @param string $sTargetType Тип владельца
* @param int $iTargetId ID владельца
* @return bool|array
*/
public function GetTagsTarget($sTargetType, $iTargetId)
{
$sMethod = 'GetTagsTarget' . func_camelize($sTargetType);
if (method_exists($this, $sMethod)) {
return $this->$sMethod($iTargetId);
}
return false;
}
/**
* Возвращает наиболее часто используемые теги
*
* @param int $iUserId ID пользователя
* @param string $sTargetType Тип владельца
* @param bool $bIsUser Возвращает все теги ли только пользовательские
* @param int $iLimit Количество элементов
* @return array
*/
public function GetGroupTags($iUserId, $sTargetType, $bIsUser, $iLimit)
{
return $this->oMapper->GetGroupTags($iUserId, $sTargetType, $bIsUser, $iLimit);
}
/**
* Возвращает список тегов по фильтру
*
* @param array $aFilter Фильтр
* @param array $aOrder Сортировка
* @param int $iCurrPage Номер страницы
* @param int $iPerPage Количество элементов на страницу
* @return array('collection'=>array,'count'=>int)
*/
public function GetTags($aFilter, $aOrder, $iCurrPage, $iPerPage)
{
return array(
'collection' => $this->oMapper->GetTags($aFilter, $aOrder, $iCount, $iCurrPage, $iPerPage),
'count' => $iCount
);
}
/**
* Возвращает список тегов для топика, название метода формируется автоматически из GetTagsTarget()
* @see GetTagsTarget
*
* @param int $iTargetId ID владельца
* @return bool|array
*/
public function GetTagsTargetTopic($iTargetId)
{
if ($oTopic = $this->Topic_GetTopicById($iTargetId)) {
return $oTopic->getTagsArray();
}
return false;
}
}

View file

@ -0,0 +1,145 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Объект сущности избрнного
*
* @package application.modules.favourite
* @since 1.0
*/
class ModuleFavourite_EntityFavourite extends Entity
{
/**
* Возвращает ID владельца
*
* @return int|null
*/
public function getTargetId()
{
return $this->_getDataOne('target_id');
}
/**
* Возвращает ID пользователя
*
* @return int|null
*/
public function getUserId()
{
return $this->_getDataOne('user_id');
}
/**
* Возвращает флаг публикации владельца
*
* @return int|null
*/
public function getTargetPublish()
{
return $this->_getDataOne('target_publish');
}
/**
* Возвращает тип владельца
*
* @return string|null
*/
public function getTargetType()
{
return $this->_getDataOne('target_type');
}
/**
* Возващает список тегов
*
* @return array
*/
public function getTagsArray()
{
if ($this->getTags()) {
return explode(',', $this->getTags());
}
return array();
}
/**
* Возвращает массив тегов в виде объектов
*
* @return array
*/
public function getTagsObjects()
{
$aReturn = array();
if ($aTags = $this->getTagsArray()) {
foreach ($aTags as $sTag) {
if ($sTag) {
$aReturn[] = Engine::GetEntity('ModuleFavourite_EntityTag', array(
'target_type' => $this->getTargetType(),
'target_id' => $this->getTargetId(),
'user_id' => $this->getUserId(),
'text' => $sTag,
));
}
}
}
return $aReturn;
}
/**
* Устанавливает ID владельца
*
* @param int $data
*/
public function setTargetId($data)
{
$this->_aData['target_id'] = $data;
}
/**
* Устанавливает ID пользователя
*
* @param int $data
*/
public function setUserId($data)
{
$this->_aData['user_id'] = $data;
}
/**
* Устанавливает статус публикации для владельца
*
* @param int $data
*/
public function setTargetPublish($data)
{
$this->_aData['target_publish'] = $data;
}
/**
* Устанавливает тип владельца
*
* @param string $data
*/
public function setTargetType($data)
{
$this->_aData['target_type'] = $data;
}
}

View file

@ -0,0 +1,49 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Объект сущности тега для избранного
*
* @package application.modules.favourite
* @since 1.0
*/
class ModuleFavourite_EntityTag extends Entity
{
/**
* Возвращает URL страницы тега
* todo: на странице списка топиков получение пользователя может стать узким местом
*
* @return string
*/
public function getUrl()
{
$_this = $this;
$oUser = $this->Cache_Remember("favourite_tag_user_{$this->getUserId()}",
function () use ($_this) {
return $_this->User_GetUserById($_this->getUserId());
}, false, array(), 'life', true);
if ($oUser) {
return $oUser->getUserWebPath() . 'favourites/topics/tag/' . urlencode($this->getText()) . '/';
}
return null;
}
}

View file

@ -0,0 +1,596 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Объект маппера для работы с БД
*
* @package application.modules.favourite
* @since 1.0
*/
class ModuleFavourite_MapperFavourite extends Mapper
{
/**
* Добавляет таргет в избранное
*
* @param ModuleFavourite_EntityFavourite $oFavourite Объект избранного
* @return bool
*/
public function AddFavourite(ModuleFavourite_EntityFavourite $oFavourite)
{
$sql = "
INSERT INTO " . Config::Get('db.table.favourite') . "
( target_id, target_type, user_id, tags )
VALUES
(?d, ?, ?d, ?)
";
if ($this->oDb->query(
$sql,
$oFavourite->getTargetId(),
$oFavourite->getTargetType(),
$oFavourite->getUserId(),
$oFavourite->getTags()
) === 0
) {
return true;
}
return false;
}
/**
* Обновляет запись об избранном
*
* @param ModuleFavourite_EntityFavourite $oFavourite Объект избранного
* @return bool
*/
public function UpdateFavourite(ModuleFavourite_EntityFavourite $oFavourite)
{
$sql = "
UPDATE " . Config::Get('db.table.favourite') . "
SET tags = ? WHERE user_id = ?d and target_id = ?d and target_type = ?
";
if ($this->oDb->query(
$sql,
$oFavourite->getTags(),
$oFavourite->getUserId(),
$oFavourite->getTargetId(),
$oFavourite->getTargetType()
) !== false
) {
return true;
}
return false;
}
/**
* Получить список избранного по списку айдишников
*
* @param array $aArrayId Список ID владельцев
* @param string $sTargetType Тип владельца
* @param int $sUserId ID пользователя
* @return array
*/
public function GetFavouritesByArray($aArrayId, $sTargetType, $sUserId)
{
if (!is_array($aArrayId) or count($aArrayId) == 0) {
return array();
}
$sql = "SELECT *
FROM " . Config::Get('db.table.favourite') . "
WHERE
user_id = ?d
AND
target_id IN(?a)
AND
target_type = ? ";
$aFavourites = array();
if ($aRows = $this->oDb->select($sql, $sUserId, $aArrayId, $sTargetType)) {
foreach ($aRows as $aRow) {
$aFavourites[] = Engine::GetEntity('Favourite', $aRow);
}
}
return $aFavourites;
}
/**
* Удаляет таргет из избранного
*
* @param ModuleFavourite_EntityFavourite $oFavourite Объект избранного
* @return bool
*/
public function DeleteFavourite(ModuleFavourite_EntityFavourite $oFavourite)
{
$sql = "
DELETE FROM " . Config::Get('db.table.favourite') . "
WHERE
user_id = ?d
AND
target_id = ?d
AND
target_type = ?
";
$res = $this->oDb->query(
$sql,
$oFavourite->getUserId(),
$oFavourite->getTargetId(),
$oFavourite->getTargetType()
);
return $this->IsSuccessful($res);
}
/**
* Удаляет теги
*
* @param ModuleFavourite_EntityFavourite $oFavourite Объект избранного
* @return bool
*/
public function DeleteTags($oFavourite)
{
$sql = "
DELETE FROM " . Config::Get('db.table.favourite_tag') . "
WHERE
user_id = ?d
AND
target_type = ?
AND
target_id = ?d
";
$res = $this->oDb->query(
$sql,
$oFavourite->getUserId(),
$oFavourite->getTargetType(),
$oFavourite->getTargetId()
);
return $this->IsSuccessful($res);
}
/**
* Добавляет тег
*
* @param ModuleFavourite_EntityTag $oTag Объект тега
* @return bool
*/
public function AddTag($oTag)
{
$sql = "
INSERT INTO " . Config::Get('db.table.favourite_tag') . "
SET target_id = ?d, target_type = ?, user_id = ?d, is_user = ?d, text =?
";
if ($this->oDb->query(
$sql,
$oTag->getTargetId(),
$oTag->getTargetType(),
$oTag->getUserId(),
$oTag->getIsUser(),
$oTag->getText()
) === 0
) {
return true;
}
return false;
}
/**
* Меняет параметры публикации у таргета
*
* @param array|int $aTargetId Список ID владельцев
* @param string $sTargetType Тип владельца
* @param int $iPublish Флаг публикации
* @return bool
*/
public function SetFavouriteTargetPublish($aTargetId, $sTargetType, $iPublish)
{
$sql = "
UPDATE " . Config::Get('db.table.favourite') . "
SET
target_publish = ?d
WHERE
target_id IN(?a)
AND
target_type = ?
";
$res = $this->oDb->query($sql, $iPublish, $aTargetId, $sTargetType);
return $this->IsSuccessful($res);
}
/**
* Получает список таргетов из избранного
*
* @param int $sUserId ID пользователя
* @param string $sTargetType Тип владельца
* @param int $iCount Возвращает количество элементов
* @param int $iCurrPage Номер страницы
* @param int $iPerPage Количество элементов на страницу
* @param array $aExcludeTarget Список ID владельцев для исклчения
* @return array
*/
public function GetFavouritesByUserId(
$sUserId,
$sTargetType,
&$iCount,
$iCurrPage,
$iPerPage,
$aExcludeTarget = array()
) {
$sql = "
SELECT target_id
FROM " . Config::Get('db.table.favourite') . "
WHERE
user_id = ?
AND
target_publish = 1
AND
target_type = ?
{ AND target_id NOT IN (?a) }
ORDER BY target_id DESC
LIMIT ?d, ?d ";
$aFavourites = array();
if ($aRows = $this->oDb->selectPage(
$iCount,
$sql,
$sUserId,
$sTargetType,
(count($aExcludeTarget) ? $aExcludeTarget : DBSIMPLE_SKIP),
($iCurrPage - 1) * $iPerPage,
$iPerPage
)
) {
foreach ($aRows as $aFavourite) {
$aFavourites[] = $aFavourite['target_id'];
}
}
return $aFavourites;
}
/**
* Возвращает число таргетов определенного типа в избранном по ID пользователя
*
* @param int $sUserId ID пользователя
* @param string $sTargetType Тип владельца
* @param array $aExcludeTarget Список ID владельцев для исклчения
* @return array
*/
public function GetCountFavouritesByUserId($sUserId, $sTargetType, $aExcludeTarget)
{
$sql = "SELECT
count(target_id) as count
FROM
" . Config::Get('db.table.favourite') . "
WHERE
user_id = ?
AND
target_publish = 1
AND
target_type = ?
{ AND target_id NOT IN (?a) }
;";
return ($aRow = $this->oDb->selectRow(
$sql, $sUserId,
$sTargetType,
(count($aExcludeTarget) ? $aExcludeTarget : DBSIMPLE_SKIP)
)
)
? $aRow['count']
: false;
}
/**
* Получает список комментариев к записям открытых блогов
* из избранного указанного пользователя
*
* @param int $sUserId ID пользователя
* @param int $iCount Возвращает количество элементов
* @param int $iCurrPage Номер страницы
* @param int $iPerPage Количество элементов на страницу
* @return array
*/
public function GetFavouriteOpenCommentsByUserId($sUserId, &$iCount, $iCurrPage, $iPerPage)
{
$sql = "
SELECT f.target_id
FROM
" . Config::Get('db.table.favourite') . " AS f,
" . Config::Get('db.table.comment') . " AS c,
" . Config::Get('db.table.topic') . " AS t,
" . Config::Get('db.table.blog') . " AS b
WHERE
f.user_id = ?d
AND
f.target_publish = 1
AND
f.target_type = 'comment'
AND
f.target_id = c.comment_id
AND
c.target_id = t.topic_id
AND
t.blog_id = b.blog_id
AND
b.blog_type IN ('open', 'personal')
ORDER BY target_id DESC
LIMIT ?d, ?d ";
$aFavourites = array();
if ($aRows = $this->oDb->selectPage(
$iCount, $sql, $sUserId,
($iCurrPage - 1) * $iPerPage, $iPerPage
)
) {
foreach ($aRows as $aFavourite) {
$aFavourites[] = $aFavourite['target_id'];
}
}
return $aFavourites;
}
/**
* Возвращает число комментариев к открытым блогам в избранном по ID пользователя
*
* @param int $sUserId ID пользователя
* @return array
*/
public function GetCountFavouriteOpenCommentsByUserId($sUserId)
{
$sql = "SELECT
count(f.target_id) as count
FROM
" . Config::Get('db.table.favourite') . " AS f,
" . Config::Get('db.table.comment') . " AS c,
" . Config::Get('db.table.topic') . " AS t,
" . Config::Get('db.table.blog') . " AS b
WHERE
f.user_id = ?d
AND
f.target_publish = 1
AND
f.target_type = 'comment'
AND
f.target_id = c.comment_id
AND
c.target_id = t.topic_id
AND
t.blog_id = b.blog_id
AND
b.blog_type IN ('open', 'personal')
;";
return ($aRow = $this->oDb->selectRow($sql, $sUserId))
? $aRow['count']
: false;
}
/**
* Получает список топиков из открытых блогов
* из избранного указанного пользователя
*
* @param int $sUserId ID пользователя
* @param int $iCount Возвращает количество элементов
* @param int $iCurrPage Номер страницы
* @param int $iPerPage Количество элементов на страницу
* @return array
*/
public function GetFavouriteOpenTopicsByUserId($sUserId, &$iCount, $iCurrPage, $iPerPage)
{
$sql = "
SELECT f.target_id
FROM
" . Config::Get('db.table.favourite') . " AS f,
" . Config::Get('db.table.topic') . " AS t,
" . Config::Get('db.table.blog') . " AS b
WHERE
f.user_id = ?d
AND
f.target_publish = 1
AND
f.target_type = 'topic'
AND
f.target_id = t.topic_id
AND
t.blog_id = b.blog_id
AND
b.blog_type IN ('open', 'personal')
ORDER BY target_id DESC
LIMIT ?d, ?d ";
$aFavourites = array();
if ($aRows = $this->oDb->selectPage(
$iCount, $sql, $sUserId,
($iCurrPage - 1) * $iPerPage, $iPerPage
)
) {
foreach ($aRows as $aFavourite) {
$aFavourites[] = $aFavourite['target_id'];
}
}
return $aFavourites;
}
/**
* Возвращает число топиков в открытых блогах из избранного по ID пользователя
*
* @param string $sUserId ID пользователя
* @return array
*/
public function GetCountFavouriteOpenTopicsByUserId($sUserId)
{
$sql = "SELECT
count(f.target_id) as count
FROM
" . Config::Get('db.table.favourite') . " AS f,
" . Config::Get('db.table.topic') . " AS t,
" . Config::Get('db.table.blog') . " AS b
WHERE
f.user_id = ?d
AND
f.target_publish = 1
AND
f.target_type = 'topic'
AND
f.target_id = t.topic_id
AND
t.blog_id = b.blog_id
AND
b.blog_type IN ('open', 'personal')
;";
return ($aRow = $this->oDb->selectRow($sql, $sUserId))
? $aRow['count']
: false;
}
/**
* Удаляет избранное по списку идентификаторов таргетов
*
* @param array|int $aTargetId Список ID владельцев
* @param string $sTargetType Тип владельца
* @return bool
*/
public function DeleteFavouriteByTargetId($aTargetId, $sTargetType)
{
$sql = "
DELETE FROM " . Config::Get('db.table.favourite') . "
WHERE
target_id IN(?a)
AND
target_type = ? ";
$res = $this->oDb->query($sql, $aTargetId, $sTargetType);
return $this->IsSuccessful($res);
}
/**
* Удаление тегов по таргету
*
* @param array $aTargetId Список ID владельцев
* @param string $sTargetType Тип владельца
* @return bool
*/
public function DeleteTagByTarget($aTargetId, $sTargetType)
{
$sql = "
DELETE FROM " . Config::Get('db.table.favourite_tag') . "
WHERE
target_type = ?
AND
target_id IN(?a)
";
$res = $this->oDb->query($sql, $sTargetType, $aTargetId);
return $this->IsSuccessful($res);
}
/**
* Возвращает наиболее часто используемые теги
*
* @param int $iUserId ID пользователя
* @param string $sTargetType Тип владельца
* @param bool $bIsUser Возвращает все теги ли только пользовательские
* @param int $iLimit Количество элементов
* @return array
*/
public function GetGroupTags($iUserId, $sTargetType, $bIsUser, $iLimit)
{
$sql = "SELECT
text,
user_id,
count(text) as count
FROM
" . Config::Get('db.table.favourite_tag') . "
WHERE
1=1
{AND user_id = ?d }
{AND target_type = ? }
{AND is_user = ?d }
GROUP BY
text
ORDER BY
count desc
LIMIT 0, ?d
";
$aReturn = array();
$aReturnSort = array();
if ($aRows = $this->oDb->select($sql, $iUserId, $sTargetType, is_null($bIsUser) ? DBSIMPLE_SKIP : $bIsUser,
$iLimit)
) {
foreach ($aRows as $aRow) {
$aReturn[mb_strtolower($aRow['text'], 'UTF-8')] = $aRow;
}
ksort($aReturn);
foreach ($aReturn as $aRow) {
$aReturnSort[] = Engine::GetEntity('ModuleFavourite_EntityTag', $aRow);
}
}
return $aReturnSort;
}
/**
* Возвращает список тегов по фильтру
*
* @param array $aFilter Фильтр
* @param array $aOrder Сортировка
* @param int $iCount Возвращает количество элементов
* @param int $iCurrPage Номер страницы
* @param int $iPerPage Количество элементов на страницу
* @return array
*/
public function GetTags($aFilter, $aOrder, &$iCount, $iCurrPage, $iPerPage)
{
$aOrderAllow = array('target_id', 'user_id', 'is_user');
$sOrder = '';
foreach ($aOrder as $key => $value) {
if (!in_array($key, $aOrderAllow)) {
unset($aOrder[$key]);
} elseif (in_array($value, array('asc', 'desc'))) {
$sOrder .= " {$key} {$value},";
}
}
$sOrder = trim($sOrder, ',');
if ($sOrder == '') {
$sOrder = ' target_id desc ';
}
$sql = "SELECT
*
FROM
" . Config::Get('db.table.favourite_tag') . "
WHERE
1 = 1
{ AND user_id = ?d }
{ AND target_type = ? }
{ AND target_id = ?d }
{ AND is_user = ?d }
{ AND text = ? }
ORDER by {$sOrder}
LIMIT ?d, ?d ;
";
$aResult = array();
if ($aRows = $this->oDb->selectPage($iCount, $sql,
isset($aFilter['user_id']) ? $aFilter['user_id'] : DBSIMPLE_SKIP,
isset($aFilter['target_type']) ? $aFilter['target_type'] : DBSIMPLE_SKIP,
isset($aFilter['target_id']) ? $aFilter['target_id'] : DBSIMPLE_SKIP,
isset($aFilter['is_user']) ? $aFilter['is_user'] : DBSIMPLE_SKIP,
isset($aFilter['text']) ? $aFilter['text'] : DBSIMPLE_SKIP,
($iCurrPage - 1) * $iPerPage, $iPerPage
)
) {
foreach ($aRows as $aRow) {
$aResult[] = Engine::GetEntity('ModuleFavourite_EntityTag', $aRow);
}
}
return $aResult;
}
}

View file

@ -0,0 +1,547 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Модуль Geo - привязка объектов к географии (страна/регион/город)
* Терминология:
* объект - который привязываем к гео-объекту
* гео-объект - географический объект(страна/регион/город)
*
* @package application.modules.geo
* @since 1.0
*/
class ModuleGeo extends Module
{
/**
* Объект маппера
*
* @var ModuleGeo_MapperGeo
*/
protected $oMapper;
/**
* Список доступных типов объектов
* На данный момент доступен параметр allow_multi=>1 - указывает на возможность создавать несколько связей для одного объекта
*
* @var array
*/
protected $aTargetTypes = array(
'user' => array(),
);
/**
* Список доступных типов гео-объектов
*
* @var array
*/
protected $aGeoTypes = array(
'country',
'region',
'city',
);
/**
* Инициализация
*
*/
public function Init()
{
$this->oMapper = Engine::GetMapper(__CLASS__);
}
/**
* Возвращает список типов объектов
*
* @return array
*/
public function GetTargetTypes()
{
return $this->aTargetTypes;
}
/**
* Добавляет в разрешенные новый тип
* @param string $sTargetType Тип владельца
* @param array $aParams Параметры
* @return bool
*/
public function AddTargetType($sTargetType, $aParams = array())
{
if (!array_key_exists($sTargetType, $this->aTargetTypes)) {
$this->aTargetTypes[$sTargetType] = $aParams;
return true;
}
return false;
}
/**
* Проверяет разрешен ли данный тип
*
* @param string $sTargetType Тип владельца
* @return bool
*/
public function IsAllowTargetType($sTargetType)
{
return in_array($sTargetType, array_keys($this->aTargetTypes));
}
/**
* Проверяет разрешен ли данный гео-тип
*
* @param string $sGeoType Тип владельца
* @return bool
*/
public function IsAllowGeoType($sGeoType)
{
return in_array($sGeoType, $this->aGeoTypes);
}
/**
* Проверка объекта
*
* @param string $sTargetType Тип владельца
* @param int $iTargetId ID владельца
* @return bool
*/
public function CheckTarget($sTargetType, $iTargetId)
{
if (!$this->IsAllowTargetType($sTargetType)) {
return false;
}
$sMethod = 'CheckTarget' . func_camelize($sTargetType);
if (method_exists($this, $sMethod)) {
return $this->$sMethod($iTargetId);
}
return false;
}
/**
* Проверка на возможность нескольких связей
*
* @param string $sTargetType Тип владельца
* @return bool
*/
public function IsAllowTargetMulti($sTargetType)
{
if ($this->IsAllowTargetType($sTargetType)) {
if (isset($this->aTargetTypes[$sTargetType]['allow_multi']) and $this->aTargetTypes[$sTargetType]['allow_multi']) {
return true;
}
}
return false;
}
/**
* Добавляет связь объекта с гео-объектом в БД
*
* @param ModuleGeo_EntityTarget $oTarget Объект связи с владельцем
* @return ModuleGeo_EntityTarget|bool
*/
public function AddTarget($oTarget)
{
if ($this->oMapper->AddTarget($oTarget)) {
return $oTarget;
}
return false;
}
/**
* Создание связи
*
* @param ModuleGeo_EntityGeo $oGeoObject
* @param string $sTargetType Тип владельца
* @param int $iTargetId ID владельца
* @return bool|ModuleGeo_EntityTarget
*/
public function CreateTarget($oGeoObject, $sTargetType, $iTargetId)
{
/**
* Проверяем объект на валидность
*/
if (!$this->CheckTarget($sTargetType, $iTargetId)) {
return false;
}
/**
* Проверяем есть ли уже у этого объекта другие связи
*/
$aTargets = $this->GetTargets(array('target_type' => $sTargetType, 'target_id' => $iTargetId), 1, 1);
if ($aTargets['count']) {
if ($this->IsAllowTargetMulti($sTargetType)) {
/**
* Разрешено несколько связей
* Проверяем есть ли уже связь с данным гео-объектом, если есть то возвращаем его
*/
$aTargetSelf = $this->GetTargets(array(
'target_type' => $sTargetType,
'target_id' => $iTargetId,
'geo_type' => $oGeoObject->getType(),
'geo_id' => $oGeoObject->getId()
), 1, 1);
if ($oTargetSelf = array_shift($aTargetSelf['collection'])) {
return $oTargetSelf;
}
} else {
/**
* Есть другие связи и несколько связей запрещено - удаляем имеющиеся связи
*/
$this->DeleteTargets(array('target_type' => $sTargetType, 'target_id' => $iTargetId));
}
}
/**
* Создаем связь
*/
$oTarget = Engine::GetEntity('ModuleGeo_EntityTarget');
$oTarget->setGeoType($oGeoObject->getType());
$oTarget->setGeoId($oGeoObject->getId());
$oTarget->setTargetType($sTargetType);
$oTarget->setTargetId($iTargetId);
if ($oGeoObject->getType() == 'city') {
$oTarget->setCountryId($oGeoObject->getCountryId());
$oTarget->setRegionId($oGeoObject->getRegionId());
$oTarget->setCityId($oGeoObject->getId());
} elseif ($oGeoObject->getType() == 'region') {
$oTarget->setCountryId($oGeoObject->getCountryId());
$oTarget->setRegionId($oGeoObject->getId());
} elseif ($oGeoObject->getType() == 'country') {
$oTarget->setCountryId($oGeoObject->getId());
}
return $this->AddTarget($oTarget);
}
/**
* Возвращает список связей по фильтру
*
* @param array $aFilter Фильтр
* @param int $iCurrPage Номер страницы
* @param int $iPerPage Количество элементов на страницу
* @return array('collection'=>array,'count'=>int)
*/
public function GetTargets($aFilter, $iCurrPage, $iPerPage)
{
return array(
'collection' => $this->oMapper->GetTargets($aFilter, $iCount, $iCurrPage, $iPerPage),
'count' => $iCount
);
}
/**
* Возвращает первый объект связи по объекту
*
* @param string $sTargetType Тип владельца
* @param int $iTargetId ID владельца
* @return null|ModuleGeo_EntityTarget
*/
public function GetTargetByTarget($sTargetType, $iTargetId)
{
$aTargets = $this->GetTargets(array('target_type' => $sTargetType, 'target_id' => $iTargetId), 1, 1);
if ($oTarget = array_shift($aTargets['collection'])) {
return $oTarget;
}
return null;
}
/**
* Возвращает список связей для списка объектов одного типа.
*
* @param string $sTargetType Тип владельца
* @param array $aTargetId Список ID владельцев
* @return array В качестве ключей используется ID объекта, в качестве значений массив связей этого объекта
*/
public function GetTargetsByTargetArray($sTargetType, $aTargetId)
{
if (!is_array($aTargetId)) {
$aTargetId = array($aTargetId);
}
if (!count($aTargetId)) {
return array();
}
$aResult = array();
$aTargets = $this->GetTargets(array('target_type' => $sTargetType, 'target_id' => $aTargetId), 1,
count($aTargetId));
if ($aTargets['count']) {
foreach ($aTargets['collection'] as $oTarget) {
$aResult[$oTarget->getTargetId()][] = $oTarget;
}
}
return $aResult;
}
/**
* Удаляет связи по фильтру
*
* @param array $aFilter Фильтр
* @return bool|int
*/
public function DeleteTargets($aFilter)
{
return $this->oMapper->DeleteTargets($aFilter);
}
/**
* Удаление всех связей объекта
*
* @param string $sTargetType Тип владельца
* @param int $iTargetId ID владельца
* @return bool|int
*/
public function DeleteTargetsByTarget($sTargetType, $iTargetId)
{
return $this->DeleteTargets(array('target_type' => $sTargetType, 'target_id' => $iTargetId));
}
/**
* Возвращает список стран по фильтру
*
* @param array $aFilter Фильтр
* @param array $aOrder Сортировка
* @param int $iCurrPage Номер страницы
* @param int $iPerPage Количество элементов на страницу
* @return array('collection'=>array,'count'=>int)
*/
public function GetCountries($aFilter, $aOrder, $iCurrPage, $iPerPage)
{
return array(
'collection' => $this->oMapper->GetCountries($aFilter, $aOrder, $iCount, $iCurrPage, $iPerPage),
'count' => $iCount
);
}
/**
* Возвращает список регионов по фильтру
*
* @param array $aFilter Фильтр
* @param array $aOrder Сортировка
* @param int $iCurrPage Номер страницы
* @param int $iPerPage Количество элементов на страницу
* @return array('collection'=>array,'count'=>int)
*/
public function GetRegions($aFilter, $aOrder, $iCurrPage, $iPerPage)
{
return array(
'collection' => $this->oMapper->GetRegions($aFilter, $aOrder, $iCount, $iCurrPage, $iPerPage),
'count' => $iCount
);
}
/**
* Возвращает список городов по фильтру
*
* @param array $aFilter Фильтр
* @param array $aOrder Сортировка
* @param int $iCurrPage Номер страницы
* @param int $iPerPage Количество элементов на страницу
* @return array('collection'=>array,'count'=>int)
*/
public function GetCities($aFilter, $aOrder, $iCurrPage, $iPerPage)
{
return array(
'collection' => $this->oMapper->GetCities($aFilter, $aOrder, $iCount, $iCurrPage, $iPerPage),
'count' => $iCount
);
}
/**
* Возвращает страну по ID
*
* @param int $iId ID страны
* @return ModuleGeo_EntityCountry|null
*/
public function GetCountryById($iId)
{
$aRes = $this->GetCountries(array('id' => $iId), array(), 1, 1);
if ($oCountry = array_shift($aRes['collection'])) {
return $oCountry;
}
return null;
}
/**
* Возвращает регион по ID
*
* @param int $iId ID региона
* @return ModuleGeo_EntityRegion|null
*/
public function GetRegionById($iId)
{
$aRes = $this->GetRegions(array('id' => $iId), array(), 1, 1);
if ($oRegion = array_shift($aRes['collection'])) {
return $oRegion;
}
return null;
}
/**
* Возвращает регион по ID
*
* @param int $iId ID города
* @return ModuleGeo_EntityCity|null
*/
public function GetCityById($iId)
{
$aRes = $this->GetCities(array('id' => $iId), array(), 1, 1);
if ($oCity = array_shift($aRes['collection'])) {
return $oCity;
}
return null;
}
/**
* Возвращает гео-объект
*
* @param string $sType Тип гео-объекта
* @param int $iId ID гео-объекта
* @return ModuleGeo_EntityGeo|null
*/
public function GetGeoObject($sType, $iId)
{
$sType = strtolower($sType);
if (!$this->IsAllowGeoType($sType)) {
return null;
}
switch ($sType) {
case 'country':
return $this->GetCountryById($iId);
break;
case 'region':
return $this->GetRegionById($iId);
break;
case 'city':
return $this->GetCityById($iId);
break;
default:
return null;
}
}
/**
* Возвращает первый гео-объект для объекта
*
* @param string $sTargetType Тип владельца
* @param int $iTargetId ID владельца
* @return ModuleGeo_EntityCity|ModuleGeo_EntityCountry|ModuleGeo_EntityRegion|null
*/
public function GetGeoObjectByTarget($sTargetType, $iTargetId)
{
$aTargets = $this->GetTargets(array('target_type' => $sTargetType, 'target_id' => $iTargetId), 1, 1);
if ($oTarget = array_shift($aTargets['collection']) ) {
$oTarget = $oTarget;
return $this->GetGeoObject($oTarget->getGeoType(), $oTarget->getGeoId());
}
return null;
}
/**
* Возвращает список стран сгруппированных по количеству использований в данном типе объектов
*
* @param string $sTargetType Тип владельца
* @param int $iLimit Количество элементов
* @return array
*/
public function GetGroupCountriesByTargetType($sTargetType, $iLimit)
{
return $this->oMapper->GetGroupCountriesByTargetType($sTargetType, $iLimit);
}
/**
* Возвращает список городов сгруппированных по количеству использований в данном типе объектов
*
* @param string $sTargetType Тип владельца
* @param int $iLimit Количество элементов
* @return array
*/
public function GetGroupCitiesByTargetType($sTargetType, $iLimit)
{
return $this->oMapper->GetGroupCitiesByTargetType($sTargetType, $iLimit);
}
/**
* Возвращает список использованых стран для типа
*
* @param string $sTargetType Тип владельца
* @return array
*/
public function GetCountriesUsedByTargetType($sTargetType)
{
return $this->oMapper->GetCountriesUsedByTargetType($sTargetType);
}
/**
* Возвращает список использованых регионов для типа
*
* @param int $iCountryId
* @param string $sTargetType Тип владельца
* @return array
*/
public function GetRegionsUsedByTargetType($iCountryId, $sTargetType)
{
return $this->oMapper->GetRegionsUsedByTargetType($iCountryId, $sTargetType);
}
/**
* Возвращает список использованых городов для типа
*
* @param int $iRegionId
* @param string $sTargetType Тип владельца
* @return array
*/
public function GetCitiesUsedByTargetType($iRegionId, $sTargetType)
{
return $this->oMapper->GetCitiesUsedByTargetType($iRegionId, $sTargetType);
}
/**
* Проверка объекта с типом "user"
* Название метода формируется автоматически
*
* @param int $iTargetId ID пользователя
* @return bool
*/
public function CheckTargetUser($iTargetId)
{
if ($oUser = $this->User_GetUserById($iTargetId)) {
return true;
}
return false;
}
/**
* Получение всех обьектов по таргетам (для загрузки в шаблон)
*
* @param arr $aTargets массив таргетов
* @return arr
*/
public function GetGeoObjectsByTargets($aTargets)
{
$aGeoCountryIds = [];
$aGeoRegoinIds = [];
$aGeoCityIds = [];
foreach ($aTargets as $oTarget) {
$aGeoCountryIds[] = $oTarget->getCountryId();
$aGeoRegoinIds[] = $oTarget->getRegionId();
$aGeoCityIds[] = $oTarget->getCityId();
}
return [
'countries' => $this->GetCountries(['id' => $aGeoCountryIds], [], 1, 1000)['collection'],
'regions' => $this->GetRegions(['id' => $aGeoRegoinIds], [], 1, 1000)['collection'],
'cities' => $this->GetCities(['id' => $aGeoCityIds], [], 1, 1000)['collection']
];
}
}

View file

@ -0,0 +1,31 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Объект сущности города
*
* @package application.modules.geo
* @since 1.0
*/
class ModuleGeo_EntityCity extends ModuleGeo_EntityGeo
{
}

View file

@ -0,0 +1,31 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Объект сущности страны
*
* @package application.modules.geo
* @since 1.0
*/
class ModuleGeo_EntityCountry extends ModuleGeo_EntityGeo
{
}

View file

@ -0,0 +1,131 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Объект сущности гео-объекта
*
* @package application.modules.geo
* @since 1.0
*/
class ModuleGeo_EntityGeo extends Entity
{
/**
* Возвращает имя гео-объекта в зависимости от языка
*
* @return string
*/
public function getName()
{
$sName = '';
$sLangDef = Config::get('lang.default');
if ($sLangDef == 'ru') {
$sName = $this->getNameRu();
} elseif ($sLangDef == 'en') {
$sName = $this->getNameEn();
}
$sLang = Config::get('lang.current');
if ($sLang == 'ru' and $this->getNameRu()) {
$sName = $this->getNameRu();
} elseif ($sLang == 'en' and $this->getNameEn()) {
$sName = $this->getNameEn();
}
return $sName;
}
/**
* Возвращает тип гео-объекта
*
* @return null|string
*/
public function getType()
{
if ($this instanceof ModuleGeo_EntityCity) {
return 'city';
} elseif ($this instanceof ModuleGeo_EntityRegion) {
return 'region';
} elseif ($this instanceof ModuleGeo_EntityCountry) {
return 'country';
}
return null;
}
/**
* Возвращает гео-объект страны
*
* @return ModuleGeo_EntityGeo|null
*/
public function getCountry()
{
if ($this->getType() == 'country') {
return $this;
}
if ($oCountry = $this->_getDataOne('country')) {
return $oCountry;
}
if ($this->getCountryId()) {
$oCountry = $this->Geo_GetCountryById($this->getCountryId());
return $this->_aData['country'] = $oCountry;
}
return null;
}
/**
* Возвращает гео-объект региона
*
* @return ModuleGeo_EntityGeo|null
*/
public function getRegion()
{
if ($this->getType() == 'region') {
return $this;
}
if ($oRegion = $this->_getDataOne('region')) {
return $oRegion;
}
if ($this->getRegionId()) {
$oRegion = $this->Geo_GetRegionById($this->getRegionId());
return $this->_aData['region'] = $oRegion;
}
return null;
}
/**
* Возвращает гео-объект города
*
* @return ModuleGeo_EntityGeo|null
*/
public function getCity()
{
if ($this->getType() == 'city') {
return $this;
}
if ($oCity = $this->_getDataOne('city')) {
return $oCity;
}
if ($this->getCityId()) {
$oCity = $this->Geo_GetCityById($this->getCityId());
return $this->_aData['city'] = $oCity;
}
return null;
}
}

View file

@ -0,0 +1,31 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Объект сущности региона
*
* @package application.modules.geo
* @since 1.0
*/
class ModuleGeo_EntityRegion extends ModuleGeo_EntityGeo
{
}

View file

@ -0,0 +1,31 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Объект связи гео-объекта с владельцем
*
* @package application.modules.geo
* @since 1.0
*/
class ModuleGeo_EntityTarget extends Entity
{
}

View file

@ -0,0 +1,467 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Объект маппера для работы с БД
*
* @package application.modules.geo
* @since 1.0
*/
class ModuleGeo_MapperGeo extends Mapper
{
/**
* Добавляет связь объекта с гео-объектом в БД
*
* @param ModuleGeo_EntityTarget $oTarget Объект связи с владельцем
* @return ModuleGeo_EntityTarget|bool
*/
public function AddTarget($oTarget)
{
$sql = "INSERT INTO " . Config::Get('db.table.geo_target') . " SET ?a ";
if ($this->oDb->query($sql, $oTarget->_getData())) {
return true;
}
return false;
}
/**
* Возвращает список связей по фильтру
*
* @param array $aFilter Фильтр
* @param int $iCount Возвращает количество элементов
* @param int $iCurrPage Номер страницы
* @param int $iPerPage Количество элементов на страницу
* @return array
*/
public function GetTargets($aFilter, &$iCount, $iCurrPage, $iPerPage)
{
if (isset($aFilter['target_id']) and !is_array($aFilter['target_id'])) {
$aFilter['target_id'] = array($aFilter['target_id']);
}
$sql = "SELECT
*
FROM
" . Config::Get('db.table.geo_target') . "
WHERE
1 = 1
{ AND geo_type = ? }
{ AND geo_id = ?d }
{ AND target_type = ? }
{ AND target_id IN ( ?a ) }
{ AND country_id = ?d }
{ AND region_id = ?d }
{ AND city_id = ?d }
ORDER BY target_id DESC
LIMIT ?d, ?d ;
";
$aResult = array();
if ($aRows = $this->oDb->selectPage($iCount, $sql,
isset($aFilter['geo_type']) ? $aFilter['geo_type'] : DBSIMPLE_SKIP,
isset($aFilter['geo_id']) ? $aFilter['geo_id'] : DBSIMPLE_SKIP,
isset($aFilter['target_type']) ? $aFilter['target_type'] : DBSIMPLE_SKIP,
(isset($aFilter['target_id']) and count($aFilter['target_id'])) ? $aFilter['target_id'] : DBSIMPLE_SKIP,
isset($aFilter['country_id']) ? $aFilter['country_id'] : DBSIMPLE_SKIP,
isset($aFilter['region_id']) ? $aFilter['region_id'] : DBSIMPLE_SKIP,
isset($aFilter['city_id']) ? $aFilter['city_id'] : DBSIMPLE_SKIP,
($iCurrPage - 1) * $iPerPage, $iPerPage
)
) {
foreach ($aRows as $aRow) {
$aResult[] = Engine::GetEntity('ModuleGeo_EntityTarget', $aRow);
}
}
return $aResult;
}
/**
* Возвращает список стран сгруппированных по количеству использований в данном типе объектов
*
* @param string $sTargetType Тип владельца
* @param int $iLimit Количество элементов
* @return array
*/
public function GetGroupCountriesByTargetType($sTargetType, $iLimit)
{
$sql = "
SELECT
t.count,
g.*
FROM (
SELECT
count(*) as count,
country_id
FROM
" . Config::Get('db.table.geo_target') . "
WHERE target_type = ? and country_id IS NOT NULL
GROUP BY country_id ORDER BY count DESC LIMIT 0, ?d
) as t
JOIN " . Config::Get('db.table.geo_country') . " as g on t.country_id=g.id
ORDER BY g.name_ru
";
$aResult = array();
if ($aRows = $this->oDb->select($sql, $sTargetType, $iLimit)) {
foreach ($aRows as $aRow) {
$aResult[] = Engine::GetEntity('ModuleGeo_EntityCountry', $aRow);
}
}
return $aResult;
}
/**
* Возвращает список городов сгруппированных по количеству использований в данном типе объектов
*
* @param string $sTargetType Тип владельца
* @param int $iLimit Количество элементов
* @return array
*/
public function GetGroupCitiesByTargetType($sTargetType, $iLimit)
{
$sql = "
SELECT
t.count,
g.*
FROM (
SELECT
count(*) as count,
city_id
FROM
" . Config::Get('db.table.geo_target') . "
WHERE target_type = ? and city_id IS NOT NULL
GROUP BY city_id ORDER BY count DESC LIMIT 0, ?d
) as t
JOIN " . Config::Get('db.table.geo_city') . " as g on t.city_id=g.id
ORDER BY g.name_ru
";
$aResult = array();
if ($aRows = $this->oDb->select($sql, $sTargetType, $iLimit)) {
foreach ($aRows as $aRow) {
$aResult[] = Engine::GetEntity('ModuleGeo_EntityCity', $aRow);
}
}
return $aResult;
}
/**
* Удаляет связи по фильтру
*
* @param array $aFilter Фильтр
* @return bool|int
*/
public function DeleteTargets($aFilter)
{
if (!$aFilter) {
return false;
}
$sql = "DELETE
FROM
" . Config::Get('db.table.geo_target') . "
WHERE
1 = 1
{ AND geo_type = ? }
{ AND geo_id = ?d }
{ AND target_type = ? }
{ AND target_id = ?d }
{ AND country_id = ?d }
{ AND region_id = ?d }
{ AND city_id = ?d }
";
$res = $this->oDb->query($sql,
isset($aFilter['geo_type']) ? $aFilter['geo_type'] : DBSIMPLE_SKIP,
isset($aFilter['geo_id']) ? $aFilter['geo_id'] : DBSIMPLE_SKIP,
isset($aFilter['target_type']) ? $aFilter['target_type'] : DBSIMPLE_SKIP,
isset($aFilter['target_id']) ? $aFilter['target_id'] : DBSIMPLE_SKIP,
isset($aFilter['country_id']) ? $aFilter['country_id'] : DBSIMPLE_SKIP,
isset($aFilter['region_id']) ? $aFilter['region_id'] : DBSIMPLE_SKIP,
isset($aFilter['city_id']) ? $aFilter['city_id'] : DBSIMPLE_SKIP
);
return $this->IsSuccessful($res);
}
/**
* Возвращает список стран по фильтру
*
* @param array $aFilter Фильтр
* @param array $aOrder Сортировка
* @param int $iCount Возвращает количество элементов
* @param int $iCurrPage Номер страницы
* @param int $iPerPage Количество элементов на страницу
* @return array
*/
public function GetCountries($aFilter, $aOrder, &$iCount, $iCurrPage, $iPerPage)
{
$aOrderAllow = array('id', 'name_ru', 'name_en', 'sort');
$sOrder = '';
foreach ($aOrder as $key => $value) {
if (!in_array($key, $aOrderAllow)) {
unset($aOrder[$key]);
} elseif (in_array($value, array('asc', 'desc'))) {
$sOrder .= " {$key} {$value},";
}
}
$sOrder = trim($sOrder, ',');
if ($sOrder == '') {
$sOrder = ' id desc ';
}
$sql = "SELECT
*
FROM
" . Config::Get('db.table.geo_country') . "
WHERE
1 = 1
{ AND id = ?d }
{ AND name_ru = ? }
{ AND name_ru LIKE ? }
{ AND name_en = ? }
{ AND name_en LIKE ? }
{ AND code = ? }
ORDER by {$sOrder}
LIMIT ?d, ?d ;
";
$aResult = array();
if ($aRows = $this->oDb->selectPage($iCount, $sql,
isset($aFilter['id']) ? $aFilter['id'] : DBSIMPLE_SKIP,
isset($aFilter['name_ru']) ? $aFilter['name_ru'] : DBSIMPLE_SKIP,
isset($aFilter['name_ru_like']) ? $aFilter['name_ru_like'] : DBSIMPLE_SKIP,
isset($aFilter['name_en']) ? $aFilter['name_en'] : DBSIMPLE_SKIP,
isset($aFilter['name_en_like']) ? $aFilter['name_en_like'] : DBSIMPLE_SKIP,
isset($aFilter['code']) ? $aFilter['code'] : DBSIMPLE_SKIP,
($iCurrPage - 1) * $iPerPage, $iPerPage
)
) {
foreach ($aRows as $aRow) {
$aResult[] = Engine::GetEntity('ModuleGeo_EntityCountry', $aRow);
}
}
return $aResult;
}
/**
* Возвращает список регионов по фильтру
*
* @param array $aFilter Фильтр
* @param array $aOrder Сортировка
* @param int $iCount Возвращает количество элементов
* @param int $iCurrPage Номер страницы
* @param int $iPerPage Количество элементов на страницу
* @return array
*/
public function GetRegions($aFilter, $aOrder, &$iCount, $iCurrPage, $iPerPage)
{
$aOrderAllow = array('id', 'name_ru', 'name_en', 'sort', 'country_id');
$sOrder = '';
foreach ($aOrder as $key => $value) {
if (!in_array($key, $aOrderAllow)) {
unset($aOrder[$key]);
} elseif (in_array($value, array('asc', 'desc'))) {
$sOrder .= " {$key} {$value},";
}
}
$sOrder = trim($sOrder, ',');
if ($sOrder == '') {
$sOrder = ' id desc ';
}
if (isset($aFilter['country_id']) and !is_array($aFilter['country_id'])) {
$aFilter['country_id'] = array($aFilter['country_id']);
}
$sql = "SELECT
*
FROM
" . Config::Get('db.table.geo_region') . "
WHERE
1 = 1
{ AND id = ?d }
{ AND name_ru = ? }
{ AND name_ru LIKE ? }
{ AND name_en = ? }
{ AND name_en LIKE ? }
{ AND country_id IN ( ?a ) }
ORDER by {$sOrder}
LIMIT ?d, ?d ;
";
$aResult = array();
if ($aRows = $this->oDb->selectPage($iCount, $sql,
isset($aFilter['id']) ? $aFilter['id'] : DBSIMPLE_SKIP,
isset($aFilter['name_ru']) ? $aFilter['name_ru'] : DBSIMPLE_SKIP,
isset($aFilter['name_ru_like']) ? $aFilter['name_ru_like'] : DBSIMPLE_SKIP,
isset($aFilter['name_en']) ? $aFilter['name_en'] : DBSIMPLE_SKIP,
isset($aFilter['name_en_like']) ? $aFilter['name_en_like'] : DBSIMPLE_SKIP,
(isset($aFilter['country_id']) && count($aFilter['country_id'])) ? $aFilter['country_id'] : DBSIMPLE_SKIP,
($iCurrPage - 1) * $iPerPage, $iPerPage
)
) {
foreach ($aRows as $aRow) {
$aResult[] = Engine::GetEntity('ModuleGeo_EntityRegion', $aRow);
}
}
return $aResult;
}
/**
* Возвращает список городов по фильтру
*
* @param array $aFilter Фильтр
* @param array $aOrder Сортировка
* @param int $iCount Возвращает количество элементов
* @param int $iCurrPage Номер страницы
* @param int $iPerPage Количество элементов на страницу
* @return array
*/
public function GetCities($aFilter, $aOrder, &$iCount, $iCurrPage, $iPerPage)
{
$aOrderAllow = array('id', 'name_ru', 'name_en', 'sort', 'country_id', 'region_id');
$sOrder = '';
foreach ($aOrder as $key => $value) {
if (!in_array($key, $aOrderAllow)) {
unset($aOrder[$key]);
} elseif (in_array($value, array('asc', 'desc'))) {
$sOrder .= " {$key} {$value},";
}
}
$sOrder = trim($sOrder, ',');
if ($sOrder == '') {
$sOrder = ' id desc ';
}
if (isset($aFilter['country_id']) and !is_array($aFilter['country_id'])) {
$aFilter['country_id'] = array($aFilter['country_id']);
}
if (isset($aFilter['region_id']) and !is_array($aFilter['region_id'])) {
$aFilter['region_id'] = array($aFilter['region_id']);
}
$sql = "SELECT
*
FROM
" . Config::Get('db.table.geo_city') . "
WHERE
1 = 1
{ AND id = ?d }
{ AND name_ru = ? }
{ AND name_ru LIKE ? }
{ AND name_en = ? }
{ AND name_en LIKE ? }
{ AND country_id IN ( ?a ) }
{ AND region_id IN ( ?a ) }
ORDER by {$sOrder}
LIMIT ?d, ?d ;
";
$aResult = array();
if ($aRows = $this->oDb->selectPage($iCount, $sql,
isset($aFilter['id']) ? $aFilter['id'] : DBSIMPLE_SKIP,
isset($aFilter['name_ru']) ? $aFilter['name_ru'] : DBSIMPLE_SKIP,
isset($aFilter['name_ru_like']) ? $aFilter['name_ru_like'] : DBSIMPLE_SKIP,
isset($aFilter['name_en']) ? $aFilter['name_en'] : DBSIMPLE_SKIP,
isset($aFilter['name_en_like']) ? $aFilter['name_en_like'] : DBSIMPLE_SKIP,
(isset($aFilter['country_id']) && count($aFilter['country_id'])) ? $aFilter['country_id'] : DBSIMPLE_SKIP,
(isset($aFilter['region_id']) && count($aFilter['region_id'])) ? $aFilter['region_id'] : DBSIMPLE_SKIP,
($iCurrPage - 1) * $iPerPage, $iPerPage
)
) {
foreach ($aRows as $aRow) {
$aResult[] = Engine::GetEntity('ModuleGeo_EntityCity', $aRow);
}
}
return $aResult;
}
public function GetCountriesUsedByTargetType($sTargetType)
{
$sql = "
SELECT
c.*
FROM (
SELECT
DISTINCT country_id
FROM
" . Config::Get('db.table.geo_target') . "
WHERE target_type = ? and country_id IS NOT NULL
) as t
JOIN " . Config::Get('db.table.geo_country') . " as c on t.country_id=c.id
ORDER BY c.name_ru
";
$aResult = array();
if ($aRows = $this->oDb->select($sql, $sTargetType)) {
foreach ($aRows as $aRow) {
$aResult[] = Engine::GetEntity('ModuleGeo_EntityCountry', $aRow);
}
}
return $aResult;
}
public function GetRegionsUsedByTargetType($iCountryId,$sTargetType)
{
$sql = "
SELECT
c.*
FROM (
SELECT
DISTINCT region_id
FROM
" . Config::Get('db.table.geo_target') . "
WHERE target_type = ? and region_id IS NOT NULL
) as t
JOIN " . Config::Get('db.table.geo_region') . " as c on ( t.region_id=c.id and c.country_id = ? )
ORDER BY c.name_ru
";
$aResult = array();
if ($aRows = $this->oDb->select($sql, $sTargetType, $iCountryId)) {
foreach ($aRows as $aRow) {
$aResult[] = Engine::GetEntity('ModuleGeo_EntityRegion', $aRow);
}
}
return $aResult;
}
public function GetCitiesUsedByTargetType($iRegionId,$sTargetType)
{
$sql = "
SELECT
c.*
FROM (
SELECT
DISTINCT city_id
FROM
" . Config::Get('db.table.geo_target') . "
WHERE target_type = ? and city_id IS NOT NULL
) as t
JOIN " . Config::Get('db.table.geo_city') . " as c on ( t.city_id=c.id and c.region_id = ? )
ORDER BY c.name_ru
";
$aResult = array();
if ($aRows = $this->oDb->select($sql, $sTargetType, $iRegionId)) {
foreach ($aRows as $aRow) {
$aResult[] = Engine::GetEntity('ModuleGeo_EntityCity', $aRow);
}
}
return $aResult;
}
}

View file

@ -0,0 +1,68 @@
<?php
/**
* Модуль для функций Ифхаба
*
* @license GPLv2
* @package application.modules.ifhub
* @author Alexander Yakovlev
*/
class ModuleIfhub extends Module
{
/**
* Инициализация
*
*/
public function Init()
{
}
/**
* Обработка тега spoiler в тексте
* <pre>
* <spoiler title="Заголовок">Текст спойлера</spoiler>
* </pre>
*
* @param string $sTag Тег на котором сработал колбэк
* @param array $aParams Список параметров тега
* @return string
*/
public function CallbackParserTagSpoiler($sTag, $aParams, $sText)
{
$sTitle = "Спойлер";
if (isset($aParams['title'])) {
$sTitle = $aParams['title'];
}
return '<details class="newspoiler">'.
'<summary class="newspoiler-title">'.$sTitle.'</summary>'.
$sText.'</details>';
}
/**
* Обработка тега aside в тексте
* <pre>
* <aside>Текст врезки</aside>
* </pre>
*
* @param string $sTag Тег на котором сработал колбэк
* @param array $aParams Список параметров тега
* @return string
*/
public function CallbackParserTagAside($sTag, $aParams, $sText)
{
return '<div class="aside">'.$sText.'</div>';
}
/**
* Обработка тега incut в тексте
* <pre>
* <incut>Текст врезки</incut>
* </pre>
*
* @param string $sTag Тег на котором сработал колбэк
* @param array $aParams Список параметров тега
* @return string
*/
public function CallbackParserTagIncut($sTag, $aParams, $sText)
{
return '<div class="incut">'.$sText.'</div>';
}
}

View file

@ -0,0 +1,279 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Модуль управления инвайтами
*
* @package application.modules.invite
* @since 2.0
*/
class ModuleInvite extends ModuleORM
{
/**
* Тип реферального инвайта, когда пользователь приглашает по своему реферальному коду
*/
const INVITE_TYPE_REFERRAL = 1;
/**
* Тип инвайта по сгенерированному коду, когда пользователь генерирует для приглашения отдельный код (доступен в закрытом режиме сайта)
*/
const INVITE_TYPE_CODE = 2;
/**
* Генерирует новый код инвайта
*
* @param int $iUserId
* @param string|null $sCode
* @param int $iCountAllowUse
* @param int|string|null $sDateExpired
* @return bool|ModuleInvite_EntityCode
*/
public function GenerateInvite($iUserId, $sCode = null, $iCountAllowUse = 1, $sDateExpired = null)
{
$iUserId = is_scalar($iUserId) ? (int)$iUserId : $iUserId->getId();
$sDateExpired = is_int($sDateExpired) ? date('Y-m-d H:i:s', time() + $sDateExpired) : $sDateExpired;
$oInviteCode = Engine::GetEntity('ModuleInvite_EntityCode');
$oInviteCode->setUserId($iUserId);
$oInviteCode->setCode(is_null($sCode) ? $this->GenerateRandomCode() : $sCode);
$oInviteCode->setCountAllowUse($iCountAllowUse);
$oInviteCode->setDateExpired($sDateExpired);
$oInviteCode->setActive(1);
if ($oInviteCode->Add()) {
return $oInviteCode;
}
return false;
}
/**
* Фиксирует факт использования кода инвайта
*
* @param string $sCode
* @param int $iUserId
* @return bool
*/
public function UseCode($sCode, $iUserId)
{
$iUserId = is_scalar($iUserId) ? (int)$iUserId : $iUserId->getId();
$iType = $this->GetInviteTypeByCode($sCode);
$oUse = Engine::GetEntity('ModuleInvite_EntityUse');
$oUse->setType($iType);
$oUse->setToUserId($iUserId);
if ($iType == self::INVITE_TYPE_CODE) {
$oCode = $this->GetCodeByCode($sCode);
$oCode->setCountUse($oCode->getCountUse() + 1);
$oCode->Update();
$oUse->setCodeId($oCode->getId());
$oUse->setFromUserId($oCode->getUserId());
} elseif ($iType == self::INVITE_TYPE_REFERRAL) {
$oUser = $this->User_GetUserByReferralCode($sCode);
$oUse->setFromUserId($oUser->getId());
} else {
return false;
}
return $oUse->Add();
}
/**
* Проверяет корректность кода инвайта с учетом его типа
*
* @param string $sCode
* @param int $iType Тип инвайта, смотри self::INVITE_TYPE_*
* @return bool
*/
public function CheckCode($sCode, $iType = self::INVITE_TYPE_CODE)
{
if ($iType == self::INVITE_TYPE_CODE) {
if ($oCode = $this->GetCodeByCode($sCode)) {
if ($oCode->getActive()
and $oCode->getCountUse() < $oCode->getCountAllowUse()
and (!$oCode->getDateExpired() or strtotime($oCode->getDateExpired()) < time())
) {
return true;
}
}
} elseif ($iType == self::INVITE_TYPE_REFERRAL) {
if ($oUser = $this->User_GetUserByReferralCode($sCode)) {
return true;
}
}
return false;
}
/**
* Возвращает тип инвайта по его коду
*
* @param string $sCode
* @return bool|int
*/
public function GetInviteTypeByCode($sCode)
{
/**
* Приоритет отдаем сгенерированному коду
*/
if ($this->CheckCode($sCode, self::INVITE_TYPE_CODE)) {
return self::INVITE_TYPE_CODE;
}
if ($this->CheckCode($sCode, self::INVITE_TYPE_REFERRAL)) {
return self::INVITE_TYPE_REFERRAL;
}
return false;
}
/**
* Возвращает персональный реферальный код пользователя
*
* @param ModuleUser_EntityUser $oUser
* @return string|null
*/
public function GetReferralCode($oUser)
{
if (is_scalar($oUser)) {
$oUser = $this->User_GetUserById($oUser);
}
if (is_object($oUser)) {
return $oUser->getReferralCode();
}
return null;
}
/**
* Возвращает полную ссылку с реферальным кодом
*
* @param ModuleUser_EntityUser $oUser
* @param string|null $sCode
* @return null|string
*/
public function GetReferralLink($oUser, $sCode = null)
{
if ($sCode or $sCode = $this->GetReferralCode($oUser)) {
return Router::GetPath('auth/referral') . urlencode($sCode) . '/';
}
return null;
}
/**
* Генерирует случайный код
*
* @return string
*/
protected function GenerateRandomCode()
{
return func_generator(10);
}
/**
* Возвращает количество доступных инвайтов для пользователя в данный момент
*
* @param ModuleUser_EntityUser $oUser
* @return int
*/
public function GetCountInviteAvailable($oUser)
{
if (is_scalar($oUser)) {
$oUser = $this->User_GetUserById($oUser);
}
/**
* Период в днях, за который выдаем инвайты
*/
$sDay = 7;
/**
* Количество выданных инвайтов за эти дни
*/
$iCountUsed = $this->GetCountFromCodeByFilter(array(
'user_id' => $oUser->getId(),
'date_create >' => date("Y-m-d 00:00:00", mktime(0, 0, 0, date("m"), date("d") - $sDay, date("Y")))
));
/**
* Доступное число инвайтов период = рейтингу пользователя
*/
$iCountAllAvailable = round($oUser->getRating());
$iCountAllAvailable = $iCountAllAvailable < 0 ? 0 : $iCountAllAvailable;
$iCountAvailable = $iCountAllAvailable - $iCountUsed;
$iCountAvailable = $iCountAvailable < 0 ? 0 : $iCountAvailable;
return $iCountAvailable;
}
/**
* Возвращает количество приглашенных пользователей (число использованных инвайтов)
*
* @param int $iUserId
* @return int
*/
public function GetCountInviteUsed($iUserId)
{
$iUserId = is_scalar($iUserId) ? (int)$iUserId : $iUserId->getId();
return $this->GetCountFromUseByFilter(array('from_user_id' => $iUserId));
}
/**
* Возвращает пользователя, который пригласил текущего
*
* @param $iUserId
* @return ModuleUser_EntityUser|null
*/
public function GetUserInviteFrom($iUserId)
{
if ($oUse = $this->GetUseByToUserId($iUserId) and $iUserFrom = $oUse->getFromUserId()) {
return $this->User_GetUserById($iUserFrom);
}
return null;
}
/**
* Возвращает список приглашенных пользователей
*
* @param int $iUserId
* @return array
*/
public function GetUsersInvite($iUserId)
{
if ($aUseItems = $this->GetUseItemsByFilter(array('from_user_id' => $iUserId, '#index-from' => 'to_user_id', '#limit' => 100))) {
return $this->User_GetUsersAdditionalData(array_keys($aUseItems));
}
return array();
}
/**
* Отправляет инвайт
*
* @param ModuleUser_EntityUser $oUserFrom Пароль пользователя, который отправляет инвайт
* @param string $sMailTo Емайл на который отправляем инвайт
* @param string $sRefCode Код приглашения
*/
public function SendNotifyInvite(ModuleUser_EntityUser $oUserFrom, $sMailTo, $sRefCode)
{
$this->Notify_Send(
$sMailTo,
'invite.tpl',
$this->Lang_Get('emails.invite.subject'),
array(
'sMailTo' => $sMailTo,
'oUserFrom' => $oUserFrom,
'sRefCode' => $sRefCode,
'sRefLink' => $this->GetReferralLink($oUserFrom, $sRefCode),
)
);
}
}

View file

@ -0,0 +1,39 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Сущность инвайта
*
* @package application.modules.invite
* @since 2.0
*/
class ModuleInvite_EntityCode extends EntityORM
{
protected function beforeSave()
{
if ($bResult = parent::beforeSave()) {
if ($this->_isNew()) {
$this->setDateCreate(date("Y-m-d H:i:s"));
}
}
return $bResult;
}
}

View file

@ -0,0 +1,39 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Сущность факта использования инвайта
*
* @package application.modules.invite
* @since 2.0
*/
class ModuleInvite_EntityUse extends EntityORM
{
protected function beforeSave()
{
if ($bResult = parent::beforeSave()) {
if ($this->_isNew()) {
$this->setDateCreate(date("Y-m-d H:i:s"));
}
}
return $bResult;
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,115 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Сущность медиа данных (изображение, видео и т.п.)
*
* @package application.modules.media
* @since 2.0
*/
class ModuleMedia_EntityMedia extends EntityORM
{
protected $aValidateRules = array();
protected $aRelations = array(
'targets' => array(self::RELATION_TYPE_HAS_MANY, 'ModuleMedia_EntityTarget', 'media_id'),
);
protected function beforeSave()
{
if ($bResult = parent::beforeSave()) {
if ($this->_isNew()) {
$this->setDateAdd(date("Y-m-d H:i:s"));
}
}
return $bResult;
}
protected function beforeDelete()
{
if ($bResult = parent::beforeDelete()) {
/**
* Удаляем все связи
*/
$aTargets = $this->getTargets();
foreach ($aTargets as $oTarget) {
$oTarget->Delete();
}
/**
* Удаляем все файлы медиа
*/
$this->Media_DeleteFiles($this);
}
return $bResult;
}
/**
* Возвращает URL до файла нужного размера, в основном используется для изображений
*
* @param null $sSize
*
* @return null
*/
public function getFileWebPath($sSize = null)
{
if ($this->getFilePath()) {
return $this->Media_GetFileWebPath($this, $sSize);
} else {
return null;
}
}
public function getData()
{
$aData = @unserialize($this->_getDataOne('data'));
if (!$aData) {
$aData = array();
}
return $aData;
}
public function setData($aRules)
{
$this->_aData['data'] = @serialize($aRules);
}
public function getDataOne($sKey)
{
$aData = $this->getData();
if (isset($aData[$sKey])) {
return $aData[$sKey];
}
return null;
}
public function setDataOne($sKey, $mValue)
{
$aData = $this->getData();
$aData[$sKey] = $mValue;
$this->setData($aData);
}
public function getRelationTarget()
{
return $this->_getDataOne('_relation_entity');
}
}

View file

@ -0,0 +1,102 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Сущность связи медиа данных с объектами
*
* @package application.modules.media
* @since 2.0
*/
class ModuleMedia_EntityTarget extends EntityORM
{
protected $aValidateRules = array();
protected $aRelations = array(
'media' => array(self::RELATION_TYPE_BELONGS_TO, 'ModuleMedia_EntityMedia', 'media_id'),
);
protected function beforeSave()
{
if ($bResult = parent::beforeSave()) {
if ($this->_isNew()) {
$this->setDateAdd(date("Y-m-d H:i:s"));
}
}
return $bResult;
}
protected function beforeDelete()
{
if ($bResult = parent::beforeDelete()) {
/**
* Удаляем превью
*/
if ($this->getIsPreview() and $oMedia = $this->getMedia()) {
$this->Media_RemoveFilePreview($oMedia, $this);
}
}
return $bResult;
}
public function getData()
{
$aData = @unserialize($this->_getDataOne('data'));
if (!$aData) {
$aData = array();
}
return $aData;
}
public function setData($aRules)
{
$this->_aData['data'] = @serialize($aRules);
}
public function getDataOne($sKey)
{
$aData = $this->getData();
if (isset($aData[$sKey])) {
return $aData[$sKey];
}
return null;
}
public function setDataOne($sKey, $mValue)
{
$aData = $this->getData();
$aData[$sKey] = $mValue;
$this->setData($aData);
}
public function getPreviewImageItemsWebPath()
{
$aPreviewItems = array();
$sPathbase = $this->getDataOne('image_preview');
$aSizes = $this->getDataOne('image_preview_sizes');
if ($sPathbase and $aSizes) {
foreach ($aSizes as $aSize) {
$aPreviewItems[] = $this->Media_GetImageWebPath($sPathbase, $aSize);
}
}
return $aPreviewItems;
}
}

View file

@ -0,0 +1,129 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Маппер для работы с БД
*
* @package application.modules.media
* @since 2.0
*/
class ModuleMedia_MapperMedia extends Mapper
{
public function GetMediaByTarget($sTargetType, $iTargetId, $iUserId = null)
{
$sFieldsJoinReturn = $this->GetFieldsRelationTarget();
$sql = "SELECT
{$sFieldsJoinReturn},
m.*
FROM " . Config::Get('db.table.media_target') . " AS t
JOIN " . Config::Get('db.table.media') . " as m on ( m.id=t.media_id { and m.user_id = ?d } )
WHERE
t.target_id = ?d
AND
t.target_type = ?
ORDER BY
m.id desc
limit 0,500";
$aResult = array();
if ($aRows = $this->oDb->select($sql, $iUserId ? $iUserId : DBSIMPLE_SKIP, $iTargetId, $sTargetType)) {
$aResult = $this->PrepareResultTarget($aRows);
}
return $aResult;
}
public function GetMediaByTargetTmp($sTargetTmp, $iUserId = null)
{
$sFieldsJoinReturn = $this->GetFieldsRelationTarget();
$sql = "SELECT
{$sFieldsJoinReturn},
m.*
FROM " . Config::Get('db.table.media_target') . " AS t
JOIN " . Config::Get('db.table.media') . " as m on ( m.id=t.media_id { and m.user_id = ?d } )
WHERE
t.target_tmp = ?
ORDER BY
m.id desc
limit 0,500";
$aResult = array();
if ($aRows = $this->oDb->select($sql, $iUserId ? $iUserId : DBSIMPLE_SKIP, $sTargetTmp)) {
$aResult = $this->PrepareResultTarget($aRows);
}
return $aResult;
}
public function RemoveTargetByTypeAndId($sTargetType, $iTargetId)
{
$sql = "DELETE
FROM " . Config::Get('db.table.media_target') . "
WHERE
target_id = ?d
AND
target_type = ?
";
if ($this->oDb->query($sql, $iTargetId, $sTargetType) !== false) {
return true;
}
return false;
}
protected function GetFieldsRelationTarget()
{
$oEntityJoinSample = Engine::GetEntity('ModuleMedia_EntityTarget');
/**
* Формируем список полей для возврата у таблице связей
*/
$aFieldsJoinReturn = $oEntityJoinSample->_getFields();
foreach ($aFieldsJoinReturn as $k => $sField) {
if (!is_numeric($k)) {
// Удаляем служебные (примари) поля
unset($aFieldsJoinReturn[$k]);
continue;
}
$aFieldsJoinReturn[$k] = "t.`{$sField}` as t_join_{$sField}";
}
$sFieldsJoinReturn = join(', ', $aFieldsJoinReturn);
return $sFieldsJoinReturn;
}
protected function PrepareResultTarget($aRows)
{
$aResult = array();
foreach ($aRows as $aRow) {
$aData = array();
$aDataRelation = array();
foreach ($aRow as $k => $v) {
if (strpos($k, 't_join_') === 0) {
$aDataRelation[str_replace('t_join_', '', $k)] = $v;
} else {
$aData[$k] = $v;
}
}
$aData['_relation_entity'] = Engine::GetEntity('ModuleMedia_EntityTarget', $aDataRelation);
$oEntity = Engine::GetEntity('ModuleMedia_EntityMedia', $aData);
$oEntity->_SetIsNew(false);
$aResult[] = $oEntity;
}
return $aResult;
}
}

View file

@ -0,0 +1,79 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2018 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Oleg Demodov <boxmilo@gmail.com>
*
*/
/**
* Description of Menu
*
* @author oleg
*/
class ModuleMenu extends ModuleORM {
const STATE_ITEM_ENABLE = 1;
const STATE_ITEM_DISABLE = 0;
const STATE_ITEM_ACTIVE = 2;
private $aMenus = [];
public function Init() {
parent::Init();
}
/**
* Возвращает дерево пунктов
*
* @param int $sId MenuId
*
* @return array
*/
public function GetItemsTreeByMenuId($sId)
{
$aItems = $this->LoadTreeOfItem(array('menu_id' => $sId));
return ModuleORM::buildTree($aItems);
}
public function Get($sName) {
if( !isset($this->aMenus[$sName]) ){
$this->aMenus[$sName] = $this->GetMenuByName($sName);
}
return $this->aMenus[$sName];
}
public function GetMenuByName($sName) {
if(!$oMenu = $this->GetMenuByFilter(['name' => $sName])){
return null;
}
$aItemsTree = $this->LoadTreeOfItem([
'menu_id' => $oMenu->getId(),
'#order' => ['priority' => 'asc']
]);
if(is_array($aItemsTree)){
foreach ($aItemsTree as $oItem) {
$oItem->setParent($oMenu);
}
}
$oMenu->setChildren($aItemsTree);
return $oMenu;
}
}

View file

@ -0,0 +1,154 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2018 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Oleg Demodov <boxmilo@gmail.com>
*
*/
/**
* Description of Item
*
* @author oleg
*/
class ModuleMenu_EntityAbstractItem extends EntityORM{
public function find($sName) {
return $this->recursiveSearch($sName, $this->getChildren());
}
public function recursiveSearch($sName, $aItems) {
if(!is_array($aItems)){
return null;
}
foreach ($aItems as $oItem) {
if($oItem->getName() == $sName){
return $oItem;
}
if($mResult = $this->recursiveSearch($sName, $oItem->getChildren())){
return $mResult;
}
}
return null;
}
private function findIndex($aItems, $sName){
if(!is_array($aItems)){
return false;
}
foreach ($aItems as $key => $oItem) {
if($oItem->getName() == $sName){
return $key;
}
}
return false;
}
public function after($oItem) {
if(!is_array($oItem)){
$oItem = [$oItem];
}
if(get_class($this) == "ModuleMenu_EntityMenu"){
return $this;
}
if(!$oParent = $this->getParent()){
return $this;
}
$oParent->spliceChild($this->getName(), 1, $oItem);
return $this;
}
public function before($oItem) {
if(get_class($this) == "ModuleMenu_EntityMenu"){
return $this;
}
if(!is_array($oItem)){
$oItem = [$oItem];
}
if(!$oParent = $this->getParent()){
return $this;
}
$oParent->spliceChild($this->getName(), 0, $oItem);
return $this;
}
public function remove() {
if(get_class($this) == "ModuleMenu_EntityMenu"){
return $this;
}
if(!$oParent = $this->getParent()){
return $this;
}
$oParent->spliceChild($this->getName(), 0, [], 1);
}
public function spliceChild($sName, $iOffset, $aItems, $iRemove=0){
$aChildrens = $this->getChildren();
if(!is_array($aChildrens)){
return $this;
}
if(($iKey = $this->findIndex($aChildrens, $sName)) === false){
return $this;
}
array_splice($aChildrens, $iKey?($iKey+$iOffset):$iKey, $iRemove, $aItems);
$this->setChildren($aChildrens);
return $this;
}
public function appendChild($oItem) {
$aItems = $this->getChildren();
if(!is_array($aItems)){
$aItems= [];
}
$aItems[] = $oItem;
$this->setChildren($aItems);
return $this;
}
public function prependChild($oItem) {
$aItems = $this->getChildren();
if(!is_array($aItems)){
$aItems= [];
}
array_unshift($aItems, $oItem);
$this->setChildren($aItems);
return $this;
}
}

View file

@ -0,0 +1,128 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2018 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Oleg Demodov <boxmilo@gmail.com>
*
*/
/**
* Description of Item
*
* @author oleg
*/
class ModuleMenu_EntityItem extends ModuleMenu_EntityAbstractItem{
protected $aRelations = [
'menu' => [self::RELATION_TYPE_BELONGS_TO, "ModuleMenu_EntityMenu", 'menu_id'],
self::RELATION_TYPE_TREE
];
public function __construct($aData) {
parent::__construct($aData);
$this->setState(ModuleMenu::STATE_ITEM_ENABLE);
}
/**
* Определяем правила валидации
*
* @var array
*/
public $aValidateRules = array(
array('title', 'string', 'max' => 250, 'min' => 1, 'allowEmpty' => false),
array('name', 'string', 'max' => 30, 'min' => 1, 'allowEmpty' => true),
array('url', 'string', 'max' => 1000, 'min' => 1, 'allowEmpty' => false),
array('enable', 'number'),
array('active', 'number'),
array('pid', 'parent_item'),
array('priority', 'number'),
array('menu_id', 'menu_id'),
);
public function _getTreeParentKey()
{
return 'pid';
}
public function beforeSave()
{
if(!parent::beforeSave()){
return false;
}
if(!$this->_getDataOne('enable')){
$this->setState(ModuleMenu::STATE_ITEM_DISABLE);
return true;
}
$this->setState(ModuleMenu::STATE_ITEM_ENABLE);
if($this->_getDataOne('active')){
$this->setState(ModuleMenu::STATE_ITEM_ACTIVE);
}
return true;
}
public function afterDelete() {
parent::afterDelete();
$aChildrenItems = $this->getChildren();
foreach ($aChildrenItems as $oItem) {
$oItem->setState(ModuleMenu::STATE_ITEM_DISABLE);
$oItem->setPid(null);
$oItem->Save();
}
}
public function ValidateParentItem($sValue, $aParams)
{
if(!$sValue){
return true;
}
if (!$oItem = $this->Menu_GetItemById($this->getPid())) {
return $this->Lang_Get('menu.message.no_find_parent_item');
}
return true;
}
public function ValidateMenuId($sValue, $aParams)
{
if (!$oMenu = $this->Menu_GetMenuById($this->getMenuId())) {
return $this->Lang_Get('menu.message.no_find_menu');
}
return true;
}
public function getEnable() {
if($this->getState()){
return 1;
}
return 0;
}
public function getActive() {
if($this->getState() == ModuleMenu::STATE_ITEM_ACTIVE){
return 1;
}
return 0;
}
}

View file

@ -0,0 +1,34 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2018 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Oleg Demodov <boxmilo@gmail.com>
*
*/
/**
* Description of Menu
*
* @author oleg
*/
class ModuleMenu_EntityMenu extends ModuleMenu_EntityAbstractItem {
public function getItems() {
return $this->getChildren();
}
}

View file

@ -0,0 +1,287 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Модуль опросов
*
* @package application.modules.poll
* @since 2.0
*/
class ModulePoll extends ModuleORM
{
/**
* Объект текущего пользователя
*
* @var ModuleUser_EntityUser|null
*/
protected $oUserCurrent;
protected $aTargetTypes = array(
'topic' => array(),
);
/**
* Инициализация
*
*/
public function Init()
{
parent::Init();
$this->oUserCurrent = $this->User_GetUserCurrent();
}
/**
* Возвращает список типов объектов
*
* @return array
*/
public function GetTargetTypes()
{
return $this->aTargetTypes;
}
/**
* Добавляет в разрешенные новый тип
*
* @param string $sTargetType Тип
* @param array $aParams Параметры
* @return bool
*/
public function AddTargetType($sTargetType, $aParams = array())
{
if (!array_key_exists($sTargetType, $this->aTargetTypes)) {
$this->aTargetTypes[$sTargetType] = $aParams;
return true;
}
return false;
}
/**
* Проверяет разрешен ли данный тип
*
* @param string $sTargetType Тип
* @return bool
*/
public function IsAllowTargetType($sTargetType)
{
return in_array($sTargetType, array_keys($this->aTargetTypes));
}
/**
* Возвращает парметры нужного типа
*
* @param string $sTargetType
*
* @return mixed
*/
public function GetTargetTypeParams($sTargetType)
{
if ($this->IsAllowTargetType($sTargetType)) {
return $this->aTargetTypes[$sTargetType];
}
}
/**
* Проверка объекта target - владелец медиа
*
* @param string $sTargetType Тип
* @param int $iTargetId ID владельца
* @return bool
*/
public function CheckTarget($sTargetType, $iTargetId)
{
if (!$this->IsAllowTargetType($sTargetType)) {
return false;
}
$sMethod = 'CheckTarget' . func_camelize($sTargetType);
if (method_exists($this, $sMethod)) {
return $this->$sMethod($iTargetId);
}
return false;
}
/**
* Заменяет временный идентификатор на необходимый ID объекта
*
* @param string $sTargetType
* @param string $sTargetId
* @param null|string $sTargetTmp Если не задан, то берется их куки "poll_target_tmp_{$sTargetType}"
*/
public function ReplaceTargetTmpById($sTargetType, $sTargetId, $sTargetTmp = null)
{
$sCookieKey = 'poll_target_tmp_' . $sTargetType;
if (is_null($sTargetTmp) and $this->Session_GetCookie($sCookieKey)) {
$sTargetTmp = $this->Session_GetCookie($sCookieKey);
$this->Session_DropCookie($sCookieKey);
}
if (is_string($sTargetTmp)) {
$aPollItems = $this->Poll_GetPollItemsByTargetTmpAndTargetType($sTargetTmp, $sTargetType);
foreach ($aPollItems as $oPoll) {
$oPoll->setTargetTmp(null);
$oPoll->setTargetId($sTargetId);
$oPoll->Update();
}
}
}
/**
* Возвращает список опросов для объекта
*
* @param string $sTargetType
* @param string $sTargetId
*
* @return mixed
*/
public function GetPollItemsByTarget($sTargetType, $sTargetId)
{
$aFilter = array(
'target_type' => $sTargetType,
'target_id' => $sTargetId,
'#with' => array('answers')
);
if ($this->oUserCurrent) {
$aFilter['#with']['vote_current'] = array(
'user_id' => $this->oUserCurrent->getId(),
'#value-default' => false
);
} else {
$_this = $this;
$aFilter['#with']['vote_current'] = array(
'#value-default' => false,
'#callback-filter' => function ($aPollItems, &$aRelationFilter) use ($_this) {
$aWhere = array();
$aWhereBind = array();
foreach ($aPollItems as $oPoll) {
/**
* Смотрим по IP
*/
if($oPoll->getIsGuestCheckIp()) {
$aWhere[] = ' ( t.poll_id = ?d and t.ip = ? ) ';
$aWhereBind[] = $oPoll->getId();
$aWhereBind[] = func_getIp();
}
/**
* Смотрим в куках
*/
if ($sKey = $_this->Session_GetCookie($_this->GetCookieVoteName($oPoll->getId()))) {
$aWhere[] = ' ( t.poll_id = ?d and t.guest_key = ? ) ';
$aWhereBind[] = $oPoll->getId();
$aWhereBind[] = $sKey;
}
}
if ($aWhere) {
$aRelationFilter['#where'] = array(
' ( ' . join(' or ', $aWhere) . ' ) ' => $aWhereBind
);
} else {
$aRelationFilter['#value-set'] = false;
}
}
);
}
$aPollItems = $this->Poll_GetPollItemsByFilter($aFilter);
return $aPollItems;
}
/**
* Проверка владельца с типом "topic"
* Название метода формируется автоматически
*
* @param int $iTargetId ID владельца
* @return bool
*/
public function CheckTargetTopic($iTargetId)
{
if ($oTopic = $this->Topic_GetTopicById($iTargetId)) {
if (!$oTopicType = $this->Topic_GetTopicType($oTopic->getType()) or !$oTopicType->getParam('allow_poll')) {
return false;
}
/**
* Проверяем права на редактирование топика
*/
if ($this->ACL_IsAllowEditTopic($oTopic, $this->oUserCurrent)) {
return true;
}
}
return false;
}
/**
* Голосовал ли пользователь в опросе
*
* @param ModulePoll_EntityPoll $oPoll
* @param int|null $iUserId Если null, то проверяется для гостя
* @return bool
*/
public function CheckUserAlreadyVote($oPoll, $iUserId)
{
return $this->GetVoteByUser($oPoll, $iUserId) ? true : false;
}
/**
* Возвращает объект голосования текущего пользователя за конкретный опрос
*
* @param ModulePoll_EntityPoll $oPoll
* @param int|null $iUserId Если null, то проверяется для гостя
* @return ModulePoll_EntityVote
*/
public function GetVoteByUser($oPoll, $iUserId)
{
$iUserId = is_object($iUserId) ? $iUserId->getId() : $iUserId;
if (is_null($iUserId)) {
/**
* Для гостя
* Два варианта - проверка по IP и по кукам
*/
if ($oPoll->getIsGuestCheckIp()) {
if ($oVote = $this->Poll_GetVoteByIpAndPollId(func_getIp(), $oPoll->getId())) {
return $oVote;
}
}
/**
* По кукам
*/
if ($sKey = $this->Session_GetCookie($this->GetCookieVoteName($oPoll))) {
return $this->Poll_GetVoteByGuestKeyAndPollId($sKey, $oPoll->getId());
}
return false;
} else {
/**
* Для авторизованного
*/
return $this->Poll_GetVoteByUserIdAndPollId($iUserId, $oPoll->getId());
}
}
/**
* Возвращает название куки для хранения факта голосования
*
* @param $oPoll
* @return string
*/
public function GetCookieVoteName($oPoll)
{
$iPollId = is_object($oPoll) ? $oPoll->getId() : $oPoll;
return "poll-vote-{$iPollId}";
}
}

View file

@ -0,0 +1,56 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Сущность ответа в опросе
*
* @package application.modules.poll
* @since 2.0
*/
class ModulePoll_EntityAnswer extends EntityORM
{
protected $aValidateRules = array(
array('title', 'string', 'allowEmpty' => false, 'min' => 1, 'max' => 250),
array('title', 'check_title'),
);
protected $aRelations = array(
'poll' => array(self::RELATION_TYPE_BELONGS_TO, 'ModulePoll_EntityPoll', 'poll_id'),
);
protected function beforeSave()
{
if ($bResult = parent::beforeSave()) {
if ($this->_isNew()) {
$this->setDateCreate(date("Y-m-d H:i:s"));
}
}
return $bResult;
}
public function ValidateCheckTitle()
{
$this->setTitle(htmlspecialchars($this->getTitle()));
return true;
}
}

View file

@ -0,0 +1,296 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Сущность опроса
*
* @package application.modules.poll
* @since 2.0
*/
class ModulePoll_EntityPoll extends EntityORM
{
protected $aValidateRules = array(
array('title', 'string', 'allowEmpty' => false, 'min' => 3, 'max' => 250, 'on' => array('create', 'update')),
array(
'count_answer_max',
'number',
'allowEmpty' => true,
'integerOnly' => true,
'min' => 0,
'on' => array('create', 'update')
),
array('type', 'check_type', 'on' => array('create', 'update')),
array('answers_raw', 'check_answers_raw', 'on' => array('create', 'update')),
array('target_raw', 'check_target_raw', 'on' => array('create')),
array('title', 'check_title', 'on' => array('create', 'update')),
array('is_guest_allow', 'check_is_guest_allow', 'on' => array('create', 'update')),
array('is_guest_check_ip', 'check_is_guest_check_ip', 'on' => array('create', 'update')),
);
protected $aRelations = array(
'answers' => array(self::RELATION_TYPE_HAS_MANY, 'ModulePoll_EntityAnswer', 'poll_id'),
'vote_current' => array(self::RELATION_TYPE_HAS_ONE, 'ModulePoll_EntityVote', 'poll_id'),
);
protected function beforeSave()
{
if ($bResult = parent::beforeSave()) {
if ($this->_isNew()) {
$this->setDateCreate(date("Y-m-d H:i:s"));
}
}
return $bResult;
}
protected function afterSave()
{
parent::afterSave();
/**
* Сохраняем варианты
*/
if ($aAnswers = $this->getAnswersObject()) {
foreach ($aAnswers as $oAnswer) {
$oAnswer->setPollId($this->getId());
$oAnswer->Save();
}
}
/**
* Удаляем варианты
*/
if ($aAnswers = $this->getAnswersObjectForRemove()) {
foreach ($aAnswers as $oAnswer) {
$oAnswer->Delete();
}
}
}
protected function afterDelete()
{
parent::afterDelete();
/**
* Удаляем варианты ответов
*/
$aAnswerItems = $this->Poll_GetAnswerItemsByPollId($this->getId());
foreach ($aAnswerItems as $oAnswer) {
$oAnswer->Delete();
}
/**
* Удаляем голосования
*/
$aVoteItems = $this->Poll_GetVoteItemsByPollId($this->getId());
foreach ($aVoteItems as $oVote) {
$oVote->Delete();
}
}
public function ValidateCheckTitle()
{
$this->setTitle(htmlspecialchars($this->getTitle()));
return true;
}
public function ValidateCheckIsGuestAllow()
{
$this->setIsGuestAllow($this->getIsGuestAllow() ? 1 : 0);
return true;
}
public function ValidateCheckIsGuestCheckIp()
{
$this->setIsGuestCheckIp($this->getIsGuestCheckIp() ? 1 : 0);
return true;
}
public function ValidateCheckType()
{
if (!$this->_isNew() and $this->getCountVote()) {
/**
* Запрещаем смену типа
*/
$this->setCountAnswerMax($this->_getOriginalDataOne('count_answer_max'));
return true;
}
$iCount = $this->getCountAnswerMax();
if ($this->getType() == 'one') {
$this->setCountAnswerMax(1);
return true;
} else {
if ($iCount < 2) {
return $this->Lang_Get('poll.notices.error_answers_max_wrong');
}
}
return true;
}
public function ValidateCheckAnswersRaw()
{
if (!$this->_isNew() and !$this->isAllowUpdate()) {
return true;
}
$aAnswersRaw = $this->getAnswersRaw();
if (!is_array($aAnswersRaw) or count($aAnswersRaw) < 2) {
return $this->Lang_Get('poll.notices.error_answers_count');
}
/**
* Здесь может быть два варианта - создание опроса или редактирование, при редактирование могут передаваться ID ответов
*/
if (!$this->_isNew()) {
$aAnswersOld = $this->Poll_GetAnswerItemsByFilter(array(
'poll_id' => $this->getId(),
'#index-from-primary'
));
} else {
$aAnswersOld = array();
}
$aAnswers = array();
foreach ($aAnswersRaw as $aAnswer) {
if ($this->_isNew() or !(isset($aAnswer['id']) and isset($aAnswersOld[$aAnswer['id']]) and $oAnswer = $aAnswersOld[$aAnswer['id']])) {
$oAnswer = Engine::GetEntity('ModulePoll_EntityAnswer');
}
if ($oAnswer->getId()) {
/**
* Фильтруем список старых ответов для будущего удаления оставшихся
*/
unset($aAnswersOld[$oAnswer->getId()]);
}
$oAnswer->setTitle(isset($aAnswer['title']) ? $aAnswer['title'] : '');
if (!$oAnswer->_Validate()) {
return $oAnswer->_getValidateError();
}
$aAnswers[] = $oAnswer;
}
$this->setAnswersObject($aAnswers);
foreach ($aAnswersOld as $oAnswer) {
if ($oAnswer->getCountVote()) {
return $this->Lang_Get('poll.notices.error_answer_remove');
}
}
$this->setAnswersObjectForRemove($aAnswersOld);
return true;
}
public function ValidateCheckTargetRaw()
{
$aTarget = $this->getTargetRaw();
$sTargetType = isset($aTarget['type']) ? $aTarget['type'] : '';
$sTargetId = isset($aTarget['id']) ? $aTarget['id'] : '';
$sTargetTmp = isset($aTarget['tmp']) ? $aTarget['tmp'] : '';
if ($sTargetId) {
$sTargetTmp = null;
if (!$this->Poll_CheckTarget($sTargetType, $sTargetId)) {
return $this->Lang_Get('poll.notices.error_target_type');
}
} else {
$sTargetId = null;
if (!$sTargetTmp or !$this->Poll_IsAllowTargetType($sTargetType)) {
return $this->Lang_Get('poll.notices.error_target_type');
}
if ($this->Poll_GetPollByFilter(array('target_tmp' => $sTargetTmp, 'target_type <>' => $sTargetType))) {
return $this->Lang_Get('poll.notices.error_target_tmp');
}
}
$this->setTargetType($sTargetType);
$this->setTargetId($sTargetId);
$this->setTargetTmp($sTargetTmp);
return true;
}
/**
* Проверяет доступность опроса для изменения
* Важно понимать, что здесь нет проверки на права доступа
*
* @return bool
*/
public function isAllowUpdate()
{
$iTime = $this->getDateCreate();
if ((time() - strtotime($iTime)) > Config::Get('module.poll.time_limit_update')) {
return false;
}
return true;
}
/**
* Проверяет возможность удаления опроса, не пользователем, а в принципе
* Важно понимать, что здесь нет проверки на права доступа
*
* @return bool
*/
public function isAllowRemove()
{
if ($this->getCountVote() || $this->getCountAbstain()) {
return false;
}
return true;
}
/**
* Проверяет возможность голосования в опросе, не пользователем, а в принципе
* Важно понимать, что здесь нет проверки на права доступа
*
* @return bool
*/
public function isAllowVote()
{
$sDateEnd = $this->getDateEnd();
if ($sDateEnd and (time() - strtotime($sDateEnd)) > 0) {
return false;
}
return true;
}
public function getAnswerPercent($oAnswer)
{
$iCountAll = $this->getCountVote();
if ($iCountAll == 0) {
return 0;
} else {
return number_format(round($oAnswer->getCountVote() * 100 / $iCountAll, 1), 1, '.', '');
}
}
public function getCountVoteAnswerMax()
{
$iMax = 0;
$aAnswers = $this->getAnswers();
foreach ($aAnswers as $oAnswer) {
if ($oAnswer->getCountVote() > $iMax) {
$iMax = $oAnswer->getCountVote();
}
}
return $iMax;
}
public function getVoteCurrent()
{
if (array_key_exists('vote_current', $this->aRelationsData)) {
return $this->aRelationsData['vote_current'];
}
return $this->Poll_GetVoteByUser($this, $this->User_GetUserCurrent());
}
}

View file

@ -0,0 +1,93 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Сущность голосования в опросе
*
* @package application.modules.poll
* @since 2.0
*/
class ModulePoll_EntityVote extends EntityORM
{
protected $aValidateRules = array();
protected $aRelations = array(
'poll' => array(self::RELATION_TYPE_BELONGS_TO, 'ModulePoll_EntityPoll', 'poll_id'),
);
protected function beforeSave()
{
if ($bResult = parent::beforeSave()) {
if ($this->_isNew()) {
$this->setDateCreate(date("Y-m-d H:i:s"));
$this->setIp(func_getIp());
}
}
return $bResult;
}
protected function afterSave()
{
parent::afterSave();
if ($this->_isNew()) {
/**
* Отмечаем факт голосования в опросе и вариантах
*/
$oPoll = $this->getPoll();
$aAnswerItems = $this->getAnswersObject();
if ($aAnswerItems) {
foreach ($aAnswerItems as $oAnswer) {
$oAnswer->setCountVote($oAnswer->getCountVote() + 1);
$oAnswer->Update();
}
$oPoll->setCountVote($oPoll->getCountVote() + 1);
} else {
$oPoll->setCountAbstain($oPoll->getCountAbstain() + 1);
}
$oPoll->Update(0);
}
}
/**
* Возвращает список вариантов, за которые голосовали
*
* @return array|mixed
*/
public function getAnswers()
{
$aData = @unserialize($this->_getDataOne('answers'));
if (!$aData) {
$aData = array();
}
return $aData;
}
/**
* Устанавливает список вариантов, за которые голосовали
*
* @param $aParams
*/
public function setAnswers($aParams)
{
$this->_aData['answers'] = @serialize($aParams);
}
}

View file

@ -0,0 +1,971 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Модуль управления дополнительными полями
*
* @package application.modules.property
* @since 2.0
*/
class ModuleProperty extends ModuleORM
{
/**
* Список возможных типов свойств/полей
*/
const PROPERTY_TYPE_INT = 'int';
const PROPERTY_TYPE_FLOAT = 'float';
const PROPERTY_TYPE_VARCHAR = 'varchar';
const PROPERTY_TYPE_TEXT = 'text';
const PROPERTY_TYPE_CHECKBOX = 'checkbox';
const PROPERTY_TYPE_TAGS = 'tags';
const PROPERTY_TYPE_VIDEO_LINK = 'video_link';
const PROPERTY_TYPE_SELECT = 'select';
const PROPERTY_TYPE_DATE = 'date';
const PROPERTY_TYPE_FILE = 'file';
const PROPERTY_TYPE_IMAGE = 'image';
const PROPERTY_TYPE_IMAGESET = 'imageset';
/**
* Список состояний типов объектов
*/
const TARGET_STATE_ACTIVE = 1;
const TARGET_STATE_NOT_ACTIVE = 2;
const TARGET_STATE_REMOVE = 3;
protected $oMapper = null;
/**
* Список доступных типов полей
*
* @var array
*/
protected $aPropertyTypes = array(
self::PROPERTY_TYPE_INT,
self::PROPERTY_TYPE_FLOAT,
self::PROPERTY_TYPE_VARCHAR,
self::PROPERTY_TYPE_TEXT,
self::PROPERTY_TYPE_CHECKBOX,
self::PROPERTY_TYPE_TAGS,
self::PROPERTY_TYPE_VIDEO_LINK,
self::PROPERTY_TYPE_SELECT,
self::PROPERTY_TYPE_DATE,
self::PROPERTY_TYPE_FILE,
self::PROPERTY_TYPE_IMAGE,
self::PROPERTY_TYPE_IMAGESET
);
/**
* Список разрешенных типов
* На данный момент допустимы параметры entity=>ModuleTest_EntityTest - указывает на класс сущности
* name=>Статьи
*
* @var array
*/
protected $aTargetTypes = array();
public function Init()
{
parent::Init();
$this->oMapper = Engine::GetMapper(__CLASS__);
/**
* Получаем типы из БД и активируем их
*/
if ($aTargetItems = $this->GetTargetItemsByFilter(array('state' => self::TARGET_STATE_ACTIVE))) {
foreach ($aTargetItems as $oTarget) {
$this->Property_AddTargetType($oTarget->getType(), $oTarget->getParams());
}
}
}
/**
* Возвращает список типов объектов
*
* @return array
*/
public function GetTargetTypes()
{
return $this->aTargetTypes;
}
/**
* Добавляет в разрешенные новый тип
*
* @param string $sTargetType Тип
* @param array $aParams Параметры
* @return bool
*/
public function AddTargetType($sTargetType, $aParams = array())
{
if (!array_key_exists($sTargetType, $this->aTargetTypes)) {
$this->aTargetTypes[$sTargetType] = $aParams;
return true;
}
return false;
}
/**
* Проверяет разрешен ли данный тип
*
* @param string $sTargetType Тип
* @return bool
*/
public function IsAllowTargetType($sTargetType)
{
return in_array($sTargetType, array_keys($this->aTargetTypes));
}
/**
* Возвращает парметры нужного типа
*
* @param string $sTargetType
*
* @return mixed
*/
public function GetTargetTypeParams($sTargetType)
{
if ($this->IsAllowTargetType($sTargetType)) {
return $this->aTargetTypes[$sTargetType];
}
}
/**
* Проверяет разрешен ли тип поля
*
* @param string $sType
*
* @return bool
*/
public function IsAllowPropertyType($sType)
{
return in_array($sType, $this->aPropertyTypes);
}
/**
* Для каждого из свойств получает значение
*
* @param array $aProperties Список свойств
* @param string $sTargetType Тип объекта
* @param int $iTargetId ID объекта
*
* @return bool
*/
public function AttachValueForProperties($aProperties, $sTargetType, $iTargetId)
{
if (!$aProperties) {
return false;
}
/**
* Формируем список ID свойств
*/
$aPropertyIds = array();
foreach ($aProperties as $oProperty) {
$aPropertyIds[] = $oProperty->getId();
}
/**
* Получаем список значений
*/
$aValues = $this->Property_GetValueItemsByFilter(array(
'target_id' => $iTargetId,
'target_type' => $sTargetType,
'property_id in' => $aPropertyIds,
'#index-from' => 'property_id'
));
/**
* Аттачим значения к свойствам
*/
foreach ($aProperties as $oProperty) {
if (isset($aValues[$oProperty->getId()])) {
$oProperty->setValue($aValues[$oProperty->getId()]);
} else {
$oProperty->setValue(Engine::GetEntity('ModuleProperty_EntityValue', array(
'property_id' => $oProperty->getId(),
'property_type' => $oProperty->getType(),
'target_type' => $sTargetType,
'target_id' => $iTargetId
)));
}
$oProperty->getValue()->setProperty($oProperty);
}
return true;
}
/**
* Сохраняет текущие значения свойств
*
* @param array $aProperties
* @param Entity|int $oTarget Объект сущности или ID сущности
*/
public function UpdatePropertiesValue($aProperties, $oTarget)
{
if ($aProperties) {
foreach ($aProperties as $oProperty) {
$oValue = $oProperty->getValue();
$oValue->setTargetId(is_object($oTarget) ? $oTarget->getId() : $oTarget);
$oValue->setPropertyType($oProperty->getType());
$oValue->Save();
}
}
}
/**
* Удаление всех свойств у конкретного объекта/сущности
*
* @param Entity $oTarget
*/
public function RemovePropertiesValue($oTarget)
{
$aProperties = $this->Property_GetPropertyItemsByFilter(array('target_type' => $oTarget->property->getPropertyTargetType()));
if ($aProperties) {
$this->AttachValueForProperties($aProperties, $oTarget->property->getPropertyTargetType(),
$oTarget->getId());
foreach ($aProperties as $oProperty) {
$oValue = $oProperty->getValue();
if ($oValue and $oValue->getId()) {
$oValueType = $oValue->getValueTypeObject();
/**
* Кастомное удаление
*/
$oValueType->removeValue();
/**
* Удаляем основные данные
*/
$oValue->Delete();
}
}
}
}
/**
* Валидирует значение свойств у объекта
*
* @param Entity $oTarget
*
* @return bool|string
*/
public function ValidateEntityPropertiesCheck($oTarget)
{
/**
* Пробуем получить свойства из реквеста
*/
$oTarget->setProperties($oTarget->getProperties() ? $oTarget->getProperties() : getRequest('property'));
$aPropertiesValue = $oTarget->getProperties();
$aPropertiesResult = array();
/**
* Получаем весь список свойств у объекта
*/
$aPropertiesObject = $this->Property_GetPropertyItemsByFilter(array('target_type' => $oTarget->property->getPropertyTargetType()));
$this->Property_AttachValueForProperties($aPropertiesObject, $oTarget->property->getPropertyTargetType(),
$oTarget->getId());
foreach ($aPropertiesObject as $oProperty) {
$oValue = $oProperty->getValue();
$sValue = isset($aPropertiesValue[$oProperty->getId()]) ? $aPropertiesValue[$oProperty->getId()] : null;
/**
* Валидируем значение
*/
$oValueType = $oValue->getValueTypeObject();
$oValueType->setValueForValidate($sValue);
if (true === ($sRes = $oValueType->validate())) {
$oValueType->setValue($oValueType->getValueForValidate());
$aPropertiesResult[$oProperty->getId()] = $oProperty;
} else {
return $this->Lang_Get('property.notices.validate_value_wrong',
array('field' => $oProperty->getTitle())) . ($sRes ? $sRes : $this->Lang_Get('property.notices.validate_value_wrong_base'));
}
}
$oTarget->setPropertiesObject($aPropertiesResult);
return true;
}
/**
* Возвращает значение свойсва у объекта
*
* @param Entity $oTarget Объект сущности
* @param int $sPropertyId ID свойства
*
* @return null|mixed
*/
public function GetEntityPropertyValue($oTarget, $sPropertyId)
{
if ($oProperty = $this->GetEntityPropertyValueObject($oTarget, $sPropertyId)) {
return $oProperty->getValue()->getValueForDisplay();
}
return null;
}
/**
* Возвращает объект свойства сущности
*
* @param Entity $oTarget Объект сущности
* @param int $sPropertyId ID свойства
*
* @return null|ModuleProperty_EntityProperty
*/
public function GetEntityProperty($oTarget, $sPropertyId)
{
if ($oProperty = $this->GetEntityPropertyValueObject($oTarget, $sPropertyId)) {
return $oProperty;
}
return null;
}
/**
* Возвращает список свойств сущности
*
* @param Entity $oTarget Объект сущности
*
* @return array
*/
public function GetEntityPropertyList($oTarget)
{
$sTargetType = $oTarget->property->getPropertyTargetType();
/**
* Проверяем зарегистрирован ли такой тип
*/
if (!$this->IsAllowTargetType($sTargetType)) {
return array();
}
if (!$oTarget->getPropertyIsLoadAll()) {
$aProperties = $this->oMapper->GetPropertiesValueByTarget($oTarget->property->getPropertyTargetType(),
$oTarget->getId());
$this->AttachPropertiesForTarget($oTarget, $aProperties);
}
return $oTarget->_getDataOne('property_list');
}
/**
* Служебный метод для аттача свойст к сущности
*
* @param Entity $oTarget Объект сущности
* @param array $aProperties Список свойств
*/
public function AttachPropertiesForTarget($oTarget, $aProperties)
{
$oTarget->setPropertyList($aProperties);
$oTarget->setPropertyIsLoadAll(true);
$aMapperCode = array();
foreach ($aProperties as $oProperty) {
$aMapperCode[$oProperty->getCode()] = $oProperty->getId();
}
$oTarget->setPropertyMapperCode($aMapperCode);
}
/**
* Возвращает объект свойства
*
* @param Entity $oTarget Объект сущности
* @param array $sPropertyId ID свойства
*
* @return null
*/
public function GetEntityPropertyValueObject($oTarget, $sPropertyId)
{
if (!$oTarget->getPropertyIsLoadAll()) {
/**
* Загружаем все свойства
*/
$aProperties = $this->oMapper->GetPropertiesValueByTarget($oTarget->property->getPropertyTargetType(),
$oTarget->getId());
$this->AttachPropertiesForTarget($oTarget, $aProperties);
}
if (!is_numeric($sPropertyId)) {
$aMapperCode = $oTarget->getPropertyMapperCode();
if (isset($aMapperCode[$sPropertyId])) {
$sPropertyId = $aMapperCode[$sPropertyId];
} else {
return null;
}
}
$aProperties = $oTarget->property->getPropertyList();
if (isset($aProperties[$sPropertyId])) {
return $aProperties[$sPropertyId];
}
return null;
}
/**
* Переопределяем метод для возможности цеплять свои кастомные данные при ORM запросах - свойства
*
* @param array $aResult
* @param array $aFilter
* @param null|string $sEntityFull
*/
public function RewriteGetItemsByFilter($aResult, $aFilter = array(), $sEntityFull = null)
{
if (!$aResult) {
return;
}
/**
* Список на входе может быть двух видом:
* 1 - одномерный массив
* 2 - двумерный, если применялась группировка (использование '#index-group')
*
* Поэтому сначала сформируем линейный список
*/
if (isset($aFilter['#index-group']) and $aFilter['#index-group']) {
$aEntitiesWork = array();
foreach ($aResult as $aItems) {
foreach ($aItems as $oItem) {
$aEntitiesWork[] = $oItem;
}
}
} else {
$aEntitiesWork = $aResult;
}
if (!$aEntitiesWork) {
return;
}
$oEntityFirst = reset($aEntitiesWork);
if (!$oEntityFirst->property) {
return;
}
/**
* Проверяем необходимость цеплять свойства
*/
if (isset($aFilter['#properties']) and $aFilter['#properties']) {
$aEntitiesId = array();
$aTargetTypes = array();
foreach ($aEntitiesWork as $oEntity) {
$sTargetType = $oEntity->property->getPropertyTargetType();
if ($this->IsAllowTargetType($sTargetType)) {
$aEntitiesId[] = $oEntity->getId();
$aTargetTypes[] = $sTargetType;
}
}
$aTargetTypes = array_unique($aTargetTypes);
/**
* Получаем все свойства со значениями для всех объектов
*/
$aResult = $this->oMapper->GetPropertiesValueByTargetArray($aTargetTypes, $aEntitiesId);
if ($aResult) {
/**
* Формируем список свойств и значений
*/
$aProperties = array();
$aValues = array();
foreach ($aResult as $aRow) {
$aPropertyData = array();
$aValueData = array();
foreach ($aRow as $k => $v) {
if (strpos($k, 'prop_') === 0) {
$aPropertyData[str_replace('prop_', '', $k)] = $v;
} else {
$aValueData[$k] = $v;
}
}
if (!isset($aProperties[$aRow['prop_id']])) {
$oProperty = Engine::GetEntity('ModuleProperty_EntityProperty', $aPropertyData);
$aProperties[$aRow['prop_id']] = $oProperty;
}
if ($aRow['target_id']) {
$sKey = $aRow['property_id'] . '_' . $aRow['target_id'];
$aValues[$sKey] = Engine::GetEntity('ModuleProperty_EntityValue', $aValueData);
}
}
/**
* Собираем данные
*/
foreach ($aEntitiesWork as $oEntity) {
$aPropertiesClone = array();
foreach ($aProperties as $oProperty) {
if ($oEntity->property->getPropertyTargetType() != $oProperty->getTargetType()) {
continue;
}
$oPropertyNew = clone $oProperty;
$sKey = $oProperty->getId() . '_' . $oEntity->getId();
if (isset($aValues[$sKey])) {
$oValue = $aValues[$sKey];
} else {
$oValue = Engine::GetEntity('ModuleProperty_EntityValue', array(
'property_type' => $oProperty->getType(),
'property_id' => $oProperty->getId(),
'target_type' => $oProperty->getTargetType(),
'target_id' => $oEntity->getId()
));
}
$oPropertyNew->setValue($oValue);
$oValue->setProperty($oPropertyNew);
$aPropertiesClone[$oPropertyNew->getId()] = $oPropertyNew;
}
$this->AttachPropertiesForTarget($oEntity, $aPropertiesClone);
}
}
}
}
/**
* Обработка фильтра ORM запросов
*
* @param array $aFilter
* @param array $sEntityFull
*
* @return array
*/
public function RewriteFilter($aFilter, $sEntityFull)
{
$oEntitySample = Engine::GetEntity($sEntityFull);
if (!$oEntitySample->property) {
return $aFilter;
}
if (!isset($aFilter['#join'])) {
$aFilter['#join'] = array();
}
$aPropFields = array();
foreach ($aFilter as $k => $v) {
if (preg_match('@^#prop:(.+)$@i', $k, $aMatch)) {
/**
* Сначала формируем список полей с операндами
*/
$aK = explode(' ', trim($aMatch[1]), 2);
$sPropCurrent = $aK[0];
$sConditionCurrent = ' = ';
if (count($aK) > 1) {
$sConditionCurrent = strtolower($aK[1]);
}
$aPropFields[$sPropCurrent] = array('value' => $v, 'condition' => $sConditionCurrent);
}
}
/**
* Проверяем на наличие сортировки по полям
*/
$aOrders = array();
if (isset($aFilter['#order'])) {
if (!is_array($aFilter['#order'])) {
$aFilter['#order'] = array($aFilter['#order']);
}
foreach ($aFilter['#order'] as $key => $value) {
$aKeys = explode(':', $key);
if (count($aKeys) == 2 and strtolower($aKeys[0]) == 'prop') {
$aOrders[$aKeys[1]] = array('way' => $value, 'replace' => $key);
}
}
}
/**
* Получаем данные по полям
*/
if ($aPropFields) {
$sTargetType = $oEntitySample->property->getPropertyTargetType();
$aProperties = $this->Property_GetPropertyItemsByFilter(array(
'code in' => array_keys($aPropFields),
'target_type' => $sTargetType
));
$iPropNum = 0;
foreach ($aProperties as $oProperty) {
/**
* По каждому полю строим JOIN запрос
*/
$sCondition = $aPropFields[$oProperty->getCode()]['condition'];
$bIsArray = in_array(strtolower($sCondition), array('in', 'not in')) ? true : false;
if (in_array($oProperty->getType(),
array(ModuleProperty::PROPERTY_TYPE_INT, ModuleProperty::PROPERTY_TYPE_CHECKBOX))) {
$sFieldValue = "value_int";
$sConditionFull = $sCondition . ($bIsArray ? ' (?a) ' : ' ?d ');
} elseif ($oProperty->getType() == ModuleProperty::PROPERTY_TYPE_FLOAT) {
$sFieldValue = "value_float";
$sConditionFull = $sCondition . ($bIsArray ? ' (?a) ' : ' ?f ');
} elseif (in_array($oProperty->getType(), array(
ModuleProperty::PROPERTY_TYPE_VARCHAR,
ModuleProperty::PROPERTY_TYPE_TAGS,
ModuleProperty::PROPERTY_TYPE_VIDEO_LINK
))) {
$sFieldValue = "value_varchar";
$sConditionFull = $sCondition . ($bIsArray ? ' (?a) ' : ' ? ');
} elseif ($oProperty->getType() == ModuleProperty::PROPERTY_TYPE_TEXT) {
$sFieldValue = "value_text";
$sConditionFull = $sCondition . ($bIsArray ? ' (?a) ' : ' ? ');
} else {
$sFieldValue = "value_varchar";
$sConditionFull = $sCondition . ($bIsArray ? ' (?a) ' : ' ? ');
}
$iPropNum++;
$sJoin = "JOIN " . Config::Get('db.table.property_value') . " propv{$iPropNum} ON
t.`{$oEntitySample->_getPrimaryKey()}` = propv{$iPropNum}.target_id and
propv{$iPropNum}.target_type = '{$sTargetType}' and
propv{$iPropNum}.property_id = {$oProperty->getId()} and
propv{$iPropNum}.{$sFieldValue} {$sConditionFull}";
$aFilter['#join'][$sJoin] = array($aPropFields[$oProperty->getCode()]['value']);
/**
* Проверяем на сортировку по текущему полю
*/
if (isset($aOrders[$oProperty->getCode()])) {
$aOrders[$oProperty->getCode()]['field'] = "propv{$iPropNum}.{$sFieldValue}";
}
}
}
/**
* Подменяем сортировку
*/
foreach ($aOrders as $aItem) {
if (isset($aFilter['#order'][$aItem['replace']])) {
$aFilter['#order'] = $this->ArrayReplaceKey($aFilter['#order'], $aItem['replace'], $aItem['field']);
}
}
return $aFilter;
}
/**
* Служебный метод для замены ключа в массиве
*
* @param array $aArray
* @param string $sKeyOld
* @param string $sKeyNew
*
* @return array|bool
*/
protected function ArrayReplaceKey($aArray, $sKeyOld, $sKeyNew)
{
$aKeys = array_keys($aArray);
if (false === $iIndex = array_search($sKeyOld, $aKeys)) {
return false;
}
$aKeys[$iIndex] = $sKeyNew;
return array_combine($aKeys, array_values($aArray));
}
/**
* Удаляет теги свойства у сущности
*
* @param string $sTargetType Тип объекта сущности
* @param int $iTargetId ID объекта сущности
* @param int $iPropertyId ID свойства
*
* @return mixed
*/
public function RemoveValueTagsByTarget($sTargetType, $iTargetId, $iPropertyId)
{
// сбрасываем кеш
$this->Cache_Clean(Zend_Cache::CLEANING_MODE_MATCHING_TAG, array('ModuleProperty_EntityValueTag_delete'));
return $this->oMapper->RemoveValueTagsByTarget($sTargetType, $iTargetId, $iPropertyId);
}
/**
* Удаляет значения типа select
*
* @param string $sTargetType Тип объекта сущности
* @param int $iTargetId ID объекта сущности
* @param int $iPropertyId ID свойства
*
* @return mixed
*/
public function RemoveValueSelectsByTarget($sTargetType, $iTargetId, $iPropertyId)
{
// сбрасываем кеш
$this->Cache_Clean(Zend_Cache::CLEANING_MODE_MATCHING_TAG, array('ModuleProperty_EntityValueSelect_delete'));
return $this->oMapper->RemoveValueSelectsByTarget($sTargetType, $iTargetId, $iPropertyId);
}
/**
* Возвращает список тегов/знаяений свойства. Используется для авкомплиттера тегов.
*
* @param string $sTag
* @param int $iPropertyId
* @param int $iLimit
*
* @return mixed
*/
public function GetPropertyTagsByLike($sTag, $iPropertyId, $iLimit)
{
return $this->oMapper->GetPropertyTagsByLike($sTag, $iPropertyId, $iLimit);
}
/**
* Возвращет список группированных тегов с их количеством для необходимого свойства
*
* @param int $iPropertyId
* @param int $iLimit
*
* @return mixed
*/
public function GetPropertyTagsGroup($iPropertyId, $iLimit)
{
return $this->oMapper->GetPropertyTagsGroup($iPropertyId, $iLimit);
}
/**
* Формирует и возвращает облако тегов необходимого свойства
*
* @param int $iPropertyId
* @param int $iLimit
*
* @return mixed
*/
public function GetPropertyTagsCloud($iPropertyId, $iLimit)
{
$aTags = $this->Property_GetPropertyTagsGroup($iPropertyId, $iLimit);
if ($aTags) {
$this->Tools_MakeCloud($aTags);
}
return $aTags;
}
/**
* Список ID сущностей по тегу конкретного свойства
*
* @param int $iPropertyId
* @param string $sTag
* @param int $iCurrPage
* @param int $iPerPage
*
* @return array
*/
public function GetTargetsByTag($iPropertyId, $sTag, $iCurrPage, $iPerPage)
{
return array(
'collection' => $this->oMapper->GetTargetsByTag($iPropertyId, $sTag, $iCount, $iCurrPage, $iPerPage),
'count' => $iCount
);
}
/**
* Производит изменение названия типа объекта, например "article" меняем на "news"
*
* @param $sType
* @param $sTypeNew
*/
public function ChangeTargetType($sType, $sTypeNew)
{
$this->oMapper->UpdatePropertyByTargetType($sType, $sTypeNew);
$this->oMapper->UpdatePropertyTargetByTargetType($sType, $sTypeNew);
$this->oMapper->UpdatePropertySelectByTargetType($sType, $sTypeNew);
$this->oMapper->UpdatePropertyValueByTargetType($sType, $sTypeNew);
$this->oMapper->UpdatePropertyValueSelectByTargetType($sType, $sTypeNew);
$this->oMapper->UpdatePropertyValueTagByTargetType($sType, $sTypeNew);
/**
* Сбрасываем кеши
*/
$this->Cache_Clean(Zend_Cache::CLEANING_MODE_MATCHING_TAG, array(
'ModuleProperty_EntityProperty_save',
'ModuleProperty_EntityTarget_save',
'ModuleProperty_EntitySelect_save',
'ModuleProperty_EntityValue_save',
'ModuleProperty_EntityValueSelect_save',
'ModuleProperty_EntityValueTag_save',
));
}
/**
* Создает новый тип объекта в БД для дополнительных полей
*
* @param string $sType
* @param array $aParams
* @param bool $bRewrite
*
* @return bool|ModuleProperty_EntityTarget
*/
public function CreateTargetType($sType, $aParams, $bRewrite = false)
{
/**
* Проверяем есть ли уже такой тип
*/
if ($oTarget = $this->GetTargetByType($sType)) {
if (!$bRewrite) {
return false;
}
} else {
$oTarget = Engine::GetEntity('ModuleProperty_EntityTarget');
$oTarget->setType($sType);
}
$oTarget->setState(self::TARGET_STATE_ACTIVE);
$oTarget->setParams($aParams);
if ($oTarget->Save()) {
return $oTarget;
}
return false;
}
/**
* Отключает тип объекта для дополнительных полей
*
* @param string $sType
* @param int $iState self::TARGET_STATE_NOT_ACTIVE или self::TARGET_STATE_REMOVE
*/
public function RemoveTargetType($sType, $iState = self::TARGET_STATE_NOT_ACTIVE)
{
if ($oTarget = $this->GetTargetByType($sType)) {
$oTarget->setState($iState);
$oTarget->Save();
}
}
/**
* Возвращает набор полей/свойств для показа их на форме редактирования
*
* @param $sTargetType
* @param $iTargetId
*
* @return mixed
*/
public function GetPropertiesForUpdate($sTargetType, $iTargetId)
{
/**
* Проверяем зарегистрирован ли такой тип
*/
if (!$this->IsAllowTargetType($sTargetType)) {
return array();
}
/**
* Получаем набор свойств
*/
$aProperties = $this->Property_GetPropertyItemsByFilter(array(
'target_type' => $sTargetType,
'#order' => array('sort' => 'desc')
));
$this->Property_AttachValueForProperties($aProperties, $sTargetType, $iTargetId);
return $aProperties;
}
/**
* Автоматическое создание дополнительного поля
* TODO: учитывать $aAdditional для создание вариантов в типе select
*
* @param string $sTargetType Тип объекта дял которого добавляем поле
* @param array $aData Данные поля: array('type'=>'int','title'=>'Название','code'=>'newfield','description'=>'Описание поля','sort'=>100);
* @param bool $bSkipErrorUniqueCode Пропускать ошибку при дублировании кода поля (такое поле уже существует)
* @param array $aValidateRules Данные валидатора поля, зависят от конкретного типа поля: array('allowEmpty'=>true,'max'=>1000)
* @param array $aParams Дополнительные параметры поля, зависят от типа поля
* @param array $aAdditional Дополнительные данные, которые нужно учитывать при создании поля, зависят от типа поля
*
* @return bool|ModuleProperty_EntityProperty
*/
public function CreateTargetProperty(
$sTargetType,
$aData,
$bSkipErrorUniqueCode = true,
$aValidateRules = array(),
$aParams = array(),
$aAdditional = array()
) {
/**
* Если необходимо и поле уже существует, то пропускаем создание
*/
if ($bSkipErrorUniqueCode and isset($aData['code']) and $this->GetPropertyByTargetTypeAndCode($sTargetType,
$aData['code'])
) {
return true;
}
$oProperty = Engine::GetEntity('ModuleProperty_EntityProperty');
$oProperty->_setValidateScenario('auto');
$oProperty->_setDataSafe($aData);
$oProperty->setValidateRulesRaw($aValidateRules);
$oProperty->setParamsRaw($aParams);
$oProperty->setTargetType($sTargetType);
if ($oProperty->_Validate()) {
if ($oProperty->Add()) {
return $oProperty;
} else {
return $this->Lang_Get('property.notices.create_error');
}
} else {
return $oProperty->_getValidateError();
}
return false;
}
/**
* Используется для создания дефолтных дополнительных полей при активации плагина
*
* @param array $aProperties Список полей
* <pre>
* array(
* array(
* 'data'=>array(
* 'type'=>ModuleProperty::PROPERTY_TYPE_INT,
* 'title'=>'Номер',
* 'code'=>'number',
* 'sort'=>100
* ),
* 'validate_rule'=>array(
* 'min'=>10
* ),
* 'params'=>array(),
* 'additional'=>array()
* )
* );
* </pre>
* @param string $sTargetType Тип объекта
*
* @return bool
*/
public function CreateDefaultTargetPropertyFromPlugin($aProperties, $sTargetType)
{
foreach ($aProperties as $aProperty) {
$sResultMsg = $this->CreateTargetProperty($sTargetType, $aProperty['data'], true,
$aProperty['validate_rule'], $aProperty['params'], $aProperty['additional']);
if ($sResultMsg !== true and !is_object($sResultMsg)) {
if (is_string($sResultMsg)) {
$this->Message_AddErrorSingle($sResultMsg, $this->Lang_Get('common.error.error'), true);
}
/**
* Отменяем добавление типа
*/
$this->RemoveTargetType($sTargetType, ModuleProperty::TARGET_STATE_NOT_ACTIVE);
return false;
}
}
return true;
}
public function RemoveValueByPropertyId($iPropertyId)
{
$bRes = $this->oMapper->RemoveValueByPropertyId($iPropertyId);
$this->Cache_Clean(Zend_Cache::CLEANING_MODE_MATCHING_TAG, array('ModuleProperty_EntityValue_delete'));
return $bRes;
}
public function RemoveValueTagByPropertyId($iPropertyId)
{
$bRes = $this->oMapper->RemoveValueTagByPropertyId($iPropertyId);
$this->Cache_Clean(Zend_Cache::CLEANING_MODE_MATCHING_TAG, array('ModuleProperty_EntityValueTag_delete'));
return $bRes;
}
public function RemoveValueSelectByPropertyId($iPropertyId)
{
$bRes = $this->oMapper->RemoveValueSelectByPropertyId($iPropertyId);
$this->Cache_Clean(Zend_Cache::CLEANING_MODE_MATCHING_TAG, array('ModuleProperty_EntityValueSelect_delete'));
return $bRes;
}
public function RemoveSelectByPropertyId($iPropertyId)
{
$bRes = $this->oMapper->RemoveSelectByPropertyId($iPropertyId);
$this->Cache_Clean(Zend_Cache::CLEANING_MODE_MATCHING_TAG, array('ModuleProperty_EntitySelect_delete'));
return $bRes;
}
public function CheckAllowTargetObject($sTargetType, $iTargetId, $aParams = array())
{
$sMethod = 'CheckAllowTargetObject' . func_camelize($sTargetType);
if (method_exists($this, $sMethod)) {
if (!array_key_exists('user', $aParams)) {
$aParams['user'] = $this->oUserCurrent;
}
return $this->$sMethod($iTargetId, $aParams);
}
/**
* По умолчанию считаем доступ разрешен
*/
return true;
}
}

View file

@ -0,0 +1,149 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Поведение для подключения функционала дополнительных полей к сущностям
*
* @package application.modules.property
* @since 2.0
*/
class ModuleProperty_BehaviorEntity extends Behavior
{
/**
* Дефолтные параметры
*
* @var array
*/
protected $aParams = array(
'target_type' => '',
);
/**
* Список хуков
*
* @var array
*/
protected $aHooks = array(
'validate_after' => 'CallbackValidateAfter',
'after_save' => 'CallbackAfterSave',
'after_delete' => 'CallbackAfterDelete',
);
/**
* Коллбэк
* Выполняется при инициализации сущности
*
* @param $aParams
*/
public function CallbackValidateAfter($aParams)
{
if ($aParams['bResult']) {
$aFields = $aParams['aFields'];
if (is_null($aFields) or in_array('properties', $aFields)) {
$oValidator = $this->Validate_CreateValidator('properties_check', $this, 'properties');
$oValidator->validateEntity($this->oObject, $aFields);
$aParams['bResult'] = !$this->oObject->_hasValidateErrors();
}
}
}
/**
* Коллбэк
* Выполняется после сохранения сущности
*/
public function CallbackAfterSave()
{
$this->Property_UpdatePropertiesValue($this->oObject->getPropertiesObject(), $this->oObject);
}
/**
* Коллбэк
* Выполняется после удаления сущности
*/
public function CallbackAfterDelete()
{
$this->Property_RemovePropertiesValue($this->oObject);
}
/**
* Дополнительный метод для сущности
* Запускает валидацию дополнительных полей
*
* @return mixed
*/
public function ValidatePropertiesCheck()
{
return $this->Property_ValidateEntityPropertiesCheck($this->oObject);
}
/**
* Возвращает полный список свойств сущности
*
* @return mixed
*/
public function getPropertyList()
{
return $this->Property_GetEntityPropertyList($this->oObject);
}
/**
* Возвращает значение конкретного свойства
* @see ModuleProperty_EntityValue::getValueForDisplay
*
* @param int|string $sPropertyId ID или код свойства
*
* @return mixed
*/
public function getPropertyValue($sPropertyId)
{
return $this->Property_GetEntityPropertyValue($this->oObject, $sPropertyId);
}
/**
* Возвращает объект конкретного свойства сущности
*
* @param int|string $sPropertyId ID или код свойства
*
* @return ModuleProperty_EntityProperty|null
*/
public function getProperty($sPropertyId)
{
return $this->Property_GetEntityProperty($this->oObject, $sPropertyId);
}
/**
* Возвращает тип объекта для дополнительных полей
*
* @return string
*/
public function getPropertyTargetType()
{
if ($sType = $this->getParam('target_type')) {
return $sType;
}
/**
* Иначе дополнительно смотрим на наличие данного метода у сущности
* Это необходимо, если тип вычисляется динамически по какой-то своей логике
*/
if (func_method_exists($this->oObject, 'getPropertyTargetType', 'public')) {
return call_user_func(array($this->oObject, 'getPropertyTargetType'));
}
}
}

View file

@ -0,0 +1,72 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Поведение для подключения функционала дополнительных полей к модулям
*
* @package application.modules.property
* @since 2.0
*/
class ModuleProperty_BehaviorModule extends Behavior
{
/**
* Список хуков
*
* @var array
*/
protected $aHooks = array(
'module_orm_GetItemsByFilter_after' => array(
'CallbackGetItemsByFilterAfter',
1000
),
'module_orm_GetItemsByFilter_before' => array(
'CallbackGetItemsByFilterBefore',
1000
),
'module_orm_GetByFilter_before' => array(
'CallbackGetItemsByFilterBefore',
1000
),
);
/**
* Модифицирует фильтр в ORM запросе
*
* @param $aParams
*/
public function CallbackGetItemsByFilterAfter($aParams)
{
$aEntities = $aParams['aEntities'];
$aFilter = $aParams['aFilter'];
$this->Property_RewriteGetItemsByFilter($aEntities, $aFilter);
}
/**
* Модифицирует результат ORM запроса
*
* @param $aParams
*/
public function CallbackGetItemsByFilterBefore($aParams)
{
$aFilter = $this->Property_RewriteFilter($aParams['aFilter'], $aParams['sEntityFull']);
$aParams['aFilter'] = $aFilter;
}
}

View file

@ -0,0 +1,345 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Сущность дополнительного поля
*
* @package application.modules.property
* @since 2.0
*/
class ModuleProperty_EntityProperty extends EntityORM
{
protected $aValidateRules = array(
array('type', 'check_type', 'on' => array('create', 'auto')),
array(
'code',
'regexp',
'allowEmpty' => false,
'pattern' => '#^[a-z0-9\_]+$#i',
'on' => array('create', 'update', 'auto')
),
array(
'title',
'string',
'allowEmpty' => false,
'min' => 1,
'max' => 250,
'on' => array('create', 'update', 'auto')
),
array('description', 'string', 'allowEmpty' => true, 'max' => 500, 'on' => array('update', 'auto')),
array('sort', 'number', 'allowEmpty' => false, 'integerOnly' => true, 'min' => 0, 'on' => array('auto')),
array('validate_rules_raw', 'check_validate_rules_raw', 'on' => array('create', 'update', 'auto')),
array('params_raw', 'check_params_raw', 'on' => array('update', 'auto')),
array('code', 'check_code', 'on' => array('create', 'update', 'auto')),
array('title', 'check_title', 'on' => array('create', 'update', 'auto')),
array('description', 'check_description', 'on' => array('update', 'auto')),
);
protected $aRelations = array(
'selects' => array(
self::RELATION_TYPE_HAS_MANY,
'ModuleProperty_EntitySelect',
'property_id',
array('#order' => array('sort' => 'desc'))
),
);
public function ValidateCheckType()
{
if ($this->Property_IsAllowPropertyType($this->getType())) {
return true;
}
return $this->Lang_Get('property.notices.validate_type');
}
public function ValidateCheckCode()
{
if ($oProperty = $this->Property_GetPropertyByTargetTypeAndCode($this->getTargetType(), $this->getCode())) {
if ($this->getId() != $oProperty->getId()) {
return $this->Lang_Get('property.notices.validate_code');
}
}
return true;
}
public function ValidateCheckTitle()
{
$this->setTitle(htmlspecialchars($this->getTitle()));
return true;
}
public function ValidateCheckDescription()
{
$this->setDescription(htmlspecialchars($this->getDescription()));
return true;
}
public function ValidateCheckValidateRulesRaw()
{
$aRulesRaw = $this->getValidateRulesRaw();
/**
* Валидация зависит от типа
*/
$oValue = Engine::GetEntity('ModuleProperty_EntityValue', array(
'property_type' => $this->getType(),
'property_id' => $this->getId(),
'target_type' => $this->getTargetType(),
'target_id' => $this->getId()
));
$oValueType = $oValue->getValueTypeObject();
$aRules = $oValueType->prepareValidateRulesRaw($aRulesRaw);
$this->setValidateRules($aRules);
return true;
}
public function ValidateCheckParamsRaw()
{
$aParamsRaw = $this->getParamsRaw();
/**
* Валидация зависит от типа
*/
$oValue = Engine::GetEntity('ModuleProperty_EntityValue', array(
'property_type' => $this->getType(),
'property_id' => $this->getId(),
'target_type' => $this->getTargetType(),
'target_id' => $this->getId()
));
$oValueType = $oValue->getValueTypeObject();
$aParams = $oValueType->prepareParamsRaw($aParamsRaw);
$this->setParams($aParams);
return true;
}
/**
* Выполняется перед сохранением сущности
*
* @return bool
*/
protected function beforeSave()
{
if ($bResult = parent::beforeSave()) {
if ($this->_isNew()) {
$this->setDateCreate(date("Y-m-d H:i:s"));
$oValue = Engine::GetEntity('ModuleProperty_EntityValue', array(
'property_type' => $this->getType(),
'property_id' => $this->getId(),
'target_type' => $this->getTargetType(),
'target_id' => $this->getId()
));
$oValueType = $oValue->getValueTypeObject();
/**
* Выставляем дефолтные значения параметров
*/
$this->setParams($oValueType->getParamsDefault());
/**
* Выставляем дефолтные значения параметров валидации
*/
$this->setValidateRules($oValueType->getValidateRulesDefault());
}
}
return $bResult;
}
/**
* Выполняется перед удалением сущности
*
* @return bool
*/
protected function beforeDelete()
{
if ($bResult = parent::beforeDelete()) {
/**
* Сначала удаляем стандартные значения
*/
$this->Property_RemoveValueByPropertyId($this->getId());
/**
* Удаляем значения тегов
*/
$this->Property_RemoveValueTagByPropertyId($this->getId());
/**
* Удаляем значения селектов
*/
$this->Property_RemoveValueSelectByPropertyId($this->getId());
/**
* Удаляем сами варианты селектов
*/
$this->Property_RemoveSelectByPropertyId($this->getId());
}
return $bResult;
}
/**
* Возвращает правила валидации поля
*
* @return array
*/
public function getValidateRules()
{
$aData = @unserialize($this->_getDataOne('validate_rules'));
if (!$aData) {
$aData = array();
}
return $aData;
}
/**
* Возвращает экранированный список правил валидации
*
* @return array
*/
public function getValidateRulesEscape()
{
$aRules = $this->getValidateRules();
func_htmlspecialchars($aRules);
return $aRules;
}
/**
* Возвращает конкретное правило валидации
*
* @param string $sRule
*
* @return null|mixed
*/
public function getValidateRuleOne($sRule)
{
$aData = $this->getValidateRules();
if (isset($aData[$sRule])) {
return $aData[$sRule];
}
return null;
}
/**
* Устанавливает правила валидации поля
*
* @param array $aRules
*/
public function setValidateRules($aRules)
{
$this->_aData['validate_rules'] = @serialize($aRules);
}
/**
* Возвращает список дополнительных параметров поля
*
* @return array|mixed
*/
public function getParams()
{
$aData = @unserialize($this->_getDataOne('params'));
if (!$aData) {
$aData = array();
}
return $aData;
}
/**
* Возвращает экранированный список параметров
*
* @return array
*/
public function getParamsEscape()
{
$aParams = $this->getParams();
func_htmlspecialchars($aParams);
return $aParams;
}
/**
* Устанавливает список дополнительных параметров поля
*
* @param $aParams
*/
public function setParams($aParams)
{
$this->_aData['params'] = @serialize($aParams);
}
/**
* Возвращает конкретный параметр поля
*
* @param $sName
*
* @return null
*/
public function getParam($sName)
{
$aParams = $this->getParams();
return isset($aParams[$sName]) ? $aParams[$sName] : null;
}
/**
* Возвращает URL админки для редактирования поля
*
* @return string
*/
public function getUrlAdminUpdate()
{
return Router::GetPath('admin/properties/' . $this->getTargetType() . '/update/' . $this->getId());
}
/**
* Возвращает URL админки для редактирования поля
*
* @return string
*/
public function getUrlAdminRemove()
{
return Router::GetPath('admin/properties/' . $this->getTargetType() . '/remove/' . $this->getId());
}
/**
* Возвращает описание типа поля
*
* @return mixed
*/
public function getTypeTitle()
{
/**
* TODO: использовать текстовку из языкового
*/
return $this->getType();
}
public function getSaveFileDir($sPostfix = '')
{
$sPostfix = trim($sPostfix, '/');
return Config::Get('path.uploads.base') . '/property/' . $this->getTargetType() . '/' . $this->getType() . '/' . date('Y/m/d/H/') . ($sPostfix ? "{$sPostfix}/" : '');
}
public function isEmpty()
{
if (!$oValue = $this->getValue()) {
return true;
}
return $oValue->isEmpty();
}
public function getValueTypeObject()
{
if ($oValue = $this->getValue()) {
return $oValue->getValueTypeObject();
}
}
}

View file

@ -0,0 +1,35 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Сущность дополнительного поля
*
* @package application.modules.property
* @since 2.0
*/
class ModuleProperty_EntitySelect extends EntityORM
{
protected $aValidateRules = array();
protected $aRelations = array();
}

View file

@ -0,0 +1,83 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Сущность связи поля с объектом
*
* @package application.modules.property
* @since 2.0
*/
class ModuleProperty_EntityTarget extends EntityORM
{
protected $aValidateRules = array();
protected $aRelations = array();
protected function beforeSave()
{
if ($bResult = parent::beforeSave()) {
if ($this->_isNew()) {
$this->setDateCreate(date("Y-m-d H:i:s"));
} else {
$this->setDateUpdate(date("Y-m-d H:i:s"));
}
}
return $bResult;
}
/**
* Возвращает список дополнительных параметров
*
* @return array|mixed
*/
public function getParams()
{
$aData = @unserialize($this->_getDataOne('params'));
if (!$aData) {
$aData = array();
}
return $aData;
}
/**
* Устанавливает список дополнительных параметров
*
* @param $aParams
*/
public function setParams($aParams)
{
$this->_aData['params'] = @serialize($aParams);
}
/**
* Возвращает конкретный параметр
*
* @param $sName
*
* @return null
*/
public function getParam($sName)
{
$aParams = $this->getParams();
return isset($aParams[$sName]) ? $aParams[$sName] : null;
}
}

View file

@ -0,0 +1,101 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Сущность значения поля
*
* @package application.modules.property
* @since 2.0
*/
class ModuleProperty_EntityValue extends EntityORM
{
protected $aRelations = array(
'property' => array(self::RELATION_TYPE_BELONGS_TO, 'ModuleProperty_EntityProperty', 'property_id'),
);
protected function beforeSave()
{
if ($bResult = parent::beforeSave()) {
$oValueType = $this->getValueTypeObject();
$oValueType->beforeSaveValue();
}
return $bResult;
}
public function getValueForDisplay()
{
$oValueType = $this->getValueTypeObject();
return $oValueType->getValueForDisplay();
}
public function isEmpty()
{
$oValueType = $this->getValueTypeObject();
return $oValueType->isEmpty();
}
public function getValueForForm()
{
$oValueType = $this->getValueTypeObject();
return $oValueType->getValueForForm();
}
public function getValueTypeObject()
{
if (!$this->_getDataOne('value_type_object')) {
$oObject = Engine::GetEntity('ModuleProperty_EntityValueType' . func_camelize($this->getPropertyType()));
$oObject->setValueObject($this);
$this->setValueTypeObject($oObject);
}
return $this->_getDataOne('value_type_object');
}
public function getData()
{
$aData = @unserialize($this->_getDataOne('data'));
if (!$aData) {
$aData = array();
}
return $aData;
}
public function setData($aRules)
{
$this->_aData['data'] = @serialize($aRules);
}
public function getDataOne($sKey)
{
$aData = $this->getData();
if (isset($aData[$sKey])) {
return $aData[$sKey];
}
return null;
}
public function setDataOne($sKey, $mValue)
{
$aData = $this->getData();
$aData[$sKey] = $mValue;
$this->setData($aData);
}
}

View file

@ -0,0 +1,33 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Сущность значений поля типа Select
*
* @package application.modules.property
* @since 2.0
*/
class ModuleProperty_EntityValueSelect extends EntityORM
{
protected $aRelations = array();
}

View file

@ -0,0 +1,33 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Сущность значений поля типа Tag
*
* @package application.modules.property
* @since 2.0
*/
class ModuleProperty_EntityValueTag extends EntityORM
{
protected $aRelations = array();
}

View file

@ -0,0 +1,144 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Базовый объект значения поля
*
* @package application.modules.property
* @since 2.0
*/
class ModuleProperty_EntityValueType extends Entity
{
protected $oValue = null;
public function getValueForDisplay()
{
// TODO: getValue() всегда вернет null
return $this->getValueObject()->getValue();
}
public function getValueForForm()
{
return htmlspecialchars($this->getValueObject()->getValue());
}
public function isEmpty()
{
return $this->getValueObject()->getValueVarchar() ? false : true;
}
public function validate()
{
return 'Неверное значение';
}
protected function validateStandart(
$sTypeValidator,
$aParamsAdditional = array(),
$sFieldForValidate = 'value_for_validate'
) {
$oProperty = $this->getValueObject()->getProperty();
/**
* Получаем параметры валидации
*/
$aParams = $oProperty->getValidateRules();
if (!isset($aParams['label'])) {
$aParams['label'] = '';
}
$aParams = array_merge($aParams, $aParamsAdditional);
$oValidator = $this->Validate_CreateValidator($sTypeValidator, $this, null, $aParams);
$oValidator->fields = array($sFieldForValidate);
$oValidator->validateEntity($this);
if ($this->_hasValidateErrors()) {
return $this->_getValidateError();
} else {
return true;
}
}
public function setValue($mValue)
{
$this->resetAllValue();
}
public function setValueObject($oValue)
{
$this->oValue = $oValue;
}
public function getValueObject()
{
return $this->oValue;
}
public function resetAllValue()
{
$oValue = $this->getValueObject();
$oValue->setValueInt(null);
$oValue->setValueFloat(null);
$oValue->setValueVarchar(null);
$oValue->setValueText(null);
$oValue->setValueDate(null);
$oValue->setData(null);
/**
* Удаляем из таблицы тегов
*/
$this->Property_RemoveValueTagsByTarget($oValue->getTargetType(), $oValue->getTargetId(),
$oValue->getPropertyId());
/**
* Удаляем из таблицы селектов
*/
$this->Property_RemoveValueSelectsByTarget($oValue->getTargetType(), $oValue->getTargetId(),
$oValue->getPropertyId());
}
public function prepareValidateRulesRaw($aRulesRaw)
{
return array();
}
public function getValidateRulesDefault()
{
return array();
}
public function prepareParamsRaw($aParamsRaw)
{
return array();
}
public function getParamsDefault()
{
return array();
}
public function beforeSaveValue()
{
}
public function removeValue()
{
}
}

View file

@ -0,0 +1,81 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Объект управления типом checkbox
*
* @package application.modules.property
* @since 2.0
*/
class ModuleProperty_EntityValueTypeCheckbox extends ModuleProperty_EntityValueType
{
public function getValueForDisplay()
{
return $this->getValueObject()->getValueInt() ? 'да' : 'нет';
}
public function getValueForForm()
{
$oValue = $this->getValueObject();
$oProperty = $oValue->getProperty();
return $oValue->_isNew() ? $oProperty->getParam('default') : $oValue->getValueInt();
}
public function isEmpty()
{
return false;
}
public function validate()
{
$sValue = $this->getValueForValidate();
$this->setValueForValidate($sValue ? 1 : 0);
return true;
}
public function setValue($mValue)
{
$this->resetAllValue();
$oValue = $this->getValueObject();
$oProperty = $oValue->getProperty();
$oValue->setValueInt($mValue ? $oProperty->getParam('default_value') : 0);
}
public function prepareParamsRaw($aParamsRaw)
{
$aParams = array();
$aParams['default'] = isset($aParamsRaw['default']) ? true : false;
if (isset($aParamsRaw['default_value'])) {
$aParams['default_value'] = htmlspecialchars($aParamsRaw['default_value']);
}
return $aParams;
}
public function getParamsDefault()
{
return array(
'default_value' => 1,
);
}
}

View file

@ -0,0 +1,159 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Объект управления типом date
*
* @package application.modules.property
* @since 2.0
*/
class ModuleProperty_EntityValueTypeDate extends ModuleProperty_EntityValueType
{
protected $sFormatDateInput = 'dd.MM.yyyy';
protected $sFormatDateTimeInput = 'dd.MM.yyyy HH:mm';
public function getValueForDisplay()
{
$oValue = $this->getValueObject();
$oProperty = $oValue->getProperty();
return $oValue->getValueDate() ? $this->Viewer_GetDateFormat(strtotime($oValue->getValueDate()), $oProperty->getParam('format_out')) : '';
}
public function isEmpty()
{
return $this->getValueObject()->getValueDate() ? false : true;
}
public function getValueForForm()
{
$oValue = $this->getValueObject();
$sDate = $oValue->getValueDate();
$iTime = strtotime($sDate);
// TODO: нужен конвертор формата дат вида Y в yyyy для учета $this->sFormatDateInput
return $sDate ? date('d.m.Y', $iTime) : '';
}
public function getValueTimeForForm()
{
$oValue = $this->getValueObject();
$sDate = $oValue->getValueDate();
return $sDate ? date('H:i', strtotime($sDate)) : '';
}
public function validate()
{
/**
* Данные поступают ввиде массива array( 'date'=>'..', 'time' => '..' )
*/
$aValue = $this->getValueForValidate();
$oValueObject = $this->getValueObject();
$oProperty = $oValueObject->getProperty();
$this->setValueForValidateDate(isset($aValue['date']) ? $aValue['date'] : '');
/**
* Формируем формат для валидации даты
* В инпуте дата идет в формате d.m.Y и плюс H:i если используется время
*/
if ($oProperty->getParam('use_time')) {
$sFormatValidate = $this->sFormatDateTimeInput;
if (isset($aValue['time'])) {
$this->setValueForValidateDate($this->getValueForValidateDate() . ' ' . $aValue['time']);
}
} else {
$sFormatValidate = $this->sFormatDateInput;
}
$mRes = $this->validateStandart('date', array('format' => $sFormatValidate), 'value_for_validate_date');
if ($mRes === true) {
/**
* Формируем полную дату
*/
if ($this->getValueForValidateDate()) {
$sTimeFull = strtotime($this->getValueForValidateDate());
/**
* Проверка на ограничение даты
*/
if ($oProperty->getValidateRuleOne('disallowFuture')) {
if ($sTimeFull > time()) {
return "{$oProperty->getTitle()}: " . $this->Lang_Get('property.notices.validate_value_date_future');
}
}
/**
* Проверка на ограничения только если это новая запись, либо старая с изменениями
*/
if ($oValueObject->_isNew() or strtotime($oValueObject->getValueDate()) != $sTimeFull) {
if ($oProperty->getValidateRuleOne('disallowPast')) {
if ($sTimeFull < time()) {
return "{$oProperty->getTitle()}: " . $this->Lang_Get('property.notices.validate_value_date_past');
}
}
}
} else {
$sTimeFull = null;
}
/**
* Переопределяем результирующее значение
*/
$this->setValueForValidate($sTimeFull ? date('Y-m-d H:i:00', $sTimeFull) : null);
return true;
} else {
return $mRes;
}
}
public function setValue($mValue)
{
$this->resetAllValue();
$oValue = $this->getValueObject();
$oValue->setValueDate($mValue ? $mValue : null);
}
public function prepareValidateRulesRaw($aRulesRaw)
{
$aRules = array();
$aRules['allowEmpty'] = isset($aRulesRaw['allowEmpty']) ? false : true;
$aRules['disallowFuture'] = isset($aRulesRaw['disallowFuture']) ? true : false;
$aRules['disallowPast'] = isset($aRulesRaw['disallowPast']) ? true : false;
return $aRules;
}
public function prepareParamsRaw($aParamsRaw)
{
$aParams = array();
$aParams['use_time'] = isset($aParamsRaw['use_time']) ? true : false;
if (isset($aParamsRaw['format_out'])) {
$aParams['format_out'] = $aParamsRaw['format_out'];
}
return $aParams;
}
public function getParamsDefault()
{
return array(
'format_out' => 'Y-m-d H:i',
'use_time' => true,
);
}
}

View file

@ -0,0 +1,305 @@
<?php
/*
* LiveStreet CMS
* Copyright © 2013 OOO "ЛС-СОФТ"
*
* ------------------------------------------------------
*
* Official site: www.livestreetcms.com
* Contact e-mail: office@livestreetcms.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* ------------------------------------------------------
*
* @link http://www.livestreetcms.com
* @copyright 2013 OOO "ЛС-СОФТ"
* @author Maxim Mzhelskiy <rus.engine@gmail.com>
*
*/
/**
* Объект управления типом file
*
* @package application.modules.property
* @since 2.0
*/
class ModuleProperty_EntityValueTypeFile extends ModuleProperty_EntityValueType
{
public function getValueForDisplay()
{
return $this->getFileFullName();
}
public function isEmpty()
{
return $this->getFileFullName() ? false : true;
}
public function validate()
{
$oValue = $this->getValueObject();
$oProperty = $oValue->getProperty();
$iPropertyId = $oProperty->getId();
$bNeedRemove = false;
$mValue = $this->getValueForValidate();
if (isset($mValue['remove']) and $mValue['remove']) {
$bNeedRemove = true;
$this->setValueForValidate(array('remove' => true));
}
$sFileName = $this->_getValueFromFiles($iPropertyId, 'name');
$sFileTmpName = $this->_getValueFromFiles($iPropertyId, 'tmp_name');
$sFileError = $this->_getValueFromFiles($iPropertyId, 'error');
$sFileSize = $this->_getValueFromFiles($iPropertyId, 'size');
if (!$sFileTmpName) {
if ($oProperty->getValidateRuleOne('allowEmpty')) {
return true;
} elseif ($aFilePrev = $oValue->getDataOne('file') and isset($aFilePrev['path']) and !$bNeedRemove) {
return true;
} else {
return $this->Lang_Get('property.notices.validate_value_file_empty');
}
}
/**
* Проверяем на ошибки
*/
if ($sFileError and $sFileError != UPLOAD_ERR_NO_FILE) {
return $this->Lang_Get('property.notices.validate_value_file_upload') . " - {$sFileError}";
}
/**
* На корректность загрузки
*/
if (!$sFileName or !$sFileTmpName) {
return false;
}
/**
* На ограничение по размеру файла
*/
if ($iSizeKb = $oProperty->getValidateRuleOne('size_max') and $iSizeKb * 1024 < $sFileSize) {
return $this->Lang_Get('property.notices.validate_value_file_size_max', array('size' => $iSizeKb));
}
/**
* На допустимые типы файлов
*/
$aPath = pathinfo($sFileName);
if (!isset($aPath['extension']) or !$aPath['extension']) {
return false;
}
if ($aTypes = $oProperty->getParam('types') and !in_array($aPath['extension'], $aTypes)) {
return $this->Lang_Get('property.notices.validate_value_file_type', array('types' => join(', ', $aTypes)));
}
/**
* Пробрасываем данные по файлу
*/
$this->setValueForValidate(array(
'name' => $sFileName,
'tmp_name' => $sFileTmpName,
'error' => $sFileError,
'size' => $sFileSize,
));
return true;
}
protected function _getValueFromFiles($iId, $sName)
{
if (isset($_FILES['property'][$sName][$iId]['file'])) {
return $_FILES['property'][$sName][$iId]['file'];
}
return null;
}
/**
* Устанавливает значение после валидации конкретного поля, а не всех полей
* Поэтому здесь нельзя сохранять файл, это нужно делать в beforeSaveValue()
*
* @param $aValue
*/
public function setValue($aValue)
{
$oValue = $this->getValueObject();
/**
* Просто пробрасываем данные
*/
if ($aValue) {
$oValue->setDataOne('file_raw', $aValue);
}
}
/**
* Дополнительная обработка перед сохранением значения
* Здесь нужно выполнять основную загрузку файла
*/
public function beforeSaveValue()
{
$oValue = $this->getValueObject();
$oProperty = $oValue->getProperty();
if (!$aFile = $oValue->getDataOne('file_raw')) {
return true;
}
$oValue->setDataOne('file_raw', null);
/**
* Удаляем предыдущий файл
*/
if (isset($aFile['remove']) or isset($aFile['name'])) {
if ($aFilePrev = $oValue->getDataOne('file')) {
$this->RemoveFile($aFilePrev['path']);
$oValue->setDataOne('file', array());
$oValue->setValueVarchar(null);
}
}
if (isset($aFile['name'])) {
/**
* Выполняем загрузку файла
*/
$aPathInfo = pathinfo($aFile['name']);
$sExtension = isset($aPathInfo['extension']) ? $aPathInfo['extension'] : 'unknown';
$sFileName = func_generator(20) . '.' . $sExtension;
/**
* Копируем загруженный файл
*/
$sDirTmp = Config::Get('path.tmp.server') . '/property/';
if (!is_dir($sDirTmp)) {
@mkdir($sDirTmp, 0777, true);
}
$sFileTmp = $sDirTmp . $sFileName;
if (move_uploaded_file($aFile['tmp_name'], $sFileTmp)) {
$sDirSave = Config::Get('path.root.server') . $oProperty->getSaveFileDir();
if (!is_dir($sDirSave)) {
@mkdir($sDirSave, 0777, true);
}
$sFilePath = $sDirSave . $sFileName;
/**
* Сохраняем файл
*/
if ($sFilePathNew = $this->SaveFile($sFileTmp, $sFilePath, null, true)) {
/**
* Сохраняем данные о файле
*/
$oValue->setDataOne('file', array(
'path' => $sFilePathNew,
'size' => filesize($sFilePath),
'name' => htmlspecialchars($aPathInfo['filename']),
'extension' => htmlspecialchars($aPathInfo['extension']),
));
/**
* Сохраняем уникальный ключ для доступа к файлу
*/
$oValue->setValueVarchar(func_generator(32));
return true;
}
}
}
}
public function prepareValidateRulesRaw($aRulesRaw)
{
$aRules = array();
$aRules['allowEmpty'] = isset($aRulesRaw['allowEmpty']) ? false : true;
if (isset($aRulesRaw['size_max']) and is_numeric($aRulesRaw['size_max'])) {
$aRules['size_max'] = (int)$aRulesRaw['size_max'];
}
return $aRules;
}
public function prepareParamsRaw($aParamsRaw)
{
$aParams = array();
$aParams['types'] = array();
if (isset($aParamsRaw['types']) and is_array($aParamsRaw['types'])) {
foreach ($aParamsRaw['types'] as $sType) {
if ($sType) {
$aParams['types'][] = htmlspecialchars($sType);
}
}
}
$aParams['access_only_auth'] = isset($aParamsRaw['access_only_auth']) ? true : false;
return $aParams;
}
public function getParamsDefault()
{
return array(
'types' => array(
'zip'
),
);
}
public function removeValue()
{
$oValue = $this->getValueObject();
/**
* Удаляем файл
*/
if ($aFilePrev = $oValue->getDataOne('file')) {
$this->RemoveFile($aFilePrev['path']);
}
}
public function getFileFullName()
{
$oValue = $this->getValueObject();
if ($aFilePrev = $oValue->getDataOne('file')) {
return $aFilePrev['name'] . '.' . $aFilePrev['extension'];
}
return null;
}
public function getCountDownloads()
{
$aStats = $this->oValue->getDataOne('stats');
return isset($aStats['count_download']) ? $aStats['count_download'] : 0;
}
/**
* Сохраняет(копирует) файл на сервер
* Если переопределить данный метод, то можно сохранять файл, например, на Amazon S3
*
* @param string $sFileSource Полный путь до исходного файла
* @param string $sFileDest Полный путь до файла для сохранения с типом, например, [server]/home/var/site.ru/book.pdf
* @param int|null $iMode Права chmod для файла, например, 0777
* @param bool $bRemoveSource Удалять исходный файл или нет
* @return bool | string При успешном сохранении возвращает относительный путь до файла с типом, например, [relative]/image.jpg
*/
protected function SaveFile($sFileSource, $sFileDest, $iMode = null, $bRemoveSource = false)
{
if ($this->Fs_SaveFileLocal($sFileSource, $this->Fs_GetPathServer($sFileDest), $iMode, $bRemoveSource)) {
return $this->Fs_MakePath($this->Fs_GetPathRelativeFromServer($sFileDest), ModuleFs::PATH_TYPE_RELATIVE);
}
return false;
}
/**
* Удаляет файл
* Если переопределить данный метод, то можно удалять файл, например, с Amazon S3
*
* @param string $sPathFile Полный путь до файла с типом, например, [relative]/book.pdf
*
* @return mixed
*/
protected function RemoveFile($sPathFile)
{
$sPathFile = $this->Fs_GetPathServer($sPathFile);
return $this->Fs_RemoveFileLocal($sPathFile);
}
public function DownloadFile()
{
$oValue = $this->getValueObject();
if ($aFilePrev = $oValue->getDataOne('file')) {
$this->Tools_DownloadFile($this->Fs_GetPathServer($aFilePrev['path']),
$aFilePrev['name'] . '.' . $aFilePrev['extension'], $aFilePrev['size']);
}
return false;
}
}

Some files were not shown because too many files have changed in this diff Show more