Наверх

Разрабатываем социальную сеть на MODx Revolution


MODx развивается стремительными темпами, и я решил попробовать сделать социальную сеть на этом замечательном движке. Ведь в нем давно уже есть возможность работать с пользователями (регистрация, авторизация и пр.), встроенный механизм сообщений пользователей, он умеет работать с изображениями и много чего еще.

Для начала давайте разберемся с пользователями, дадим им возможность писать статьи, например, или добавлять свои события.

Регистрация пользователей


Для регистрации мы будем использовать сниппет Login.
[[!Register? &postHooks=`addUser` &usergroups=`Users` &submittedResourceId=`9`
 &activationResourceId=`11` &activationEmailSubject=`Подтвердите регистрацию
 на сайте` &validate=`email:email:required`]]
О самом сниппете написано уже много, покажу, что делает наш хук addUser:

Сниппет addUser

<?php
$output = "";
$parent = 2;
$template = 3;

// Создаем ресурс для пользователя (его личная страничка)

if ($id = $modx->runSnippet('addResource', array(
	  'pagetitle' => $hook->getValue('username'),
	  'parent' => $parent,
	  'template' => $template,
	  'isfolder' => 1,
	  'published' => 1,
  	  'hidemenu' => 1
	))) {

// Записываем id странички пользователя в поле website
// (хотя можно было использовать и User Extended)
	
  $userId = $hook->getValue('register.user')->get('id');
  $user = $modx->getObject('modUserProfile', array('id' => $userId));
  $user->set('website',$id);
  $user->save();

// А в для самого ресурса создаем TV-параметр, где указываем id пользователя
  
  $modx->runSnippet('tv', array('id' => $id, 'tv' => 1, 'value' => $userId));  

  $modx->cacheManager->refresh();

  $output = $id;

} else {
  
  print '<h1>Can not to create the new user</h1>
         <p>Please, tell us about this</p>
         <h2>Contacts</h2>
         <p>E-mail: <a href="mailto:admin@site.ru">admin@site.ru</a></p>';
  die();

}

return $output;

Сниппет addResource

<?php
// Сниппет будет получать данные из формы методом POST
if (!$pagetitle)   $pagetitle   =  $_POST['title'];
if (!$longtitle)   $longtitle   =  $_POST['longtitle'];
if (!$content)     $content     =  $_POST['content'];
if (!$introtext)   $introtext   =  $_POST['introtext'];
if (!$description) $description =  $_POST['description'];
if (!$parent)      $parent      =  $_POST['parent'];
if (!$isfolder)    $isfolder    =  $_POST['isfolder'];
if (!$hidemenu)    $hidemenu    =  $_POST['hidemenu'];
if (!$template)    $template    =  $_POST['template'];
if (!$menutitle)   $menutitle   =  $_POST['menutitle'];
if (!$published)   $published   =  $_POST['published'];
if (!$publishedon) $publishedon =  date('Y-m-d H:i:s');

// Если некоторые значения не будут указаны,
// они будут установлены по умолчанию
if (!$parent)      $parent = 1;
if (!$template)    $template = 1;

// Устанавливаем префикс для псевдонима
switch ($template) {
  case 1: $prefix = "art"; break;		// Статья
  case 2: $prefix = "id"; break;		// Пользователь
  case 3: $prefix = "id"; break;		// Пользователь
  case 4: $prefix = "event"; break;		// Событие
  case 5: $prefix = "animal"; break;       // Домашнее животное
  default: $prefix = "id"; break;
}

// Создаем ресурс
$newResource = $modx->newObject('modResource');

// Заполняем нужные значения
$newResource->set('pagetitle',$pagetitle);
$newResource->set('longtitle',$longtitle);
$newResource->set('description',$description);
$newResource->set('introtext',$introtext);
$newResource->set('content',$content);
$newResource->set('menutitle',$menutitle);
$newResource->set('template',$template);
$newResource->set('isfolder',$isfolder);
$newResource->set('hidemenu',$hidemenu);
$newResource->set('parent',$parent);
$newResource->set('published',$published);
$newResource->set('alias',$parent.date('YmdHis'));
if ($published) $newResource->set('publishedon',$publishedon);


// Сохраняем ресурс
if ($newResource->save()) {
  $id = $newResource->get('id');
  $newResource->set('alias',$prefix.$id);
  $newResource->save();
// Очищаем кеш, чтобы изменения были видны сразу
  $modx->cacheManager->refresh();
  return $id;
} 

return false;

Сниппет tv

<?php
if ($input) {
  // Либо выводим значение TV по id документа
  $q = $modx->newQuery('modTemplateVarResource');
  $q->select(array('value',
		   'tmplvarid',
		   'contentid'))->where(array('tmplvarid'=>$options,
					      'contentid'=>$input));	
  $r = $modx->getObject('modTemplateVarResource', $q);
  
  return $r->value;
  
} else {
  // либо устанавливаем значение TV
  if (!$id) {$id = $_POST['id'];}
  if (!$tv) $tv = $_POST['tv'];
  if (!$value) $value = $_POST['value'];
  if ($value == ' ') $value = '';
  
  if ($modx->getObject('modTemplateVarResource', array(
                                                 'contentid' => $id
                                               , 'tmplvarid' => $tv))) {
    $tvar = $modx->getObject('modTemplateVarResource', array(
                                                 'contentid' => $id
                                               , 'tmplvarid' => $tv));
    } else {
    $tvar = $modx->newObject('modTemplateVarResource');
    $tvar->set('contentid', $id);
    $tvar->set('tmplvarid', $tv);
  }
  
  $tvar->set('value', $value);
  
  $tvar->save();
  
}
После того, как пользователь подтвердил свой e-mail, направляем его на страничку редактирования информации о себе:
[[!FormIt? &hooks=`editUserPage` &successMessage=`Изменения сохранены`]]
[[$editPage]]
Соответственно, сниппет editUserPage

Сниппет editUserPage

<?php
// Берем id ресурса из профиля пользователя
$id = $modx->user->getOne('Profile')->get('website');
$name = $_POST['name'];
if ($name == '') $name = ' ';

// И вносим изменения на страницу
if ($modx->runSnippet('editResource',array('resId' => $id
                                         , 'pagetitle' => $name
                                         , 'longtitle' => $name
                                         , 'menutitle' => $name
                                         , 'hidemenu' => 'show'))) {
foreach ($_POST as $key => $value) {
  switch ($key) {
    case 'com_address':  $tv = 2; break;
    case 'com_egrul': 	 $tv = 5; break;
    case 'com_email':	 $tv = 9; break;
    case 'com_federate': $tv = 4; break;
    case 'com_head':	 $tv = 10; break;
    case 'com_inn':	 $tv = 6; break;
    case 'com_kpp':	 $tv = 7; break;
    case 'com_phone':	 $tv = 3; break;
    case 'com_regon':	 $tv = 8; break;
    default: 		 $tv = 0; break;
  }
  if (!$value) $value = ' ';
  if ($tv) $modx->runSnippet('tv', array('id' => $id, 'tv' => $tv,
                                          'value' => $value));
}
// Очищаем кеш, чтобы изменения были видны сразу
$modx->cacheManager->refresh();
return true;
}

Создаем статьи или события пользователя


Пусть у нас пользователи могут добавлять на свою страничку предстоящие и прошедшие события:
[[!FormIt? &hooks=`addEvent` &successMessage=`Изменения сохранены`
  &submitVar=`addEvent`]]
[[$addEventForm]]

Сниппет addEvent

<?php
// События будут дочерними ресурсами страницы пользователя
$parent = $modx->user->getOne('Profile')->get('website');
$name = $_POST['name'];
$date = explode('.',$_POST['event_date']);
$publishedon = $date[2]."-".$date[1]."-".$date[0]." 10:00:00";
$introtext = $_POST['description'];
if ($id = $modx->runSnippet('addResource',array('pagetitle' => $name
                                              , 'longtitle' => $name
                                              , 'introtext' => $introtext
                                              , 'menutitle' => $name
                                              , 'published' => 1
                                              , 'publishedon' => $publishedon
                                              , 'parent' => $parent
                                              , 'template' => 4
                                              , 'isfolder' => 1))) {

// Заполняем любые параметры события, которые нам нужны
foreach ($_POST as $key => $value) {
  switch ($key) {
    case 'event_address': 		$tv = 14; break;
    case 'event_type':			$tv = 12; break;
    case 'event_org':			$tv = 34; break;
    case 'event_peoples':		$tv = 24; break;
    default: 		  			$tv = 0; break;
  }
  if (!$value) $value = ' ';
  if ($tv) $modx->runSnippet('tv', array('id' => $id
                                       , 'tv' => $tv
                                       , 'value' => $value));
}

$modx->cacheManager->refresh();

// Переадресовываем на просмотр события
$url = "/companies/id".$parent."/event".$id;
header('location: '.$url); exit;
return true;
}

В итоге


На нашем сайте пользователи могут зарегистрироваться, разместить информацию о себе, создавать события или писать статьи.

Что я планирую с этим делать


Дальше я планирую сделать для пользователей возможность загрузки фотографий, добавить функционал для отправки и чтения личных сообщений, как писал об этом Goobs, а так же возможность пользователей регистрироваться на понравившиеся события.

Оригинал статьи habrahabr.ru/post/148876/


35 комментариев

  1. Михаил 19 апреля 2013, 20:26(Комментарий был изменён) # 0
    Вот то что я искал! огромное спасибо! Буду реализовать. Хотя только изучаю php. Кстати по php не будет уроков?
    1. Илья Уткин 20 апреля 2013, 15:32(Комментарий был изменён) # 0
      А что конкретно по php вас интересует? По-моему, по php достаточно информации и в свободном доступе и в виде книг.
      1. Михаил 20 апреля 2013, 17:41(Комментарий был изменён) # 0
        ДА много. Вот учу. Хочу научиться разрабатывать динамические сайты.
    2. Сергей Лелеко 22 сентября 2013, 20:16(Комментарий был изменён) # 0
      Проект получил дальнейшее развитие?
      1. Илья Уткин 23 сентября 2013, 09:53(Комментарий был изменён) # 0
        К сожалению, нет, финансирование кончилось и проект пока так и застыл на начальной стадии…
      2. Сергей Новиков 01 декабря 2013, 16:33(Комментарий был изменён) # 0
        Илья, отличный мануал. Только нет информации по снипету editResource, который используется в editUserPage.

        я попробовал снипет совместно с UpdateProfile из комплекта Login, но так что-то ничего не получилось. Подскажи где рыть…
        1. Илья Уткин 01 декабря 2013, 16:42(Комментарий был изменён) # 0
          По идее его надо написать самому, изучив xPDO на основе сниппета addResource.

          Но, чтобы не возиться, вот его код, так уж и быть))
          <?php
          // Сниппет будет получать данные из формы методом POST
          if (!$pagetitle)   $pagetitle   =  $_POST['pagetitle'];
          if (!$resId)       $resId	=  $_POST['resId'];
          if (!$longtitle)   $longtitle   =  $_POST['longtitle'];
          if (!$menutitle)   $menutitle   =  $_POST['menutitle'];
          if (!$hidemenu)    $hidemenu    =  $_POST['hidemenu'];
          if ($hidemenu == 'show') $hidemenu = 0;
          if (!$content)     $content     =  $_POST['content'];
          if (!$introtext)   $introtext   =  $_POST['introtext'];
          if (!$description) $description =  $_POST['description'];
          if (!$template)    $template    =  $_POST['template'];
          if (!$published)   $published   =  $_POST['published'];
          		   $publishedon =  date('Y-m-d H:i:s');
          
          
          
          // Получаем ресурс по id ресурса
          $resource = $modx->getObject('modResource',array('id'=>$resId));
          
          // Устанавливаем нужные значения
          if ($pagetitle)   $resource->set('pagetitle',$pagetitle);
          if ($longtitle)   $resource->set('longtitle',$longtitle);
          if ($menutitle)   $resource->set('menutitle',$menutitle);
          if ($pagetitle == ' ') $resource->set('pagetitle', '');
          if ($longtitle == ' ') $resource->set('longtitle', '');
          if ($menutitle == ' ') $resource->set('menutitle', '');
          if ($description) $resource->set('description',$description);
          if ($introtext)   $resource->set('introtext',$introtext);
          if ($content)     $resource->set('content',$content);
                            $resource->set('hidemenu',$hidemenu);
          if ($template)    $resource->set('template',$template);
                            $resource->set('published',$published);
          if ($published)   $resource->set('publishedon',$publishedon);
          
          // Сохраняем ресурс
          if ($resource->save()) {
          
          // Очищаем кеш, чтобы изменения были видны сразу
            $modx->cacheManager->clearCache();
            return true;
          } 
          
          return false;
          1. Сергей Новиков 01 декабря 2013, 17:13(Комментарий был изменён) # 0
            Отлично. Спасибо. я так понимаю, что этот снипет можно также применить совместно с UpdateProfile чтобы обновить пользовательские данные.
        2. Emily Hunt 06 февраля 2015, 14:27 # 0
          Здравствуйте.
          Поделитесь пожалуйсте чанками которые использовали при реализации. Вот эта форма добавления интересует [[$addEventForm]]
          1. Илья Уткин 06 февраля 2015, 14:41 # 0
            Код чанка давно утерян, но вот такой код будет работать:
            <form action="[[*uri]]" method="post">
            	<input name="name" type="text">
            	<input name="event_date" type="text">
            	<textarea name="description"></textarea>
            	<input name="event_address" type="text">
            	<input name="event_type" type="text">
            	<input name="event_org" type="text">
            	<input name="event_peoples" type="text">
            </form>
            Оформление уже на ваше усмотрение
            1. Emily Hunt 06 февраля 2015, 14:56(Комментарий был изменён) # 0
              Да вот не получается что то. После создания события просто перекидывает на ту же страницу Добавления события.
              И конечно же ничего не добавляется. В контейнере пользователя ничего нет.

              Эти тв обязательно должны быть?
              case 'event_address': $tv = 14; break;
              case 'event_type': $tv = 12; break;
              case 'event_org': $tv = 34; break;
              case 'event_peoples': $tv = 24; break;
              1. Илья Уткин 06 февраля 2015, 15:11 # 0
                Нет, конечно — это все для примера
                1. Emily Hunt 06 февраля 2015, 15:21 # 0
                  Ничего не происходит.
                  Вызываю все так как у вас на страницу добавления события, заполняю поля и просто перезагружается страница.
                  1. Emily Hunt 06 февраля 2015, 15:25 # 0
                    [[!FormIt? &hooks=`addEvent` &successMessage=`Изменения сохранены`
                      &submitVar=`addEvent`]]
                    
                    <form action="[[*uri]]" method="post">
                    	<input type="text" name="title" id="title" /><br />
                    <textarea id="content" name="content"></textarea><br />
                    	<input type="submit" value="Отправить!" />
                    </form>
                    Вот так вызываю на странице добавления. Можете помочь?
                    1. Emily Hunt 06 февраля 2015, 15:28 # 0
                      Если убрать &submitVar=`addEvent` то документ создается.
                      НЕ подскажете еще как сделать что бы для пользователя создавался контейнер Articles а в нем уже событияи статьи.
                      1. Vitaliy 10 февраля 2015, 11:39(Комментарий был изменён) # 0
                        для того что бы &submitVar=`addEvent` работал, нужно в самой форме в submit, указать
                        name="addEvent".
            2. Emily Hunt 06 февраля 2015, 14:29 # 0
              И еще вопрос не подскажете как показать количество событий у пользователя?
              1. Илья Уткин 06 февраля 2015, 14:43 # 0
                return $modx->getCount('modResource',
                    array(
                        'parent' => $modx->user->getOne('Profile')->get('website')
                    )
                );
              2. Артём 19 февраля 2015, 19:32 # 0
                Илья, здравствуйте! При такой регистрации большого количества пользователей, допустим 5к, насколько адекватно будет работать админка? А если у каждого пользователя будет еще по несколько дочерних ресурсов?
                1. Илья Уткин 20 февраля 2015, 09:30 # 0
                  Я думаю, дерево сильно тормозить будет. Надо поставить Collections и сделать корневой ресурс коллекцией.
                2. juvern 23 июня 2015, 12:57 # 0
                  Здравствуйте.
                  Подскажите как быть уже с существующими пользователями? К примеру у меня уже есть пользователи на сайте, если сделаю по вашей инструкции то как для каждого пользователя, который уже зарегистрирован был, создастся страница?
                  1. Илья Уткин 23 июня 2015, 13:33 # 0
                    Да, это проблемка… Думаю, лучше не создавать для каждого пользователя свою страницу, а воспользоваться UserProfile2 для вывода информации о пользователе…
                  2. krok 28 марта 2016, 12:24 # 0
                    Здравствуйте! Илья, такой вопрос. После регистрации и выполнении сниппета addUser не происходит перехода по &submittedResourceId=`9`, появляется белый фон и id ресурс остается то же. Как можно это исправить?
                    1. Илья Уткин 28 марта 2016, 12:26 # 0
                      Ну, можно внутри сниппета addUser прописать
                      $url = $modx->makeUrl(9);
                      $modx->sendRedirect($url);
                    2. krok 28 марта 2016, 12:47 # 0
                      Да, получилось. Спасибо большое!
                      1. krok 01 апреля 2016, 13:41 # 0
                        А как после внесения изменений и выполнения сниппета editUserPage переадресовать пользователя на его личную страничку?
                        1. Илья Уткин 03 апреля 2016, 13:22 # 0
                          Вот так реализуется редирект в MODX
                          $url = $modx->makeUrl(9);
                          $modx->sendRedirect($url);
                          1. krok 06 апреля 2016, 11:12 # 0
                            Да, это Вы уже показали, это понятно и это получается.
                            Но пробую переадресовать пользователя именно на его личную страницу (ресурс созданный при регистрации), и показывается просто пустая страница с id страницы настроек.

                            Пробую так:
                            $id = $modx->user->getOne('Profile')->get('website');
                            $url = $modx->makeUrl($id);
                            $modx->sendRedirect($url);
                            И так:
                            $id = $modx->user->getOne('Profile')->get('website');
                            $modx->sendRedirect($id);
                            Результат один(
                            1. Илья Уткин 06 апреля 2016, 11:40 # 0
                              Возможно, нужно очистить кеш перед makeUrl — ресурс только-только создан, и его URL получить пока не возможно.
                              $id = $modx->user->getOne('Profile')->get('website');
                              $modx->cacheManager->refresh();
                              $url = $modx->makeUrl($id);
                              $modx->sendRedirect($url);
                              1. krok 06 апреля 2016, 15:27 # 0
                                Спасибо огромное, Илья! Ошибка была в сниппете addUser, сейчас все получилось.
                        2. Kate Hadson 03 апреля 2016, 11:31 # 0
                          Здравствуйте, Илья! Делаю все по инструкции, не получается создание tv параметра. Я так понимаю, именно с помощью него будет выводиться информация о пользователе?
                          В логах только это:
                          [2016-04-03 14:26:06] (ERROR @ /index.php) modResource: Attempt to set NOT NULL field longtitle to NULL
                          [2016-04-03 14:26:06] (ERROR @ /index.php) modResource: Attempt to set NOT NULL field description to NULL
                          [2016-04-03 14:26:06] (ERROR @ /index.php) modResource: Attempt to set NOT NULL field menutitle to NULL
                          1. Илья Уткин 03 апреля 2016, 13:25 # 0
                            Для создания ТВ можно использовать следующий код:
                            $resource->setTVValue('img', $img);
                          2. Sergiy Yakimenko 08 января 2017, 14:44 # 0
                            Огромное спасибо, Илья, за Вашу помощь.
                            Я не обращался еще к Вам за советом, но, читая комментарии, я вижу, насколько Вы добры и отзывчивы к людям, даже, порой, к не совсем адекватным.
                            Ваш сайт очень помогает в работе. Пусть Господь даст Вам сил и возможности продолжать развитие этого сайта и благословит достойными дарами за Ваш труд.
                            Очень хотелось бы, чтобы Вы продолжили этот проект. Буду надеяться, что когда-нибудь у вас появятся на это время и желание.
                            Всех Вам благ.
                            1. Илья Уткин 09 января 2017, 10:00 # 0
                              Спасибо большое за тёплые слова)
                            2. polniy noob 26 июля 2018, 01:44 # 0
                              Спасибо за статью. Было бы здорово если бы вы выложили
                              возможность загрузки фотографий пользователя
                              отправка и чтение личных сообщений от пользователя к польщователю.
                              Сечас пробую на package PersonalMessage только как пользователь к пользователю может писать неразобрался

                              Авторизация

                              через сервис Loginza:


                              Шаблоны MODX

                              1 2 Дальше »

                              Объектная
                              модель
                              MODX