We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!
    • 18962
    • 2 Posts
    I’ve been evaluating modx for a few days. I’m new to it, but have a good grasp of PHP, SQL, CMS systems, and software design in general. I’ve been learning just by jumping in, but I’m looking for some specific direction in the way of best practices. (btw, I’m going with Revolution)

    Overall, I’ve just been trying to migrate a small site to modx. Pages are ported fine, with templates, chunks, snippets being employed. Now I’m trying to migrate a custom app that was written for an art library. It’s a simple app really, consisting of only a few tables (artworks, artists, etc.), and I’m trying to figure out the best way to implement this in a modx way.

    I used the xpdo interface to write an import, creating resources that match the artwork entries and using template variables for the custom fields (date, subject, etc.). This results in hundreds of resources in one container though, which seems cumbersome through the manager interface. Is this the right way to go? Do I implement each artwork entry as a resource, each artist entry as a resource, etc.?

    In terms of SQL/code/complexity, I wouldn’t consider this part of the project anything fancier than a simple blog app, so even a solid example along those lines might be helpful for me.

    Or does something like this require a custom package to directly map to custom db tables? Or is there a simple way to browse/manage hundreds of resources from the manager?

    I’m not afraid of getting my hands dirty with coding and custom components, I’m just really not sure what the best road to take for this might be given that I’m very new to modx. Thanks for any tips, advice or recommendations of what direction to go.
      • 10152
      • 156 Posts
      I am a newbie but this may be useful, assuming you haveread the "build a 3rd part component with custom DB" tutorial.

      It’s a draft snippet called "rafentries" that allows logged users to post entries ( title, message, skills, price, delay, ispublic). 3 context are handled ( "web", "en" and "de" ) storing entries from each context in a separate table.
      raf_entries_web
      raf_entries_en
      raf_entries_de

      The site declines in
      http://mysite.localhost/
      http://en.mysite.localhost/
      http://de.mysite.localhost/


      Let’s define our 3 tables in rafentries.mysql.schema.xml
      <?xml version="1.0" encoding="UTF-8"?>
      <model package="rafentries" baseClass="xPDOObject" platform="mysql" defaultEngine="MyISAM" phpdoc-package="rafentries" phpdoc-subpackage="model">
          <object class="rafEntries_web" table="raf_entries_web" extends="xPDOSimpleObject">
              <field key="usrid"      dbtype="int"        precision="1"       attributes="unsigned"   phptype="integer"   null="false" />
              <field key="title"      dbtype="varchar"    precision="255"                             phptype="string"    null="false" />
              <field key="alias"      dbtype="varchar"    precision="255"                             phptype="string"    null="false" index="index" />
              <field key="entry"      dbtype="mediumtext"                                             phptype="string"    null="false" />
              <field key="skills"     dbtype="varchar"    precision="255"                             phptype="string"    null="true"  />
              <field key="delay"      dbtype="int"        precision="1"       attributes="unsigned"   phptype="integer"   null="true"  />
              <field key="price"      dbtype="int"        precision="1"       attributes="unsigned"   phptype="integer"   null="true"  />
              <field key="status"     dbtype="int"        precision="1"       attributes="unsigned"   phptype="integer"   null="true"  />
              <field key="public"     dbtype="int"        precision="1"       attributes="unsigned"   phptype="integer"   null="true"  />
              <field key="ip"         dbtype="varchar"    precision="255"                             phptype="string"    null="true"  />
              <field key="editedon"   dbtype="datetime"   phptype="datetime" null="true" />
              <field key="createdon"  dbtype="datetime"   phptype="datetime" null="true" />
          </object>
          <object class="rafEntries_en" table="raf_entries_en" extends="xPDOSimpleObject">
              <field key="usrid"      dbtype="int"        precision="1"       attributes="unsigned"   phptype="integer"   null="false" />
              <field key="title"      dbtype="varchar"    precision="255"                             phptype="string"    null="false" />
              <field key="alias"      dbtype="varchar"    precision="255"                             phptype="string"    null="false" index="index" />
              <field key="entry"      dbtype="mediumtext"                                             phptype="string"    null="false" />
              <field key="skills"     dbtype="varchar"    precision="255"                             phptype="string"    null="true"  />
              <field key="delay"      dbtype="int"        precision="1"       attributes="unsigned"   phptype="integer"   null="true"  />
              <field key="price"      dbtype="int"        precision="1"       attributes="unsigned"   phptype="integer"   null="true"  />
              <field key="status"     dbtype="int"        precision="1"       attributes="unsigned"   phptype="integer"   null="true"  />
              <field key="public"     dbtype="int"        precision="1"       attributes="unsigned"   phptype="integer"   null="true"  />
              <field key="ip"         dbtype="varchar"    precision="255"                             phptype="string"    null="true"  />
              <field key="editedon"   dbtype="datetime"   phptype="datetime" null="true" />
              <field key="createdon"  dbtype="datetime"   phptype="datetime" null="true" />
          </object>
          <object class="rafEntries_de" table="raf_entries_de" extends="xPDOSimpleObject">
              <field key="usrid"      dbtype="int"        precision="1"       attributes="unsigned"   phptype="integer"   null="false" />
              <field key="title"      dbtype="varchar"    precision="255"                             phptype="string"    null="false" />
              <field key="alias"      dbtype="varchar"    precision="255"                             phptype="string"    null="false" index="index" />
              <field key="entry"      dbtype="mediumtext"                                             phptype="string"    null="false" />
              <field key="skills"     dbtype="varchar"    precision="255"                             phptype="string"    null="true"  />
              <field key="delay"      dbtype="int"        precision="1"       attributes="unsigned"   phptype="integer"   null="true"  />
              <field key="price"      dbtype="int"        precision="1"       attributes="unsigned"   phptype="integer"   null="true"  />
              <field key="status"     dbtype="int"        precision="1"       attributes="unsigned"   phptype="integer"   null="true"  />
              <field key="public"     dbtype="int"        precision="1"       attributes="unsigned"   phptype="integer"   null="true"  />
              <field key="ip"         dbtype="varchar"    precision="255"                             phptype="string"    null="true"  />
              <field key="editedon"   dbtype="datetime"   phptype="datetime" null="true" />
              <field key="createdon"  dbtype="datetime"   phptype="datetime" null="true" />
          </object>
      </model>
      



      Now after building, comes the snippet /core/components/rafentries/snippet.rafentries.php
      <?php
      /**
       * @package rafentries
       */
      
          $publishedByDefault = 0;
      
          $alias          = $_GET['alias'];// check here if alias exists (and if usrid is ok if edit)
      
          if ( $service == 'viewentries' && $alias != '' ) {
      
              $service='viewentry';
      
          }
      
          $title          = $_POST['title'];
      
          $entryId        = $_POST['entryId'];
          $entry          = $_POST['entry'];
          $skill1         = $_POST['skill1'];
          $delay          = ( int ) $_POST['delay'];
          $price          = ( int ) $_POST['price'];
          $public          = ( int ) $_POST['public'];
      
      
      
          $status         = array ( 'unpublishentry'=>2, 'closeentry'=>3, 'removeentry'=>4 );
          $contexts       = array ( 'mysite'=>'web', 'en'=>'en', 'de'=>'de' );
      
          $tmp            = explode ( '.', $_SERVER['HTTP_HOST'] );
          $context        = $contexts[ $tmp[ 0 ] ];
      
      
          $userId         = $modx->getLoginUserID($context);
      
      
          $base_path      = !empty($base_path) ? $base_path : $modx->getOption('core_path').'/www/mysite/core/components/rafentries/';
          $modx->addPackage( 'rafentries',$base_path.'model/' );
      
      
          if ( $service == 'newentry' && !empty( $_POST ) ) {
      
      
      
              if ( $title != '' && $entry != '' ) {
      
      
      
      
                  $storeEntry = $modx -> newObject ( 'rafEntries_'.$context );
      
                  $storeEntry->fromArray(array(
                      'usrid' => $userId,
                      'title' => $title,
                      'alias' => makeAlias($title),
                      'entry' => $entry,
                      'delay' => $delay,
                      'price' => $price,
                      'skills' => $skill1,
                      'status' => $publishedByDefault,
                      'public' => $public,
                      'ip' => get_ip(),
                      'createdon' => time(),
                  ));
      
      
                  $storeEntry->save();
      
                  $url = $modx->makeUrl($successRedirectPage,'','','full');
      
                  $modx->sendRedirect($url,0,REDIRECT_META);
      
              }
      
      
          }
          if ( $service == 'viewentries' || $service=='viewentry' || $service=='viewmyentries' ) {
      
              $sortie = array();
      
              if ( $service=='viewmyentries') {
      
                  $entries = $modx->getCollection('rafEntries_'.$context, array ( 'usrid' => $userId,));
      
              }
              elseif ( $service=='viewentries') {
      
                  $entries = $modx->getCollection('rafEntries_'.$context);
      
              }
              elseif ( $service=='viewentry') {
      
                  $entries = $modx->getCollection('rafEntries_'.$context,array ('alias' => $alias,));
      
              }
      
      
              foreach ($entries as $entry) {
      
      
                  if ( ( $service=='viewentry' && $alias == $entry->get( 'alias' ) ) || $service!='viewentry' ) {
      
                      $properties             = $entry->toArray();
      
      
                      $sortie[] = $modx->getChunk('tplEntries', $properties);
      
      
                      $modx->setPlaceholders(array(
                              'id' => $entry->get('id'),
                              'usrid' => $entry->get('usrid'),
                              'title' => $entry->get('title'),
                              'alias' => $entry->get('alias'),
                              'entry' => $entry->get('entry'),
                              'skills' => $entry->get('skills'),
                              'price' => $entry->get('price'),
                              'delay' => $entry->get('delay'),
                              'status' => $entry->get('status'),
                              'public' => $entry->get('public'),
                              'ip' => $entry->get('ip'),
                              'editedon' => $entry->get('editedon'),
                              'createdon' => $entry->get('createdon'),
                              )
                              ,'entry.');
      
      
                  }
      
      
              }
      
      
      
              $output.=implode("\n", $sortie);
      
      
      
      
      
          }
          if ( $service == 'editentry') {
      
              if ( $userId>0) {
      
      
                  if ( !empty ( $_POST ) ) {
      
      
                      if ( $title!='' && $entry!='' ) {
      
      
      
                          $storeEntry = $modx->getObject('rafEntries_'.$context,array ('alias' => $alias, 'usrid'=>$userId,  ));// && usridd=ok a tester
      
      
                          $storeEntry->fromArray(array(
                              'title' => $title,
                              'entry' => $entry,
                              'delay' => $delay,
                              'price' => $price,
                              'skills' => $skill1,
                              'editedon' => time(),
                          ));
      
      
      
                          $storeEntry->save();
      
      
                          $url = $modx->makeUrl($successRedirectPage,'','','full');
      
      
                          $modx->sendRedirect($url,0,REDIRECT_META);
      
      
                      }
      
      
                  }
      
      
                  $entry = $modx->getObject('rafEntries_'.$context,array ('alias' => $alias, 'usrid'=>$userId, ));
      
      
      
      
                      $properties             = $entry->toArray();
      
                      $output = $modx->getChunk('tplEditEntry', $properties);
      
      
                      $modx->setPlaceholders(array(
                              'id' => $entry->get('id'),
                              'title' => $entry->get('title'),
                              'alias' => $entry->get('alias'),
                              'entry' => $entry->get('entry'),
                              'skills' => $entry->get('skills'),
                              'price' => $entry->get('price'),
                              'delay' => $entry->get('delay'),
                              'status' => $entry->get('status'),
                              'public' => $entry->get('public'),
                              'editedon' => $entry->get('editedon'),
                              'createdon' => $entry->get('createdon'),
                              )
                              ,'entry.');
      
      
      
      
      
      
      
              }
      
      
          }
          if ( $service == 'unpublishentry' || $service == 'closeentry' || $service == 'removeentry') {
      
              $entry = $modx->getObject('rafEntries_'.$context,array ('alias' => $alias, 'usrid'=>$userId, ));
      
      
              $properties             = $entry->toArray();
      
      
              $sortie[] = $modx->getChunk('tplEntries', $properties);
      
      
              $modx->setPlaceholders(array(
                      'id' => $entry->get('id'),
                      'usrid' => $entry->get('usrid'),
                      'title' => $entry->get('title'),
                      'alias' => $entry->get('alias'),
                      'entry' => $entry->get('entry'),
                      'skills' => $entry->get('skills'),
                      'price' => $entry->get('price'),
                      'delay' => $entry->get('delay'),
                      'status' => $entry->get('status'),
                      'public' => $entry->get('public'),
                      'ip' => $entry->get('ip'),
                      'editedon' => $entry->get('editedon'),
                      'createdon' => $entry->get('createdon'),
                      )
                      ,'entry.');
      
      
      
      
              if ( $userId == $entry->get('usrid')) {
      
      
                  if ( $alias == $entry->get('alias') ) {
      
      
      
                      $storeEntry = $modx->getObject('rafEntries_'.$context,array ('alias' => $alias,  'usrid'=>$userId, ));
      
      
                      $storeEntry->fromArray(array(
                          'status'=>$status[$service],
                      ));
      
      
                      $storeEntry->save();
      
      
                  }
      
      
              }
      
      
          }
      
          if ( $service == 'replyentry' ) {
      
      
              if ( $userId>0) {
      
      
      
      
      
              }
      
      
          }
      
      
          echo $output;
      
      
      
          // change this later by using the modx stuff for autoalias generation
          function makeAlias($url){
      
              $url    = no_accent($url);
              $url    = ereg_replace("[^a-z A-Z0-9-]*","",$url);
              $url    = ereg_replace("-{2,}","-",$url);
              $url    = ereg_replace(' ','-',$url);
              $url    = trim(strtolower($url));
              $url    = ltrim($url,'-');
              $url    = rtrim($url,'-');
              return $url;
          }
          function no_accent($filename) {
              $str = strtr(utf8_decode($filename),utf8_decode("ÀÁÂÃÄÅÇÑñÇçÈÉÊËÌÍÎÏÒÓÔÕÖØÙÚÛÜÝàáâãäåçèéêëìíîïðòóôõöøùúûüýÿ' "),
                                                 "AAAAAACNnCcEEEEIIIIOOOOOOUUUUYaaaaaaceeeeiiiiooooooouuuuyy--" );
              return $str;
          }
          function get_ip() {
      
              if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
                  $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
              }
              elseif(isset($_SERVER['HTTP_CLIENT_IP'])) {
                  $ip = $_SERVER['HTTP_CLIENT_IP'];
              }
              else {
                  $ip = $_SERVER['REMOTE_ADDR'];
              }
              return $ip;
      
          }
      
      


      Set up url rewriting ( i do this amateur with .htaccess, temporary solution )
      RewriteRule ^yourpath/([0-9A-Za-z-]+)/$ yourpath/?alias=$1 [L,QSA]       
      


      The template tplEditEntry :

      <form action="[[++site_url]][[~[[++page_modify_entry]]]][[+entry.alias]]/" method="post" name="entryForm" autocomplete="on" accept-charset="[[++modx_charset]]" enctype="multipart/form-data">
          <fieldset>
              <legend>[[%edit_entry]]</legend>
                  <label for="title"><span class="padLeft">[[%title]]</span>[[$arrow1]]
                  <input id="title" name= "title" type="text" value="[[+entry.title]]" /></label>
                  <label for="entry"><span class="padLeft">[[%entry]]</span>[[$arrow1]]
                  <textarea id="entry" name="entry">[[+entry.entry]]</textarea></label>
                  <label for="skill1"><span class="padLeft">[[%required_skills]]</span>[[$arrow1]]
                  <input id="skill1" name= "skill1" type="text" value="[[+entry.skills]]" /></label>
                  <label for="price"><span class="padLeft">[[%approx_price]] [[++currency]]</span>[[$arrow1]]
                  <input id="price" name= "price" type="text" value="[[+entry.price]]" /></label>
                  <label for="delay"><span class="padLeft">[[%deadline]]</span>[[$arrow1]]
                  <input id="delay" name= "delay" type="text" value="[[+entry.delay]]" /></label>
                  <button type="submit" name="newEntryBtn" value="[[%edit_entry]]">[[%edit_entry]]</button>
          </fieldset>
      </form>
      

      And then the template tplEntries :

      <li class="summary">
      <ul>  
      
      <li>
      <a href="[[++site_url]][[~[[++page_entries]]]][[+entry.alias]]/"><strong>[[+entry.title]]</strong></a></li>
      
      <li>[[+entry.entry]]</strong>
      </li>
        
      [[!If? &operator=`NEQ` &operand=`` &subject=`[[+entry.createdon]]` &then=`<li><span>[[%createdon]]</span>[[$arrow1]][[+entry.createdon]]</li>`]]
      
      [[!If? &operator=`NEQ` &operand=`` &subject=`[[+entry.editedon]]` &then=`<li><span>[[%editedon]]</span>[[$arrow1]][[+entry.editedon]]</li>`]]
      
      [[!If? &operator=`NEQ` &operand=`` &subject=`[[+entry.skills]]` &then=`<li><span>[[%required_skills]]</span>[[$arrow1]][[+entry.skills]]</li>`]]
      
      [[!If? &operator=`NEQ` &operand=`` &subject=`[[+entry.price]]` &then=`<li><span>[[%approx_price]]</span>[[$arrow1]][[+entry.price]] [[++currency]]</li>`]]
      
      [[!If? &operator=`EQ` &operand=`1` &subject=`[[+entry.delay]]` &then=`<li><span>[[%deadline]]</span>[[$arrow1]][[+entry.delay]] [[++time_unit]]</li>`]]
      
      [[!If? &operator=`GT` &operand=`1` &subject=`[[+entry.delay]]` &then=`<li><span>[[%deadline]]</span>[[$arrow1]][[+entry.delay]] [[++time_unit_plural]]</li>`]]
      
      
      
      [[If? &operator=`EQ` &operand=`advertisers` &subject=`[[!+mf.group]]` &then=`[[$advEntryActions]]`]]
      [[If? &operator=`EQ` &operand=`competitors` &subject=`[[!+mf.group]]` &then=`[[$cmpEntryActions]]`]]
      [[If? &operator=`EQ` &operand=`(anonymous)` &subject=`[[+modx.user.username]]` &then=`[[%login_or_register_to_reply]]`]]
      
      
      </ul>
          </li>    
      


      Form to add entry :
      <form action="[[++site_url]][[~[[*id]]]]" method="post" name="entryForm" autocomplete="on" accept-charset="[[++modx_charset]]" enctype="multipart/form-data">
      <fieldset>
      <legend>[[$checkbox1]][[%required_informations]]</legend>
              <label for="title"><span class="padLeft">[[%entry_title]]</span>[[$arrow1]]
              <input id="title" name= "title" type="text"></label>
              <label for="entry"><span class="padLeft">[[%your_entry]]</span>[[$arrow1]]
              <textarea id="entry" name="entry"></textarea></label>
      <legend>[[$checkbox1]][[%optional_informations]]</legend>
              <label for="skill1"><span class="padLeft">[[%required_skills]]</span>[[$arrow1]]
              <input id="skill1" name="skill1" type="text" /></label>
              <label for="delay"><span class="padLeft">[[%deadline]]</span>[[$arrow1]]
              <input id="delay"  name="delay" type="number" min="1" max="365" /></label>
              <label for="price"><span class="padLeft">[[%approx_price]]</span>[[$arrow1]]
              <input id="price"  name="price" type="number" min="[[++min_price_allowed]]" max="[[++max_price_allowed]]" /></label>
      </fieldset>
               <button type="submit" name="newEntryBtn" value="[[%submit_new_entry]]">[[%submit_new_entry]]</button>
      </form>
      
      


      Usage ( call on the same page, just befor the previous form ) :
      
      [[rafEntries? &service=`service`]]
      service values => newentry, viewentry, viewentries, viewmyentries, unpublishentry, closeentry, removeentry
      
      
        • 18962
        • 2 Posts
        Thanks for taking the time to respond with such a substantial reply!