public function set($value, &$node)
 {
     if (empty($value) or !is_array($value)) {
         return;
     }
     switch ($value['error']) {
         case UPLOAD_ERR_OK:
             $value = Node::create('file')->import($value);
             break;
         case UPLOAD_ERR_INI_SIZE:
             throw new RuntimeException(t('Размер файла превышает установленное в системе ограничение (%size).', array('%size' => ini_get('upload_max_filesize'))));
         case UPLOAD_ERR_FORM_SIZE:
             throw new RuntimeException(t('Размер файла превышает установленное в форме ограничение.'));
         case UPLOAD_ERR_PARTIAL:
             throw new RuntimeException(t('Файл получен не полностью.'));
         case UPLOAD_ERR_NO_FILE:
             if (!empty($value['id']) and is_numeric($value['id'])) {
                 $value = Node::load($value['id']);
             } elseif (!empty($value['url'])) {
                 $value = FileNode::fromURL($value['url']);
             } elseif (!empty($value['ftp'])) {
                 $value = Node::create('file')->importFromFTP(array_shift($value['ftp']));
             } elseif (!empty($value['unlink'])) {
                 $node->linkRemoveChild(null, $this->value);
                 $value = null;
             } else {
                 $value = $node->{$this->value};
             }
     }
     if ($this->required and empty($value)) {
         throw new ValidationException($this->label, t('Вы не загрузили файл в поле «%name», хотя оно отмечено как обязательное.', array('%name' => mb_strtolower($this->label))));
     }
     $node->{$this->value} = $value;
 }
 public static function rpc_get_default(Context $ctx)
 {
     $user = Node::load(array('class' => 'user', 'deleted' => 0, 'published' => 1, 'id' => $ctx->get('id')), $ctx->db);
     $email = $user ? $user->email : '*****@*****.**';
     $gurl = 'http://www.gravatar.com/avatar/' . md5($email);
     if (null !== ($s = $ctx->get('s'))) {
         $gurl .= '?s=' . intval($s) . '&r=x';
     }
     return new Redirect($gurl);
 }
 /**
  * Открепление файлов от ноды.
  */
 public static function on_post_detach(Context $ctx)
 {
     if (is_array($ids = $ctx->post('remove'))) {
         $ctx->db->beginTransaction();
         $params = array();
         Node::load($ctx->get('id'), $ctx->db)->touch(ACL::UPDATE)->onSave('DELETE FROM `node__rel` WHERE `tid` = %ID% AND `key` IS NULL AND `nid` ' . sql::in($ids, $params), $params)->save();
         $ctx->db->commit();
     }
     return $ctx->getRedirect();
 }
 /**
  * Добавляет тип документа label.
  *
  * @mcms_message ru.molinos.cms.install
  */
 public static function onInstall(Context $ctx)
 {
     try {
         $node = Node::load(array('class' => 'type', 'name' => 'label'), $ctx->db);
     } catch (ObjectNotFoundException $e) {
         $ctx->db->beginTransaction();
         $node = Node::create(array('class' => 'type', 'name' => 'label', 'label' => t('Метка'), 'isdictionary' => true, 'fields' => array('name' => array('type' => 'TextLineControl', 'title' => t('Метка'), 'required' => true))), $ctx->db)->save();
         $ctx->db->commit();
     }
 }
 public static function on_get_list(Context $ctx)
 {
     $xml = $ctx->db->getResult("SELECT `xmltree` FROM `node` WHERE `class` = 'tag' AND `parent_id` IS NULL");
     if (empty($xml)) {
         $node = Node::load(array('class' => 'tag', 'deleted' => 0, 'parent_id' => null), $ctx->db);
         $xml = $node->getTreeXML(false, true);
     }
     $data = html::em('data', $xml);
     return html::em('content', array('edit' => true, 'nosearch' => true, 'name' => 'list', 'title' => t('Карта разделов сайта'), 'preset' => 'taxonomy'), $data);
 }
Exemple #6
0
 /**
  * Воссоздаёт контролы из БД.
  */
 public static function rebuild(Database $db, $className)
 {
     try {
         $node = Node::load(array('class' => 'type', 'name' => $className, 'deleted' => 0), $db);
         $schema = (array) $node->fields;
     } catch (ObjectNotFoundException $e) {
         $schema = array();
     }
     return $schema;
 }
 /**
  * Инсталляция типа документа subscription.
  *
  * @mcms_message ru.molinos.cms.install
  */
 public static function onInstall(Context $ctx)
 {
     try {
         $node = Node::load(array('class' => 'type', 'name' => 'subscription', 'deleted' => 0), $ctx->db);
     } catch (ObjectNotFoundException $e) {
         $ctx->db->beginTransaction();
         $node = Node::create('type', array('name' => 'subscription', 'title' => t('Подписка на новости')))->save();
         $ctx->db->commit();
     }
 }
 private static function getEmail(Context $ctx)
 {
     if ($id = $ctx->config->get('modules/admin/admin')) {
         try {
             $node = Node::load(array('id' => $id, 'class' => 'user'));
             return $node->getEmail();
         } catch (ObjectNotFoundException $e) {
         }
     }
 }
 /**
  * Обновление XML ноды и всех её связей.
  */
 private static function update_node_xml(Node $node)
 {
     if ($ids = self::get_ids($node)) {
         $upd = $node->getDB()->prepare("UPDATE `node` SET `xml` = ? WHERE `id` = ?");
         foreach ($ids as $id) {
             $upd->execute(array(Node::load($id, $node->getDB())->getXML(), $id));
             Logger::log("node[{$id}]: XML updated", 'xml');
         }
     }
 }
 public function testLoadNode()
 {
     $id = get_test_context()->db->getResult("SELECT `id` FROM `node` WHERE `deleted` = 0 AND `class` = 'type' AND `name` = 'domain'");
     $this->assertNotEquals(null, $id);
     $node = Node::load($id);
     $this->assertTrue($node instanceof Node);
     $this->assertEquals($id, $node->id);
     $this->assertEquals('type', $node->class);
     $this->assertEquals('domain', $node->name);
 }
Exemple #11
0
 public function __get($k)
 {
     if (!property_exists($this, $k)) {
         if (property_exists($this, 'ref_' . $k) && null !== $this->{'ref_' . $k}) {
             $this->{$k} = Node::load($this->{'ref_' . $k});
         } else {
             $this->{$k} = null;
         }
     }
     return $this->{$k};
 }
 /**
  * @mcms_message ru.molinos.cms.install
  */
 public static function on_install(Context $ctx)
 {
     try {
         $node = Node::load(array('class' => 'type', 'name' => 'tag', 'deleted' => 0), $ctx->db);
     } catch (ObjectNotFoundException $e) {
         $node = Node::create(array('class' => 'type', 'name' => 'tag', 'title' => t('Раздел'), 'fields' => array('name' => array('type' => 'TextLineControl', 'title' => t('Имя раздела'), 'required' => true))), $ctx->db);
         $node->getDB()->beginTransaction();
         $node->save();
         $node->getDB()->commit();
     }
 }
 public static function rpc_get_restore(Context $ctx)
 {
     $node = Node::load(array('class' => 'user', 'name' => $ctx->get('email'), 'deleted' => 0, 'published' => 1));
     if ($ctx->get('otp') != $node->otp) {
         throw new ForbiddenException(t('Эта ссылка устарела.'));
     }
     $ctx->db->beginTransaction();
     unset($node->otp);
     $node->save();
     $ctx->db->commit();
     $ctx->user->login($node->name, null, true);
     Logger::log($node->name . ' logged in using OTP.', 'auth');
 }
 /**
  * 
  */
 protected function editNode($node, $errors = array())
 {
     $node = ARONode::finder()->byPK((int) $node);
     $this->tpl->assign('node', $node);
     $nodevalues = Node::load($node->id);
     $this->tpl->assign('values', !empty($_POST) ? (object) $_POST : $nodevalues);
     $this->tpl->assign('errors', $errors);
     $ct = $node->type;
     $ct->prepFields();
     $this->tpl->assign('ct', $ct);
     $this->tpl->display('content/node_form.tpl.php');
     //		print_r($node);
 }
 private static function updateXML($db)
 {
     $db->beginTransaction();
     $upd = $db->prepare("UPDATE `node` SET `xml` = ? WHERE `id` = ?");
     $sel = $db->exec("SELECT * FROM `node` WHERE `xml` IS NULL");
     while ($row = $sel->fetch(PDO::FETCH_ASSOC)) {
         $id = $row['id'];
         unset($row['id']);
         unset($row['xml']);
         $node = Node::load($id, $db);
         $upd->execute(array($node->getXML(), $id));
     }
     $db->commit();
 }
Exemple #16
0
 /**
  * Переключение в контекст произвольного пользователя.
  *
  * Используется для отладки проблем, специфичных для пользователей.
  * Пользователь, в чей контекст нужно переключиться, указывается
  * в GET-параметрах "uid" или "username", числовой идентификатор
  * или логин, соответственно.
  *
  * При выходе из системы будет возвращена ранее активная сессия.
  *
  * Это действие доступно только отладчикам.
  *
  * @param Context $ctx используется для доступа к GET/POST данным.
  * @return string адрес перенаправления пользователя.
  */
 public static function rpc_get_su(Context $ctx)
 {
     $user = Node::load(array('class' => 'user', 'deleted' => 0, 'id' => $ctx->get('id')), $ctx->db)->knock(ACL::CREATE);
     $curuid = $ctx->user->id;
     if ($user->id and $user->id != $curuid) {
         if (!is_array($stack = mcms::session('uidstack'))) {
             $stack = array();
         }
         $stack[] = $curuid;
         mcms::session('uidstack', $stack);
         self::login($user->id);
     }
     return $ctx->getRedirect();
 }
 protected static function rpc_get_remove(Context $ctx)
 {
     $name = $ctx->get('name');
     try {
         $node = Node::load(array('class' => 'subscription', 'name' => $name, 'deleted' => 0, 'published' => 1));
         if (empty($node) or $node->id != $ctx->get('id')) {
             throw new PageNotFoundException();
         }
         $ctx->db->beginTransaction();
         $node->delete();
         $ctx->db->commit();
     } catch (ObjectNotFoundException $e) {
     }
     return $ctx->getRedirect('?unsubscribed=' . urlencode($name));
 }
 /**
  * Возвращает разделы, в которые можно помещать документы запрошенного типа.
  * Для типов документов всегда возвращает все разделы.
  */
 public static function on_get_enabled(Context $ctx)
 {
     $node = Node::load($ctx->get('node'), $ctx->db);
     $filter = array('class' => 'tag', 'deleted' => 0);
     $options = array('multiple' => true);
     if ('type' != $node->class) {
         $type = Node::load(array('class' => 'type', 'name' => $node->class, 'deleted' => 0), $ctx->db);
         $filter['tagged'] = $type->id;
         if (!in_array($node->class, $ctx->config->getArray('modules/taxonomy/multitagtypes'))) {
             unset($options['multiple']);
         }
         $options['typeid'] = $type->id;
     }
     $filter['id'] = self::getPermittedSections($ctx);
     return new Response(html::em('nodes', $options, Node::findXML($filter, $ctx->db)), 'text/xml');
 }
Exemple #19
0
 /**
  * Перемещает файл в S3.
  */
 public static function on_move_to_s3(Context $ctx)
 {
     $node = Node::load($ctx->get('node'), $ctx->db);
     if (file_exists($fileName = $node->getRealURL())) {
         if ($url = self::moveFileToS3($fileName, null, $node->id . '/' . $node->filename)) {
             $ctx->db->beginTransaction();
             $node->remoteurl = $url;
             $node->save();
             $ctx->db->commit();
             unlink($fileName);
         }
     } else {
         Logger::log('file not found: ' . $fileName, 's3');
     }
     return $ctx->getRedirect();
 }
 /**
  * Клонирование объекта.
  * @route GET//api/node/clone.rpc
  */
 public static function on_clone(Context $ctx)
 {
     $node = Node::load($ctx->get('id'))->knock(ACL::CREATE);
     $ctx->db->beginTransaction();
     $node->published = false;
     $node->deleted = false;
     $node->created = null;
     $node->parent_id = $ctx->get('parent');
     // Копируем связи с другими объектами.
     $node->onSave("REPLACE INTO `node__rel` (`tid`, `nid`, `key`) " . "SELECT %ID%, `nid`, `key` FROM `node__rel` WHERE `tid` = ?", array($node->id));
     $node->onSave("REPLACE INTO `node__rel` (`tid`, `nid`, `key`) " . "SELECT `tid`, %ID%, `key` FROM `node__rel` WHERE `nid` = ?", array($node->id));
     $ctx->registry->broadcast('ru.molinos.cms.node.clone', array($node));
     $node->id = null;
     $node->save();
     $node->updateXML();
     $ctx->db->commit();
     $ctx->redirect("admin/node/{$node->id}?destination=" . urlencode($ctx->get('destination')));
 }
Exemple #21
0
 /**
  * Индексация документов, отсутствующих в индексе.
  */
 private static function reindexMissingNodes(Context $ctx, Node $type)
 {
     $schema = Schema::load($ctx->db, $type->name);
     foreach ($schema->getIndexes() as $fieldName) {
         $tableName = 'node__idx_' . $fieldName;
         try {
             $ids = $ctx->db->getResultsV("id", "SELECT `id` FROM `node` WHERE `class` = ? AND `deleted` = 0 AND `id` NOT IN (SELECT `id` FROM `{$tableName}`)", array($type->name));
             $upd = $ctx->db->prepare("INSERT INTO `{$tableName}` (`id`, `value`) VALUES (?, ?)");
             $count = 0;
             foreach ((array) $ids as $nid) {
                 $node = Node::load($nid, $ctx->db);
                 $upd->execute(array($nid, $schema[$fieldName]->getIndexValue($node->{$fieldName})));
             }
         } catch (TableNotFoundException $e) {
             Logger::log($e->getTableName() . ': missing table.');
         }
     }
 }
Exemple #22
0
 /**
  * Сохранение раздела.
  *
  * При сохранении раздела с пустым полем parent_id, в него подставляется код
  * существующего корневого раздела (если он существует).  Привязка к типам
  * документов копируется из родительского раздела.
  *
  * @return Node ссылка на себя (для построения цепочек).
  */
 public function save()
 {
     $copyACL = false;
     if ($this->isNew()) {
         if (!$this->parent_id) {
             try {
                 Node::load(array('class' => 'tag', 'parent_id' => null, 'deleted' => 0), $this->getDB());
                 throw new RuntimeException(t('Нельзя создать новый корневой раздел.'));
             } catch (ObjectNotFoundException $e) {
             }
         }
         // Копируем родительскую привязку к типам.
         $this->onSave("INSERT INTO `node__rel` (`tid`, `nid`, `key`, `order`) " . "SELECT %ID%, `nid`, `key`, `order` FROM `node__rel` " . "WHERE `tid` = ? AND `nid` IN (SELECT `id` FROM `node` WHERE `class` = 'type')", array($this->parent_id));
         $copyACL = true;
     }
     parent::save();
     if ($copyACL) {
         ACL::copyNode($this->parent_id, $this->id);
     }
 }
 /**
  * Восстановление пароля.
  * 
  * @param Context $ctx 
  * @param array $params 
  * @return void
  * @mcms_message ru.molinos.cms.auth.process.basicpw
  */
 public static function on_register(Context $ctx, array $params)
 {
     if (false === strpos($params['email'], '@')) {
         throw new BadRequestException(t('Неверно введён почтовый адрес.'));
     }
     $node = Node::load(array('class' => 'user', 'name' => $params['email']));
     if ($node->deleted) {
         throw new ForbiddenException(t('Этот пользователь был удалён.'));
     } elseif (!$node->published) {
         throw new ForbiddenException(t('Этот пользователь заблокирован.'));
     }
     $salt = md5($_SERVER['REMOTE_ADDR'] . microtime(true) . $node->name . rand());
     $node->otp = $salt;
     $ctx->db->beginTransaction();
     $node->save();
     $ctx->db->commit();
     $xml = html::em('request', array('email' => $node->name, 'host' => MCMS_HOST_NAME, 'base' => $ctx->url()->getBase($ctx), 'link' => 'authbasic/restore.rpc?email=' . urlencode($node->name) . '&otp=' . urlencode($salt)));
     $xsl = $ctx->config->get('modules/authbasic/restoretpl', os::path('lib', 'modules', 'authbasic', 'restore.xsl'));
     $html = xslt::transform($xml, $xsl, null);
     BebopMimeMail::send(null, $node->name, t('Восстановление пароля'), $html);
 }
Exemple #24
0
 private function notify($isnew)
 {
     if ($this->to and $this->to == Context::last()->user->id) {
         return;
     }
     $data = array('mode' => 'mail', 'node' => $this->getRaw());
     $data['node']['uid'] = Node::load(array('class' => 'user', 'id' => $this->uid))->getRaw();
     $message = bebop_render_object('mail', 'todo', null, $data, __CLASS__);
     if (!empty($message)) {
         if ($isnew) {
             if ($this->to) {
                 mcms::mail(null, $this->to, t('Новое напоминание'), $message);
             }
         } elseif (!$isnew) {
             if ($this->closed) {
                 mcms::mail(null, $this->uid, t('Напоминание удалено'), $message);
             } elseif ($this->to) {
                 mcms::mail(null, $this->to, t('Напоминание реактивировано'), $message);
             }
         }
     }
 }
Exemple #25
0
 public function save()
 {
     if (empty($this->id)) {
         try {
             $dst = Node::load(array('class' => 'user', 'id' => $this->re));
             if (!empty($dst->email)) {
                 $email = $dst->email;
             } elseif (false !== strstr($dst->name, '@')) {
                 $email = $dst->name;
             }
             if (!empty($email) and class_exists('BebopMimeMail')) {
                 BebopMimeMail::send(null, $email, $this->name, $this->text);
                 $this->data['sent'] = 1;
             }
             // Сохраняем в базе только если пользователь найден.
             // Чтобы можно было спокойно вызывать mcms::mail() для
             // любых объектов, не парясь с проверкой на class=user.
             return parent::save();
         } catch (ObjectNotFoundException $e) {
         }
     }
 }
 public function __construct(Context $ctx)
 {
     // Если кроме id аттачмента ничего не задали, ругаемся
     if (null == $ctx->get('fid', null) or null == $ctx->get('scale', null)) {
         $this->sendError(500, 'usage: ?q=imgtoolkit.rpc&fid=attachment[&operation=parameter...]');
     }
     foreach ($this->options as $k => $v) {
         if ($p = $ctx->get($k)) {
             if (in_array($k, array('noshow', 'merge', 'fid', 'mirrorH', 'mirrorV'))) {
                 $this->options[$k] = $p;
             } else {
                 $this->options[$k] = floatval($p);
             }
         }
         // Формируем имя файла-ссылки для кэша
         $outfile .= "{$this->options[$k]},";
     }
     $outfile = trim($outfile, ',');
     $node = Node::load(array('class' => 'file', 'id' => $this->options['fid']));
     if (empty($node)) {
         self::sendError(404, 'attachment not found.');
     }
     if (null === ($storage = mcms::config('filestorage'))) {
         $storage = 'storage';
     }
     $this->node = $node;
     $this->filename = $node->filename;
     $this->folder = $storage;
     $this->sourceDir = $storage;
     $this->source = $storage . '/' . $node->filepath;
     $this->output = $this->folder . '/' . $outfile;
     if (null != $this->options['merge']) {
         $this->mergeNode = Node::load(array('class' => 'file', 'id' => $this->options['merge']));
         if (empty($this->mergeNode)) {
             self::sendError(404, 'merge attachment not found.');
         }
     }
 }
Exemple #27
0
 public static function hookRemoteCall(Context $ctx)
 {
     switch ($ctx->get('action')) {
         case 'add':
             $ctx->user->checkAccess(ACL::CREATE, 'todo');
             $node = Node::create('todo', array('name' => $ctx->post('name'), 'uid' => $ctx->user->id, 'to' => $ctx->post('user', $ctx->user->id), 'published' => 1, 'rel' => $ctx->post('rel')));
             if (empty($node->name)) {
                 $msg = t('не указан текст задачи.');
                 bebop_on_json(array('status' => 'error', 'message' => $msg));
                 throw new InvalidArgumentException($msg);
             }
             $node->save();
             bebop_on_json(array('status' => 'created', 'id' => $node->id, 'html' => $node->render()));
             break;
         case 'toggle':
             try {
                 $node = Node::load(array('class' => 'todo', 'id' => $ctx->get('id')));
             } catch (ObjectNotFoundException $e) {
                 bebop_on_json(array('status' => 'error', 'message' => 'todo ' . $ctx->get('id') . ' not found'));
                 throw new PageNotFoundException();
             }
             if (empty($node->closed)) {
                 $node->closed = date('Y-m-d H:i:s', time() - date('Z', time()));
             } else {
                 $node->closed = null;
             }
             $node->save();
             if ($ctx->method('POST') and null !== ($comment = $ctx->post('comment'))) {
                 $tmp = Node::create('comment', array('uid' => $ctx->user->id, 'author' => $ctx->user->name, 'name' => t('Комментарий к напоминанию'), 'text' => $comment));
                 $tmp->save();
                 $tmp->linkAddParent($node->id);
             }
             $state = $node->closed ? 'closed' : 'open';
             bebop_on_json(array('status' => 'ok', 'state' => $state));
             break;
     }
 }
 private static function getRecipients(Context $ctx)
 {
     $config = $ctx->config->get('modules/moderator');
     $list = isset($config['super']) ? preg_split('/, */', $config['super']) : array();
     if (Context::last()->user->id) {
         try {
             $tmp = Node::load(array('class' => 'user', 'id' => Context::last()->user->id));
             if (!empty($tmp->publisher) and is_numeric($tmp->publisher)) {
                 $tmp = Node::load(array('class' => 'user', 'id' => $tmp->publisher));
                 if (!empty($tmp->email)) {
                     $list[] = $tmp->email;
                 }
             }
         } catch (ObjectNotFoundException $e) {
         }
     }
     // Добавляем в список адреса, указанные в свойствах домена.
     if ($ctx = Context::last()) {
         if (isset($ctx->moderatoremail)) {
             $list += preg_split('/, */', $ctx->moderatoremail);
         }
     }
     return array_unique($list);
 }
 public function set($value, &$node)
 {
     $this->validate($value);
     $fieldName = $this->value . '*';
     $node->onSave("DELETE FROM `node__rel` WHERE `nid` = %ID% AND `key` = ?", array($fieldName));
     if (empty($value)) {
         unset($node->{$this->value});
     } else {
         $result = array();
         $labels = preg_split('/,\\s*/', $value, -1, PREG_SPLIT_NO_EMPTY);
         foreach ($labels as $label) {
             try {
                 $label = trim($label);
                 $tmp = Node::load($f = array('class' => 'label', 'name' => $label, 'deleted' => 0), $node->getDB());
             } catch (ObjectNotFoundException $e) {
                 $tmp = Node::create(array('class' => 'label', 'name' => $label, 'published' => 1), $node->getDB())->save();
             }
             $result[$tmp->id] = $tmp->name;
         }
         $params = array($fieldName);
         $node->onSave($sql = "INSERT INTO `node__rel` (`nid`, `tid`, `key`) SELECT %ID%, `id`, ? FROM `node` WHERE `class` = 'label' AND `id` " . sql::in(array_keys($result), $params), $params);
         $node->{$this->value} = $result;
     }
 }
Exemple #30
0
 /**
  * Диспетчер запросов.
  *
  * В зависимости от GET-параметра mode вызывает один из методов: onGetList()
  * или больше никакой.  Гасит ошибки NoIndexException, возвращая вместо них
  * массив с ключём "error", значение которого содержит описание ошибки.
  *
  * @param array $options то, что насобирал getRequestOptions().
  *
  * @return mixed то, что вернул конкретный метод-обработчик.
  */
 public function onGet(array $options)
 {
     $count = null;
     $result = html::wrap('nodes', Node::findXML($query = $this->getQuery($options), $this->ctx->db));
     // Пусто: откатываемся на другой раздел, но только если в текущем разделе
     // вообще ничего нет, на несуществующей странице выводим пустой список.
     if (empty($result)) {
         $count = $query->getCount($this->ctx->db);
         if (!$count and 'empty' == $this->fallbackmode and $this->fixed) {
             $options['section']['id'] = $this->fixed;
             $result = html::wrap('nodes', Node::findXML($query = $this->getQuery($options), $this->ctx->db));
             $count = null;
         }
     }
     if (!empty($result)) {
         // Добавляем информацию о разделе.
         if ($this->showpath and !empty($options['section'])) {
             $tmp = '';
             $section = Node::load($options['section'], $this->ctx->db);
             foreach ($section->getParents() as $node) {
                 $tmp .= $node->push('section');
             }
             if (!empty($tmp)) {
                 $result .= html::em('path', $tmp);
             }
         }
         if ($this->pager and !empty($options['limit'])) {
             if (null === $count) {
                 $count = $query->getCount($this->ctx->db);
             }
             $result .= $this->getPager($count, $options['page'], $options['limit']);
         }
     }
     return $result;
 }