On March 26, 2019 we launched new MODX Forums. Please join us at the new MODX Community Forums.
Subscribe: RSS
  • В MODx API отсутствуют функции для создания/редактирования документов, а это очень, имхо, необходимо. Есть модуль DocAPI, на мой взгляд абсолютно бесполезный, к тому же частично дублирующий код MODx. Для моей задачи оказалось вполне достаточно следующего кода:
    <?
    /***************************************************************
      Класс для Создания/Редактирования/Удаления документов MODx
      Версия 0.5.1a
      Автор: ur001
      Контакты: ur001@mail.ru
      Использование:
      Пример 1 (создание):
    	require_once('assets/libs/docapi/document.class.inc.php');
    	$doc = new Document();
    	$doc->Set('parent',$folder);
    	$doc->Set('alias','post'.time());
    	$doc->Set('content','Текст документа');
    	$doc->Set('template','GuestBookComments');
    	$doc->Set('tvComment','Комментарий к посту');
    	$doc->Save();
    
      Пример 2 (редактирование):
    	require_once('assets/libs/docapi/document.class.inc.php');
    	$doc = new Document($id,'content');
    	$content=$doc->Get('content');
    	$doc->Set('content', '<p>'.$content.'</p>');
    	$doc->Save();
    
      Область применения:
    	Написание гостевых книг, блогов, форумов, модулей для
    	администрирования из frontedn-а (новоси, галлереи)
    	
      TODO:
    	* Необходимо тестирование
    	* document_groups
    
      Важно:
    	1) Это не врапер для MODx API. Это дополнение функционала
    	   для создания и редактирования документов
    	2) Не следует создавать этот класс только для получения 
    	   значений TV или удаления документов в цикле. Для этого 
    	   есть соответствующие функции, такие как 
    	   $modx->getTemplateVars(); и $modx->db->delete();
    
    ***************************************************************/
    class Document{
    	var $fields;	// Массив полей документа
    	var $tvs;		// Массив TV
    	
    	var $tvNames;	// Массив возможных имен TV
    	var $oldTVs;	// Массив уже определенных в документе значений TV
    	var $isNew;		// true - новый документ, false - существующий
    
    	/***********************************************
    	  Инициализация класса
    	  $id   - идентификатор существующего документа 
    	          или 0 для создание нового
    	  $fields - список полей разделенных запятой
    	************************************************/	
    	function Document($id=0,$fields="*"){
    		global $modx;
    		$this->isNew = $id==0;
    		if(!$this->isNew){
    			$this->fields = $modx->getPageInfo($id,0,$fields);
    			$this->fields['id']=$id;
    		}
    		else
    			$this->fields = array(
    				'pagetitle'	=> 'Новый документ',
    				'alias'		=> '',
    				'parent'	=> 0, 
    				'createdon' => time(),
    				'createdby' => '0',
    				'editedon' 	=> '0',
    				'editedby' 	=> '0',
    				'published' => '1',
    				'deleted' 	=> '0',
    				'hidemenu' 	=> '1',
    				'template' 	=> '0',
    				'content' 	=> ''
    			);	
    	}
    	
    	/***********************************************
    	  Сохранение/Обновление документа
    	************************************************/	
    	function Save(){
    		global $modx;
    		$tablename=$modx->getFullTableName('site_content');
    		if($this->isNew){
    			$this->fields['id']=$modx->db->insert(&$this->fields, $tablename);
    			$this->isNew = false;
    		} else {
    			$id=$this->fields['id'];
    			$modx->db->update(&$this->fields, $tablename, "id=$id");
    		}
    		if(is_array($this->tvs)) $this->saveTVs();
    	}
    	
    
    	/***********************************************
    	  Получение значения поля документа или TV
    	  $field - Имя поля документа или имя TV 
    	           с префиксом 'tv'
    	  Результат: значение поля, TV или null
    	************************************************/	
    	function Get($field){ 
    		switch(1){
    			case substr($field,0,2)=='tv': return $this->GetTV(substr($field,2));
    			default: return isset($this->fields[$field]) ? $this->fields[$field] : null; 
    		}
    	}
    	
    	/***********************************************
    	  Установка значения поля документа (включая TV)
    	  $field - Имя поля документа. Для установки TV 
    	           следует добавить префикс 'tv'
    	  $value - Значение
    	  Результат: true, или false при неудаче
    	************************************************/	
    	function Set($field, $value){
    		switch(1){
    			case substr($field,0,2)=='tv':		return $this->SetTV(substr($field,2), $value);
    			case $field=='template':		return $this->SetTemplate($value);
    			default: $this->fields[$field]=$value;	return true;
    		}
    	}
    	
    	
    	/***********************************************
    	  Получение значения TV. 
    	  $name - имя TV
    	************************************************/
    	function GetTV($tv){
    		if(!is_array($this->tvs)){
    			if($this->isNew) return null; 
    			$this->tvs=array();
    		}
    		// Поиск в значениях установленных функцией Set()
    		if(isset($this->tvs[$tv])) return $this->tvs[$tv];
    		// Поиск в TV уже определенных для документа
    		// Если они еще не получены вызываем fillOldTVValues()
    		if(!is_array($this->oldTVs)){
    			if($this->isNew) return null; 
    			$this->fillOldTVValues();
    		}
    		if(isset($this->oldTVs[$tv])) return $this->oldTVs[$tv];
    		return null;
    	}
    	
    	/***********************************************
    	  Установка TV
    	************************************************/
    	function SetTV($tv,$value){
    		if(!is_array($this->tvs)) $this->tvs=array();
    		$this->tvs[$tv]=$value;
    	}
    	
    	/***********************************************
    	  Установка шаблона документа
    	  $tpl - Имя или идентификатор шаблона
    	************************************************/		
    	function SetTemplate($tpl){	
    		global $modx;
    		// Если указано имч шаблона, получаем id
    		if(!is_numeric($tpl)) {
    			$tablename=$modx->getFullTableName('site_templates');
    			$tpl = $modx->db->getValue("SELECT id FROM $tablename WHERE templatename='$tpl' LIMIT 1");
    			if(empty($tpl)) return false;
    		}
    		
    		$this->fields['template']=$tpl; 
    		return true;
    	}
    
    	/************************************************************
    	  Удаление доккумента и связанных с ним TV
    	*************************************************************/
    	function Delete(){
    		if($this->isNew) return;
    		global $modx;
    		$id=$this->fields['id'];
    		$modx->db->delete($modx->getFullTableName('site_content'),"id=$id");
    		$modx->db->delete($modx->getFullTableName('site_tmplvar_contentvalues'),"contentid=$id");
    		$this->isNew=true;
    	}
    	
    	/************************************************************
    	  Сохранение значений TV, служебная функция. Сохраняются 
    	  тлько значения поределенные в $tvNames, если Такое имя TV 
    	  уже есть в oldTVs, происходит update, иначе insert
    	*************************************************************/
    	function saveTVs(){
    		global $modx;
    		if(!is_array($this->tvNames))$this->fillTVNames();
    		if(!is_array($this->oldTVs) && !$this->isNew)
    			$this->fillOldTVValues();
    		else 
    			$this->oldTVs = array();
    			
    		if(!is_array($this->tvNames))$this->fillTVNames();
    		$tvc = $modx->getFullTableName('site_tmplvar_contentvalues');
    		$id=$this->fields['id'];
    		foreach($this->tvs as $tv=>$value)
    		if(isset($this->tvNames[$tv])){
    			$tmplvarid=$this->tvNames[$tv];		
    			if(isset($this->oldTVs[$tv])){
    				if($this->oldTVs[$tv]==$this->tvNames[$tv]) continue;
    				$sql="UPDATE $tvc SET value='$value' WHERE tmplvarid=$tmplvarid AND contentid=$id";
    			}
    			else
    				$sql="INSERT INTO $tvc (tmplvarid,value,contentid) VALUES ($tmplvarid,'$value',$id)";
    			$modx->db->query($sql);
    		}
    	}
    	
    	/************************************************************
    	  Заполнение массива значений TV ($oldTVs), служебная функция. 
    	  В отличие от $modx->getTemplateVars, берет только 
    	  фактические значения игнорируя значения "по-умолчанию"
    	*************************************************************/
    	function fillOldTVValues(){
    		global $modx;
    		$tvc = $modx->getFullTableName('site_tmplvar_contentvalues');
    		$tvs = $modx->getFullTableName('site_tmplvars');
    		$sql = 'SELECT tvs.name as name, tvc.value as value '.
    		       "FROM $tvc tvc INNER JOIN $tvs tvs ".
    			   'ON tvs.id=tvc.tmplvarid WHERE tvc.contentid ='.$this->fields['id'];
    		$result = $modx->db->query($sql);
    		$this->oldTVs = array();
    		while ($row = mysql_fetch_assoc($result)) $this->oldTVs[$row['name']] = $row['value'];
    	}
    	
    	/************************************************************
    	  Заполнение массива имен TV ($tvNames)), служебная функция. 
    	*************************************************************/	
    	function fillTVNames(){
    		global $modx;
    		$this->tvNames = array();
    		$tvs = $modx->getFullTableName('site_tmplvars');
    		$result = $modx->db->select('id, name', $modx->getFullTableName('site_tmplvars'));
    		while ($row = mysql_fetch_assoc($result)) $this->tvNames[$row['name']] = $row['id'];
    	}
    }
    ?>
    

    Использовать - элементарно. Пример создания документа:
    require_once('assets/libs/docapi/document.class.inc.php');
    $doc = new Document();
    $doc->Set('parent',$folder);
    $doc->Set('alias','post'.time());
    $doc->Set('content','Текст документа');
    $doc->Set('template','GuestBookComments');
    $doc->Set('tvComment','Комментарий к посту');
    $doc->Save();
    

    Пример редактирования документа:
    require_once('assets/libs/docapi/document.class.inc.php');
    $doc = new Document($id,'content');
    $content=$doc->Get('content');
    $doc->Set('content', '<p>'.$content.'</p>');
    $doc->Save();
    


    Предлагаю интерактивно продолжить разработку subj-а. Принимаются дополнения/замечания/исправления/наставления.

    В проекте следующие возможности:
    Управление web-группами
    • Итак, я дополнил свой класс:

      1. Появились функции Get()/Set().
      2. Теперь возможно установить шаблон вызовом
      $doc->Set('template','GuestBookComments');

      3. Убрал тз инициализации $modx, в пользу global $modx;

      Полный код:

      [перенесен в первый пост]

      Надеюсь это кому-нибудь пригодится. Требуется тестирование и предложения по доработке/оптимизиции и т.д.
      • отличный класс! как-то где-то у меня лично возникала необходимость программо создавать контент, и пришлось вводить все-таки в ручную. а как вы в частности используете его?

        по поводу доработки - программистов то у нас тут особо нет пока:) я надеюсь однако это исправится вскоре.

        PS. кстати у вас нет ли случайно полного списка API функций MODx? очень пригодился бы на сайте.
          http://modx.ru - российская поддержка MODx
          http://newscup.ru - экспериментальный проект
          http://yentsun.com - персональный сайт
        • Мне нужно гостевую книгу было сделать с возможностью комментирования постов админимтраторами. Ну, типо "вопрос-ответ". Я создал шаблон с TV для комментариев. Каждый пост, соответственно складывается в некоторую папку как документ и ему устанавливается этот шаблон. Админ может написать комментарий в менеджере или в фронтэнде через quickedit.

          По-этому UserComments не подходит, т.к. пишет в один доккумент, а NewsPublisher не помню чем не подошел. А так, я часто встречался с подобной задачей. К тому же вышеназванные снипеты тоже обращаются непосредственно к базе, а могли бы использовать подобный API

          Полного списка API нет, приходится открывать document.parser.class.inc.php каждый раз

          Последняя версия класса:

          [перенесена в первый пост]

          Тут все тоже самое, только код установки шаблона пооптимальней
          • может, когда закончите класс до какой-нибудь продакшн стадии, на сайт его вместе с руководством?
              http://modx.ru - российская поддержка MODx
              http://newscup.ru - экспериментальный проект
              http://yentsun.com - персональный сайт
            • Да, без проблем. Только я его дополняю по мере своей необходимости в этом, и надеялся, что кто-нибудь поддержит из программистов. Чтобы дело быстрее шло. Или, хотя бы советом - каки функции еще нужны, как что удобнее.

              Может стоит перевести на английский и в основной форум запостить? Я, просто, переводить могу без проблем с инглиша, а наоборот - криво...
              • я честно говря не понял, это класс враппер для апи? а почему сами вызовы АПИ не канают?
                  "Und wenn du lange in einen Abgrund blickst, blickt der Abgrund auch in dich hinein."

                  Не используйте Revo для "просто сайтов". Используйте Evo

                  Who can defeat the Russian bear?
                • Нет, это совсем не врапер. Это дополнение API. Существующий API, как бы, read-anly, он не позволяет Создавать/Изменять/Удалять документы. И я бы очень хотел его в самом API видеть.
                  Инклюдится в снипите

                  include '/assets/lib/document.class.inc.php';


                  и вызывается.
                  • окей... уже можно переводить и постить? или еще дорабатывается?
                      http://modx.ru - российская поддержка MODx
                      http://newscup.ru - экспериментальный проект
                      http://yentsun.com - персональный сайт
                    • Я думаю, с TV доделаю сегодня, и тогда можно smiley