Одностраничники на базе MODx без контекстов

Доброго времени суток!
Стояла задача реализовать создание одностраничных сайтов с минимальными затратами по времени и ресурсам.
Моя реализация основана принципе создания одностраничного сайта в рамках стандартного ресурса MODx и подмены шаблона и содержимого главной страницы в зависимости от доменного имени сайта, по которому пользователь перешел.
Итак, суть решения:
  1. К каждому ресурсу, который представляет собой отдельный одностраничный сайт присваивается tv поле с доменным именем
  2. на событие OnLoadWebDocument вешается плагин, который получает текущий домен и находит ресурс,
    привязанный к данному домену, получает и применяет шаблон данного ресурса к главной странице, создает плейсхолдер [[+resid]], в котором хранится id нужного нам ресурса
  3. Выводится нужный нам контент в соответствии с плейсхолдером [[+resid]] в нужном нам шаблоне
Собственно сам плагин:
<?php
$id = $modx->resource->get('id');

if($modx->event->name == 'OnLoadWebDocument' ){
    $domain = $_SERVER['HTTP_HOST'];
    $q = $modx->newQuery('modTemplateVarResource', array('tmplvarid'=>1,'value'=>$domain));// 'tmplvarid'=>1 это id тв поля с доменом
    $q->select('contentid');
    $RESID = $modx->getValue($q->prepare());// получаем id ресурса соответствующего домену
    
    if($RESID){
        $modx->setPlaceholder('resid', $RESID);
        if(!in_array($id,array(3,4))){//отсекаем страницы роботса и сайтмап
            $res = $modx->getObject('modResource',$RESID);// 
            $template = $res->get('template');// сохраним id нужного ресурса для вызова в шаблонах
            $modx->resource->set('template', $template);//задаем шаблон вывода
            $modx->resource->save();
            $cm = $modx->getCacheManager();
            $cm->refresh();
        }
    }
}
Конечно можно просто создать для каждого сайта свой шаблон и не заморачиваться, но это не то, что нам нужно, поэтому весь контент в шаблонах вызывается через fastField: [[#[[+resid]].pagetitle]]

Если кому-то будет полезно — буду рад.
Поправил по замечаниям, спасибо что указали на ошибки
Арсений
06 октября 2017, 08:24
modx.pro
9
3 725
+5

Комментарии: 16

Евгений Шеронов
08 октября 2017, 18:08
+2
Вот такие конструкции:
$data = "SELECT contentid FROM base_site_tmplvar_contentvalues WHERE tmplvarid = 1 AND value = '$domain'";
Лучше писать более универсально:
$q = $modx->newQuery('modTemplateVarResource');
$q->where(array('tmplavarid'=>1,'value'=>$domain));
$q->select('contentid');
$q->limit(1); // один же ресурс ищем
if($q->prepare() && $q->stmt->execute()) {
   if($RESID = $q->stmt->fetch(PDO::FETCH_COLUMN)) { // - один столбец для одной стройки
       // весь остальной код 
    }
}
    Сергей Шлоков
    09 октября 2017, 07:17
    1
    +2
    Получить одно поле —
    $q = $modx->newQuery('modTemplateVarResource', array('tmplavarid'=>1,'value'=>$domain));
    $q->select('contentid');
    $RESID = $modx->getValue($q->prepare());
Alexander V
09 октября 2017, 04:15
0
Довелось недавно делать одностраничник на Modx. В итоге получилось:
10+ ресурсов
10+ TV
20+ чанков
    Сергей Шлоков
    09 октября 2017, 07:15
    +2
    "SELECT contentid FROM base_site_tmplvar_contentvalues WHERE tmplvarid = 1 AND value = '$domain'";
    Жесть. Кому нужен дырявый сайт, налетай.

    Стыдно должно быть, молодой человек!
      Арсений
      09 октября 2017, 11:26
      0
      а как в данном случае может проявиться уязвимость? этот скрипт запускается в плагине и, по сути из параметров принимает только домен. Как можно на этой дыре что-то сделать?
      Спасибо за критику!
        Василий Наумкин
        09 октября 2017, 13:54
        +3
        Домен у тебя получается из $_SERVER['HTTP_HOST'], который при не очень хорошо настроенном сервере будет выдавать то, что прислал юзер.

        А прислать он может что угодно, включая длиннющую строку со слепой SQL инъекцией.
          Арсений
          09 октября 2017, 17:19
          0
          Но здесь же по сути переменная получает данные типа site.ru, то есть все остальные параметры просто не принимаются типа get параметров и прочего, или я не прав?
            Василий Наумкин
            09 октября 2017, 17:26
            +1
            Ты не прав. HTTP_HOST присылает юзер в запросе.

            Если у сервера нет определённых настроек (которых по умолчанию и нет), тебе могут вместо site.ru прислать что угодно, включая SQL инъекцию.
              Арсений
              09 октября 2017, 17:39
              0
              Спасибо! дополнительно ознакомлюсь с темой!
          Сергей Шлоков
          09 октября 2017, 15:47
          +2
          Спасибо за критику!
          Ну если такое отношение к критике, то возьму на себя смелость разобрать код.
          1. Теперь на один просмотр страницы будет 2 лишних запроса к БД.
          2. Вот это
          $modx->resource->save();
          зачем? Кроме того, это ещё один запрос к БД.
          3. Вы понимаете, что после каждого просмотра вы убиваете весь кэш сайта?
          4. И наконец, эта странная фраза собака друг человека
          весь контент в шаблонах вызывается через fastField: [[#[[+resid]].pagetitle]]
          Это как интересно?

          Почему нельзя просто сделать форвард на найденный ресурс?

          Вообще, эта задача легко решается через контексты. И поддержка такого решения гораздо проще, ведь всё понятно. А вот для вашего решения нужна инструкция, ибо следующий программист вряд ли сходу поймёт ваше творчество.
            Арсений
            09 октября 2017, 17:15
            0
            2. $modx->resource->save(); без этого зачастую не срабатывала привязка шаблона, хз почему но с этим была беда
            3. Да, согласен, это лишнее
            4. А каким образом делается форвард на ресурс, при условии что url измениться не должен?

            Про контексты — когда стоит задача сделать систему такую, чтоб обычный юзверь, без дополнительных регистраций контекстов, мог зарегистрировать, наполнить и запустить еще пару тройку одностраничников, по готовым шаблонам — мне кажется так проще. Человеку просто нужно зайти и заполнить ресурс как обычно + добавить url в поле — больше ничего делать не нужно (ну кроме регистрации домена, но это уже не касается системы)
              Алексей
              09 октября 2017, 17:41
              0
              modx.pro/development/2157-method-sendforward-and-save-the-fields-of-the-resource/
              А вот контент поменять врятли удастся:
              github.com/modxcms/revolution/pull/13163
              Вообще это хороший вопрос про sendforward
                Василий Наумкин
                10 октября 2017, 12:39
                6
                +5
                Если покопаться в MODX API то можно научиться выводить любой ресурс в плагине на нужном событии:
                $modx->resource = $modx->getObject('modResource', $modx->getOption('site_start'));
                $modx->resource->set('content', $pdoTools->runSnippet('@FILE snippets/get_panel.php'));
                $modx->request->prepareResponse();
                Здесь, как видно, еще и замена контента на свой идёт, на лету.

                Можно так на лету и виртуальные ресурсы делать, со своими pagetitle и прочими свойствами. При желании, можно вообще весь сайт без ресурсов сделать =)
                  Арсений
                  10 октября 2017, 15:23
                  0
                  Хорошая штука:) Василий, а что скажете на счет такой реализации? Работать то она работает, но не является ли это каким-то велосипедом? Как-то привык доверять вашему мнению)
                    Василий Наумкин
                    10 октября 2017, 15:29
                    1
                    +1
                    Ну а что здесь велосипедного?

                    MODX делает примерно тоже самое при загрузке страницы, просто дольше и с большими условиями.
          Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
          16