'; /** * Список символов, запрещенных для использования в wordforms * @return mixed */ public static function wordformsCharsForbidden() { return bff::filter('sphinx.wordforms.chars.forbidden', '/"\'\\'); } /** * Путь к конфигурационному файлу модуля * @return string */ protected function wordformsFile() { return $this->dir() . DS . 'wordforms' . $this->moduleID() . '.txt'; } /** * Добавление словоформ в конфигурацию индекса и сохранение при необходимости * @param array $config @ref * @return bool */ public function wordformsConfig(&$config) { $cnt = $this->wordformsListing(); if ($cnt) { if ($this->wordformsFileUpdate()) { $config['wordforms'] = $this->wordformsFile(); } } return false; } /** * Менеджер для управления словоформами * @param array $ajaxParams URL для обработки ajax запросов * @return string HTML */ public function wordformsManager($ajaxParams = []) { if (empty($ajaxParams['action'])) { $action = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2)[1]['function']; } else { $action = $ajaxParams['action']; } unset($ajaxParams['action']); if (empty($ajaxParams['s'])) { $ajaxParams['s'] = Route::controllerName(); } $form = Admin::form($this, 'admin/wordforms.form', ['action' => $action]); $form->ajaxParams($ajaxParams); $form->defaultCssClass($form->defaultCssClass() . '-' . Route::controllerName()); $form ->onSubmit(function ($id, $params) { $many = $this->input->post('many', TYPE_UINT); if ($many) { $text = $params['data']['text']; if (empty($text)) { $this->errors->set(_t('sphinx', 'Specify a list of word forms'), 'text'); return false; } if (! mb_strpos($text, $this->wordformsSeparator)) { $this->errors->set(_t('sphinx', 'The synonym and original are separated by [separator]', ['separator' => '"' . $this->wordformsSeparator . '"']), 'text'); return false; } $cnt = $this->wordformSaveMany($text); $params['response']['msg'] = _t('sphinx', 'Added [cnt]', ['cnt' => tpl::declension($cnt, _t('sphinx', 'wordform;wordforms;wordforms'))]); return false; } else { unset($params['data']['text']); return $this->wordformCheck($params['data'], $id); } }) ->onLoad(function ($id) { return $this->wordformData($id); }) ->onSave(function ($id, $save) { return $this->wordformSave($id, $save); }); $list = Admin::list($this, 'admin/wordforms.list', ['action' => $action]); $list->ajaxParams($ajaxParams); $list->defaultCssClass($list->defaultCssClass() . '-' . Route::controllerName()); $list->formAdd($form, ['popup' => true]); $list->onDelete(function ($id) { $this->wordformDelete($id); }); $sql = []; $q = $list->filter('q'); if ($q) { $sql[':q'] = ['(src LIKE :q OR dest LIKE :q)', ':q' => '%' . $q . '%']; } $list->total($this->wordformsListing($sql)); $rows = $this->wordformsListing($sql, ['id','src','dest'], $list->getLimitOffset(), $list->order('id-desc', true)); $list->rows($rows); return $list->view(); } /** * Проверка параметров словоформы * @param array $data параметры словоформы * @param int $wordformID ID словоформы или 0 * @param bool $setErrors устанавливать ошибки * @return bool проверка прошла успешно (true) */ protected function wordformCheck($data, $wordformID, $setErrors = true) { do { if (empty($data['src'])) { if ($setErrors) { $this->errors->set(_t('sphinx', 'Enter synonym'), 'src'); } break; } if (mb_strlen($data['src']) < 3) { if ($setErrors) { $this->errors->set(_t('sphinx', 'The word synonym is too short'), 'src'); } break; } if (empty($data['dest'])) { if ($setErrors) { $this->errors->set(_t('sphinx', 'Enter the original word'), 'src'); } break; } if (mb_strlen($data['dest']) < 3) { if ($setErrors) { $this->errors->set(_t('sphinx', 'The original word is too short'), 'dest'); } } if ($data['src'] == $data['dest']) { if ($setErrors) { $this->errors->set(_t('sphinx', 'The specified words cannot be identical'), 'dest'); } break; } $denied = static::wordformsCharsForbidden(); $exist = strpbrk($data['src'], $denied); if ($exist !== false) { if ($setErrors) { $this->errors->set(_t('sphinx', 'The word synonym contains a forbidden symbol: [symbol]', ['symbol' => mb_substr($exist, 0, 1)]), 'src'); } break; } $exist = strpbrk($data['dest'], $denied); if ($exist !== false) { if ($setErrors) { $this->errors->set(_t('sphinx', 'The original word contains a forbidden symbol: [symbol]', ['symbol' => mb_substr($exist, 0, 1)]), 'dest'); } break; } $filter = [ ':exist' => ['(src = :query OR dest = :query)', ':query' => $data['src']], ]; if ($wordformID) { $filter['id'] = ['!=', $wordformID]; } if ($this->wordformsListing($filter)) { if ($setErrors) { $this->errors->set(_t('sphinx', 'The wordform [word] is already in use', ['word' => '"' . $data['src'] . '"']), 'src'); } break; } $filter = [ 'src' => $data['dest'], ]; if ($wordformID) { $filter['id'] = ['!=', $wordformID]; } if ($this->wordformsListing($filter)) { if ($setErrors) { $this->errors->set(_t('sphinx', 'The wordform [word] is already in use', ['word' => '"' . $data['dest'] . '"']), 'dest'); } break; } return true; } while (false); return false; } /** * Сохранение данных словоформы * @param int $wordformID ID словоформы * @param array $data данные * @return mixed */ protected function wordformSave($wordformID, array $data) { if (empty($data)) { return false; } if ($wordformID > 0) { $res = $this->db->update(static::TABLE_WORDFORMS, $data, [ 'id' => $wordformID, 'module' => $this->moduleID(), ]); if ($res) { $this->wordformsFileUpdate(); } } else { if (empty($data['created'])) { $data['created'] = $this->db->now(); } if (! isset($data['module'])) { $data['module'] = $this->moduleID(); } $res = $this->db->insert(static::TABLE_WORDFORMS, $data); if ($res) { $cnt = $this->wordformsListing(); if ($cnt == 1) { $this->configFile(); } else { $this->wordformsFileUpdate(); } } } return $res; } /** * Пакетное добавление словоформ * @param string $text текст содержащий список словорм * @return int кол-во добавленных словоформ */ protected function wordformSaveMany($text) { $cnt = 0; $text = explode("\n", $text); foreach ($text as $v) { $row = explode($this->wordformsSeparator, $v); if (count($row) != 2) { continue; } $data = [ 'src' => trim($row[0]), 'dest' => trim($row[1]), ]; if (! $this->wordformCheck($data, 0, false)) { continue; } $this->wordformSave(0, $data); $cnt++; } return $cnt; } /** * Данные словоформы * @param int $wordformID ID словоформы * @param array $fields список полей * @return array */ protected function wordformData($wordformID, array $fields = []) { if (empty($fields)) { $fields = ['*']; } if (! $wordformID) { return []; } $data = $this->db->select_row(static::TABLE_WORDFORMS, $fields, ['id' => $wordformID]); if (empty($data)) { return []; } return $data; } /** * Удаление словоформы * @param int $wordformID ID словоформы */ protected function wordformDelete($wordformID) { $this->db->delete(static::TABLE_WORDFORMS, array('id' => $wordformID, 'module' => $this->moduleID())); $cnt = $this->wordformsListing(); if ($cnt) { $this->wordformsFileUpdate(); } else { $this->configFile(); } } /** * Список словоформ * @param array $filter фильтр * @param array $fields список полей * @param string $limit SQL Limit * @param string $order SQL Order * @return mixed */ protected function wordformsListing(array $filter = [], array $fields = [], $limit = '', $order = '') { if (! isset($filter['module'])) { $filter['module'] = $this->moduleID(); } if (empty($fields)) { return $this->db->select_rows_count(static::TABLE_WORDFORMS, $filter); } $data = $this->db->select_rows(static::TABLE_WORDFORMS, $fields, $filter, $order, $limit); if (empty($data)) { return []; } return $data; } /** * Сохранение списка словоформ в конфигурационный файл * @return bool true удалось сохранить */ protected function wordformsFileUpdate() { $path = $this->wordformsFile(); $file = fopen($path, 'w'); if ($file === false) { bff::log(_t('dev', 'Unable to create file "[file]"', ['file' => $path])); return false; } $select = $this->db->select_prepare(static::TABLE_WORDFORMS, ['src','dest'], [ 'module' => $this->moduleID(), ]); $this->db->select_iterator($select['query'], $select['bind'], function ($row) use (&$file) { fwrite($file, $row['src'] . ' ' . $this->wordformsSeparator . ' ' . $row['dest'] . PHP_EOL); }); fclose($file); return true; } }