MODXのドキュメントアクセスシステム

みなさん、良い一日を。



現在、通常のユーザーごとに個別のドキュメントを使用してmodxを作成しています。

管理者はこれらのドキュメントに手を加えたくなかったので(サイトで問題がなければ、ドキュメントが多すぎて管理者の速度が低下し始めます)、私はそれらを別のデータベーステーブルに配置し、1つのリソースを介して出力することにしました。



したがって、ドキュメントの要件を検討してください(少なくともこれらは必要でした)。

  1. ドキュメントにはタイトルとコンテンツが必要です。
  2. ドキュメントにはタイプが必要です(同じタイプのドキュメントを簡単に検索できるようにするため)。
  3. ドキュメントの所有者は、常にドキュメントを編集および表示するアクセス権を持っています。
  4. サイトの所有者と弁護士は、任意のドキュメントにランダムにアクセスできます。
  5. サイトの所有者と彼がこれを許可したユーザーは、適切なユーザーに任意のドキュメントの表示と編集を許可できる必要があります。
  6. 任意の登録ユーザーは、任意のドキュメントをしばらくまたは即座に永久に表示または編集する権利のみを取得できます。




1.データ構造の定義



最初に、データベース内のドキュメントレコードの構造を推定しましょう。

特定のドキュメントの構造
// TryLoadDocument <?php /** ,         (   JSON   ): { "type":"agreement", -  , , , : carta, license  .. "title":"", -   "text":".  .  : ______ ", -  , XSS  CLeditor,   .    -     . "owner":29, -   ,   ,      .            (..  "") "edit":[29,555,34,52], -  ,    . !!   Administrator,Jurists     ! "view":[5677,599677,5999898677,855677] - ,    http://.../docs?doc_id=5   (   ) "view-temp":[{"id":5,"until":1413640050},{"id":9,"until":1413640100},{"id":7,"until":1413640050}] -  view,  "until"( timestamp) ,         (    ) "edit-temp":[{"id":5,"until":1413640050},{"id":9,"until":1413640100},{"id":7,"until":1413640050}] -  edit,  "until"( timestamp) ,         (    ) }       : CREATE TABLE IF NOT EXISTS `documents` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id ', `type` varchar(255) NOT NULL COMMENT ' ', `title` varchar(255) NOT NULL COMMENT ' ', `text` text NOT NULL COMMENT ' ', `owner` bigint(20) NOT NULL COMMENT ' ', `edit` text NOT NULL COMMENT ' ,        ', `edit-temp` text NOT NULL COMMENT '   ', `view` text NOT NULL COMMENT ' ,      ', `view-temp` text NOT NULL COMMENT '   ', UNIQUE KEY `id` (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=cp1251 COMMENT='   - ...'; */
      
      







2. TryLoadDocumentスニペット



2.1移植性の確保


構造を決定した後、一連の関数を使用してこれを行うことは議論の余地がある決定であることが明らかになったため、OOPのオプションが選択されました。

まあ、同じ段階で、他のモジュール(この場合はスニペット)でオブジェクトを再利用するのが便利であることを思い出してください。そのため、このスニペットのストレージを静的docs.phpファイルで使用します)、およびこのスニペットが次のようにクラスのためだけに別のスニペットに接続されているかどうかを確認するチェックを追加します。

スニペットがDocumentクラスのソースとして使用されているかどうかを確認する
 <?php class Document {...} if(DOC_API_MODE!="API")//    Document,     ) { ...//    }
      
      







Documentクラスを接続するには、別のスニペットを記述するだけで十分です。



 define("DOC_API_MODE","API"); include_once 'docs.php';
      
      







2.2クラスの一般的なロジックを書く


すべての準備が完了したので、Documentクラス自体の操作を始めましょう。

まず、ドキュメントのデータを定義します。



  private $data;//       ( $data['title'] -  ) private $uid;//=user id — id ,     ( ) private $modx;//   modx API
      
      





デザイナでは、 が私たちをロードしているのかがわかり、どのようなドキュメントが必要かはわかりません。これにより、たとえば同じクラスオブジェクトを使用して、一度に多くのドキュメントを作成できます。



  public function __construct($modx) {//..    $modx   (    ),    $this->modx=$modx; $this->uid=$this->modx->user->get('id');//         }
      
      





次に、このクラスのオブジェクトが私たちに与えるものを推定しましょう。 つまり、パブリックメソッドです。

明らかにこれ:





また、このクラスで実行することをここに追加します。



これらの関数の実装は次のとおりです。

パブリックメソッド
最も簡単なのは、クラス外のフィールドへのアクセスです。

  public function &__set ( $name , $value ) {//(  )    title  text $allowed=["title","text"]; if(in_array($name,$allowed)) { if($this->editAllowed())//     $this->data[$name]=$value; } } public function &__get ( $name ) {//          edit & view,   ... if($this->isOwner() || $this->viewAllowed() || $this->editAllowed()) { switch ($name) { case "title":return $this->data['title']; case "text": return $this->data['text']; case "id": return $this->data['id']; case "uid": return $this->uid; } } return 'forbidden'; }
      
      





権限チェック+指定されたデータから新しいドキュメントを作成:

データベースを直接操作することはまだありません
  public function MakeNew($type,$title,$text)//    ,    { $this->data['text']=$text;//  $this->data['title']=$title;// $this->data['view']=[];//    $this->data['view-temp']=[]; $this->data['edit']=[];//    $this->data['edit-temp']=[]; $this->load($this->saveAsNew($type));//        } public function viewAllowed() {// ,       ,  - .. $allowed= $this->isOwner()//  -   || in_array($this->uid,$this->data['view']);//      if($allowed) return true; else for($i=0; $i<count($this->data['view-temp']);$i++) if($this->data['view-temp'][$i]->id==$this->uid) return $this->data['view-temp'][$i]->until > time(); return false; } public function editAllowed() {// ,       ,  - .. $allowed = $this->isOwner() || //  -   in_array($this->uid,$this->data['edit']);//     if($allowed) return true; else for($i=0; $i<count($this->data['edit-temp']);$i++) if($this->data['edit-temp'][$i]->id==$this->uid) return $this->data['edit-temp'][$i]->until > time(); //     '->' -    json_decode return false; } public function manageAllowed() {//true         . false   . return $this->modx->user->isMember('Jurists')||$this->modx->user->isMember('Administrator'); } public function allow($new_user,$can_edit,$time=0) { // -   . $new_user -  , //$can_edit -   (     ,   ) //$time -     (  0 - .    $user_id=(int)$new_user; if($user_id!=0 && $this->manageAllowed()) if($can_edit) { if($this->editAllowed()) { if($time==0)//   $this->data['edit'][]=$user_id; else//   $time  $this->data['edit-temp'][]=["id"=>$user_id,"until"=>time()+$time]; } } else { if($time==0)//   $this->data['view'][]=$user_id; else//   $time  $this->data['view-temp'][]=["id"=>$user_id,"until"=>time()+$time]; } } public function isOwner() { $usual=$this->uid==$this->data['owner'];//   : if($usual) return true;// , else//  return $this->manageAllowed(); }
      
      





古い一時的な許可のドキュメントをクリアするヘルパー関数:



  private function clearTemp() {//    e       if(count($this->data['view-temp'])+count($this->data['edit-temp']) > 0)//  -    { for($i=0; $i<count($this->data['view-temp']);$i++) //   ,       (time()) { if($this->data['view-temp'][$i]->until < time()) unset($this->data['view-temp'][$i]); } $this->data['view-temp']=array_values($this->data['view-temp']);//    ( [1,3,5]=>[0,1,2)] for($i=0; $i<count($this->data['edit-temp']);$i++) //   ,       (time()) { if($this->data['edit-temp'][$i]->until < time()) unset($this->data['edit-temp'][$i]); } $this->data['edit-temp'] = array_values($this->data['edit-temp']);//    ( [1,3,5]=>[0,1,2)] $this->save();//  } }
      
      









2.3特定のデータベースを操作するための関数を作成します。


したがって、特定のデータベースに依存しない、コードの論理部分は完全です。 それでは、PDOを使用してMODXのデータベースを直接操作して、下位レベルに移動しましょう。

データベースを直接操作する
  public function load($id) {//   (     ,          ) $sql="SELECT * FROM `documents` WHERE `id`=:id"; $query = new xPDOCriteria($this->modx, $sql,array(':id'=>$id)); if($query->prepare() && $query->stmt->execute()) {//    $this->data = $query->stmt->fetchAll(PDO::FETCH_ASSOC)[0]; if(count($this->data)==0) return false;//   ,     $this->data['edit']=json_decode($this->data['edit']);///        $this->data['edit-temp']=json_decode($this->data['edit-temp']);///         $this->data['view']=json_decode($this->data['view']);///        $this->data['view-temp']=json_decode($this->data['view-temp']);///         $this->clearTemp();//  view-temp & edit-temp    return true;//  , ,    } else return false;//   ,     } public function save() {//      $sql="UPDATE `documents` SET `title`=:title, `text`=:text, `view`=:view, `edit`=:edit, `view-temp`=:viewtemp, `edit-temp`=:edittemp WHERE `id`=:id";//  $this->data['view']=json_encode($this->data['view']);///        $this->data['view-temp']=json_encode($this->data['view-temp']);///         $this->data['edit']=json_encode($this->data['edit']);///        $this->data['edit-temp']=json_encode($this->data['edit-temp']);///         $query=new xPDOCriteria($this->modx, $sql, [":title"=>$this->data['title'],":text"=>$this->data['text'],":edit"=>$this->data['edit'],":view"=>$this->data['view'],":edittemp"=>$this->data['edit-temp'],":viewtemp"=>$this->data['view-temp'],":id"=>$this->data["id"]]);//  $query->prepare() && $query->stmt->execute();//  //     $this->data['view']=json_decode($this->data['view']); $this->data['view-temp']=json_decode($this->data['view-temp']); $this->data['edit']=json_decode($this->data['edit']); $this->data['edit-temp']=json_decode($this->data['edit-temp']); } private function saveAsNew($type) {//        $type $sql="INSERT INTO `documents` (`title`,`text`,`view`,`edit`,`owner`,`type`) VALUES(:title,:text,:view,:edit,:uid,:type)";//  $this->data['view']=json_encode($this->data['view']);///        $this->data['edit']=json_encode($this->data['edit']);///        $this->data['view-temp']=json_encode($this->data['view-temp']);///        $this->data['edit-temp']=json_encode($this->data['edit-temp']);///        $query=new xPDOCriteria($this->modx, $sql, [":title"=>$this->data['title'],":text"=>$this->data['text'],":edit"=>$this->data['edit'],":view"=>$this->data['view'],":uid"=>$this->uid,":type"=>$type]);//  //   ,           //$this->modx->log(modX::LOG_LEVEL_ERROR," : ".$query->toSQL()); $query->prepare(); $query->stmt->execute();//  return $this->modx->lastInsertId();// id   }
      
      







これがDocumentクラス全体です。 とてもシンプル、私見。



2.4スニペット実行可能コード


ここで、TryLoadDocumentスニペットの機能を見みましょう。



だから...

TryLoadDoc実行中のコードスニペット-解析
匿名の著者が私たちに来たかどうかを確認します(彼のidは0です)。この場合、ログインするために彼を送ります。
 if($modx->user->get('id')==0)//    , { $modx->sendRedirect($modx->makeUrl(14));//     14,       . exit;//      ,   (     ) }
      
      







要求されたドキュメントをロードしようとしています(このスニペットが使用されるリソースの形式は/ docs?Doc_id = Nです)。
 $doc=new Document($modx);//           if(!$doc->load($_GET['doc_id']))//     {//  , ... return '  ...'; }
      
      





プレースホルダーに値を入力すると、ドキュメントを編集するためのフォームを表示したり、これを実行できないユーザーの権限を編集したりすることはできなくなります。
 //!!!   Rights,      $modx->setPlaceholder('CanManage',$doc->manageAllowed()?'true':'false'); //!!!   DocText,     $modx->setPlaceholder('CanEdit',$doc->editAllowed()?'true':'false');
      
      





次は、編集権限フォームフィールドにユーザーとして入力した内容を解析する単純な関数です。
 function DataToUID($userstr,$modx)//        "" { $link_rgx="/(.*uid=)([\d]{1,})(.*)/";//    http://*   *?uid=56 $id_rgx="/([^\w]{0,})([\d]{1,})/";// id (      ) if(preg_match($link_rgx,$userstr)) {//   http://*   *?uid=56 $r="$2"; return preg_replace($link_rgx,$r,$userstr); } else if(preg_match($id_rgx,$userstr))//   " 234",  { $r="$2"; return preg_replace($id_rgx,$r,$userstr);//   } else//          ?    ? { $usr=$modx->getObject('modUser',["username"=>$userstr]);//      return $usr?$usr->get('id'):'-1'; } }
      
      





権利の追加があれば処理します。
 if(isset($_POST['add']))//    "  ... { $userID=(int)DataToUID($_POST['userid'],$modx);// id     'userid' if($userID!='-1')//   { if($_POST['allow']=="edit")//       (   'allow') { //   $modx->log(modX::LOG_LEVEL_ERROR,"      #".$doc->id."  #".$doc->uid."  #".$userID); $doc->allow($userID,true,(int)$_POST['length']); $doc->save(); } else if($_POST['allow']=="view")////     (   'allow') { //   $modx->log(modX::LOG_LEVEL_ERROR,"      #".$doc->id."  #".$doc->uid."  #".$userID); $doc->allow($userID,false,(int)$_POST['length']); $doc->save(); } }else $modx->log(modX::LOG_LEVEL_ERROR,"DataToUID  . (".$_POST['userid'].")");//     ,    }
      
      





文書編集の処理(ある場合)
 if(isset($_POST['edit']))//      "" { $modx->log(modX::LOG_LEVEL_ERROR,"    #".$doc->id."  #".$doc->uid);//   if(!empty($_POST["text"]))//     (    ) { $doc->text=$_POST["text"];//   text   $doc->save(); $modx->log(modX::LOG_LEVEL_ERROR,"   #".$doc->id."  #".$doc->uid);//   } }
      
      





プレースホルダー[[+ doc]]に、ユーザーがアクセスできるドキュメントとそれを編集するためのフォームで構成されるリソースのコンテンツを返します。
 /**********   *************/ if(!isset($_POST['ajax']))//     ,    . { $output=""; // ,  ,     //   DocTitle   title,    .     -   . $output.=$modx->getChunk('DocTitle',['title'=>$doc->title]); //   DocText   title,    .     -   . $output.=$modx->getChunk('DocText',['text'=>$doc->text]); $modx->setPlaceholder('doc', $output); return ''; }
      
      









理解を深めるために、誰かが1つのブロックでコードを見る方が便利な場合があります。

TryLoadDocumentスニペットコード全体
 if($modx->user->get('id')==0)//    , { $modx->sendRedirect($modx->makeUrl(14));//     14,       . exit;//      ,   (     ) } /*******/ $doc=new Document($modx);//           if(!$doc->load($_GET['doc_id']))//     {//  , ... return '  ...'; } //!!!   Rights,      $modx->setPlaceholder('CanManage',$doc->manageAllowed()?'true':'false'); //!!!   DocText,     $modx->setPlaceholder('CanEdit',$doc->editAllowed()?'true':'false'); function DataToUID($userstr,$modx)//        "" { $link_rgx="/(.*uid=)([\d]{1,})(.*)/";//    http://*   *?uid=56 $id_rgx="/([^\w]{0,})([\d]{1,})/";// id (      ) if(preg_match($link_rgx,$userstr)) {//   http://*   *?uid=56 $r="$2"; return preg_replace($link_rgx,$r,$userstr); } else if(preg_match($id_rgx,$userstr))//   " 234",  { $r="$2"; return preg_replace($id_rgx,$r,$userstr);//   } else//          ?    ? { $usr=$modx->getObject('modUser',["username"=>$userstr]);//      return $usr?$usr->get('id'):'-1'; } } /*********      ***********/ if(isset($_POST['add']))//    "  ... { $userID=(int)DataToUID($_POST['userid'],$modx);// id     'userid' if($userID!='-1')//   { if($_POST['allow']=="edit")//       (   'allow') { //   $modx->log(modX::LOG_LEVEL_ERROR,"      #".$doc->id."  #".$doc->uid."  #".$userID); $doc->allow($userID,true,(int)$_POST['length']); $doc->save(); } else if($_POST['allow']=="view")////     (   'allow') { //   $modx->log(modX::LOG_LEVEL_ERROR,"      #".$doc->id."  #".$doc->uid."  #".$userID); $doc->allow($userID,false,(int)$_POST['length']); $doc->save(); } }else $modx->log(modX::LOG_LEVEL_ERROR,"DataToUID  . (".$_POST['userid'].")");//     ,    } if(isset($_POST['edit']))//      "" { $modx->log(modX::LOG_LEVEL_ERROR,"    #".$doc->id."  #".$doc->uid);//   if(!empty($_POST["text"]))//     (    ) { $doc->text=$_POST["text"];//   text   $doc->save(); $modx->log(modX::LOG_LEVEL_ERROR,"   #".$doc->id."  #".$doc->uid);//   } } /**********   *************/ if(!isset($_POST['ajax']))//     ,    . { $output=""; // ,  ,     //   DocTitle   title,    .     -   . $output.=$modx->getChunk('DocTitle',['title'=>$doc->title]); //   DocText   title,    .     -   . $output.=$modx->getChunk('DocText',['text'=>$doc->text]); $modx->setPlaceholder('doc', $output); return ''; } return '...';//        ,     -   
      
      







3.受信したデータのフォーマットとページへの出力



3.1必要なチャンク


ドキュメントの正しい出力のために、3つの単純なチャンクが使用されます。

権利-権利を編集するためのフォーム
 <form action="[[~[[*id]]]]?doc_id=[[!GET? &param=`doc_id`]]" method="post" > <fieldset><span>  ...</span><input type="text" name="userid" style=" background: white; width: 340px; padding: 5px; font-size: 14px; margin: 0 15px; "/>  <select name="allow"> <option value="view" selected="selected"></option> <option value="edit">  </option> </select> <select name="length"> <option value="60"> 1 .</option> <option value="600"> 10 .</option> <option value="3600"> .</option> <option value="86400"> .</option> <option value="0">.</option> </select> <input type="hidden" name="add" value="1" /> </fieldset> <input type="submit" value=" !"/> </form>
      
      







DocTitle-ドキュメントの表示タイトルのテンプレート。
 <h2>[[!+title]]</h2>
      
      







DoctText *-ドキュメント自体のテキストテンプレート
 [[!If? &subject=`[[!+CanEdit]]` &operator=`EQ` &operand=`true` &then=`<form action="[[~[[*id]]]]?doc_id=[[!GET? &param=`doc_id`]]" method="post"> <input type="submit" value="   ..."/>`]] <textarea id="text" name="text" > [[+text]] </textarea> <script type="text/javascript"> CKEDITOR.replace( 'text' ); CKEDITOR.config.height=800; </script> <!--    CKeditor--> [[!If? &subject=`[[!+CanEdit]]` &operator=`EQ` &operand=`true` &then=`<input type="hidden" name="edit" value="1"/> <input type="submit" value="   ..."/> </form>`]]
      
      







* -何らかの理由でフォームが表示されない場合、 Ifコンポーネントがインストールされているかどうかを確認する価値がありますか?

そして、アドレスバーからパラメータを取得する最も簡単なスニペット:

ゲット
 <? return isset($param)?$_GET[$param.""]:'0';
      
      







最終的なTryLoadDocumentスニペットコードは、pastebin.com / R55bPUCHにあります。

さて、ほとんどすべての準備が整いました。テンプレートを使用してリソースコンテンツに添付するだけです。



3.2ドキュメントを操作するためのリソース


リソース自体のコンテンツフィールドのコードは次のようになります。



 [[!TryLoadDocument]] [[!If? &subject=`[[!+CanManage]]` &operator=`EQ` &operand=`true` &then=`[[$Rights]]`]] [[!+doc]] [[!If? &subject=`[[!+CanManage]]` &operator=`EQ` &operand=`true` &then=`[[$Rights]]`]]
      
      





(DocTextチャンクからの)ドキュメントのテキストを含むTextareaは、WYSIWYGエディターでラップする必要があります。たとえば、CKeditorを使用しました。

CKeditorはこのように配置されます
<head>*

  <script src="//cdn.ckeditor.com/4.4.5/full/ckeditor.js"></script>
      
      





* — TV ExtraHeaders , <head> , , , TV. DocText textarea, ( ).



4.別のスニペットでDocumentクラスを使用する例



別のスニペットで別のユーザーのドキュメントを作成するとします。



 <?php ... define("DOC_API_MODE","API"); include_once 'docs.php'; ... $doc= new Document($modx); $title=""; $text=$modx->getChunk('agreement_template');//         //        -  $doc->MakeNew('agreement',$title,$text);//,    ...
      
      







この記事では、アイデアがどのようにロジックに移行し、次にコードに移行し、最終的には作業メカニズムに移行するかを示しました。



これが誰かに役立つことを願っています。



記事のテキストの誤りを事前に謝罪します(すべてをキャッチしようとしましたが)。大きなテキストを書いた経験はありません。私はコメントを喜んでいます。



All Articles