• Good or bad? Extending site_content with a custom table#

  • chrizz Reply #1, 4 months, 1 week ago

    Reply
    Hi everyone,

    I'm thinking about to extend the regular site_content table, because I need a lot more information for some resources (it will become a gallery).
    First try: I used TVs. Unfortunately a lot of TVs slow down the page speed.
    Now I have two ideas but I don't know which one will be the MODx way
    1)
    Using one TV, storing all data as JSON
    => fast but for sorting I need to sort an array. Can't be done by MySQL

    2)
    Extending site_content table with a custom table (as described here mit modUser http://rtfm.modx.com/display/revolution20/Extending+modUser )
    => defining a new class_key for all the gallery resources (single pictures), sorting via tables

    I'm new on this level of developing and I hope someone will give me a hint. Perhaps I didn't realized that there's a third possibility or a improvement for 1 or 2
    thanks a lot!


  • opengeek Reply #2, 4 months, 1 week ago

    Reply
    Optimally, you would combine 1 and 2. Create some new relations to custom tables storing the data as you might need to sort or filter by and then summarize the data into JSON which can be used for quick access when rendering data.

    In MODX 2.2, you can easily achieve this with Custom Resource Classes, and there will also be a namespaced properties field (stored as JSON) available on modResource (site_content table) with full API access in 2.2.1 you can use to store the data on the Resource itself.


  • chrizz Reply #3, 4 months, 1 week ago

    Reply
    hey,

    thanks for your quick response.
    Let me try to summarize:
    In the backend and with my CMP I'll use the custom table. This is done by creating custom CRC. I can sort, filter, edit, create, whatever using my CMP. In the front end I can access my modMyCRC with ->getObject("modMyCRC")

    But why do I need to summarize data into JSON? I mean, if I got all relevant information in a table and I want to show them up in the front end / CMP: I have to call getObject("modMyCRC"), so all the fields are available?

    Sorry for this - perhaps - silly question. But I'm new on 2.2 and I'll try my very best to make it the MODx & optimal way... I mean: using seperate TVs was quite simple and the script/CMP worked well... but when I tested it with a bit more than 50 docs it became very slow

    cheers from Berlin


  • opengeek Reply #4, 4 months, 1 week ago

    Reply
    Quote from: chrizz at Jan 15, 2012, 03:40 PM
    hey,
    Let me try to summarize:
    In the backend and with my CMP I'll use the custom table. This is done by creating custom CRC. I can sort, filter, edit, create, whatever using my CMP. In the front end I can access my modMyCRC with ->getObject("modMyCRC")

    But why do I need to summarize data into JSON? I mean, if I got all relevant information in a table and I want to show them up in the front end / CMP: I have to call getObject("modMyCRC"), so all the fields are available?

    Sorry for this - perhaps - silly question. But I'm new on 2.2 and I'll try my very best to make it the MODx & optimal way... I mean: using seperate TVs was quite simple and the script/CMP worked well... but when I tested it with a bit more than 50 docs it became very slow
    It's not a silly question at all — we are still in the process of developing best practices for working with Custom Resource Classes.

    What we are trying to avoid is the need to add custom fields to the Resource table and instead encourage the use of custom related tables that can be joined on demand for back-end management and advanced front-end summarization requirements (searching/sorting). The only reason to summarize or duplicate the data in the new properties field is to make it easier to access and use that data without having to always join the additional tables, for performance reasons (i.e. avoiding additional joins/queries when working with collections of these custom Resources).


  • chrizz Reply #5, 4 months, 1 week ago

    Reply
    thanks for this explanation. This is what I like about MODx. It's getting more flexible with every new release
    Unfortunatley this is the problem right now... I followed the steps in these tutorials:
    http://rtfm.modx.com/display/revolution20/Extending+modUser
    http://rtfm.modx.com/display/revolution20/Creating+a+Resource+Class

    I created a schema file, generated a model from this and added classes as described. The difference between the provided schema file of copyrightresources (custom CRC tutorial) is the second object (see below) which describes my custom table and the composite information.

    The CRC works out fine and it add's the copyright notice on every "ugalleryMeta" (name of my resource type) resource.
    I got no errors/warnings at all, but my custom table seems to be not accessible. For testing I used the getContent method and try to add a value from my custom field.
    $content .= $this->get("price");
    


    I also tried to set a custom table field @beforeSave. No effect.

    Here's a part of my schema file
    <?xml version="1.0" encoding="UTF-8"?>
    <model package="ugallerymeta" baseClass="xPDOObject" platform="mysql" defaultEngine="MyISAM"> 
        <object class="ugalleryMeta" table="site_content" extends="modResource">
            <composite alias="ugalleryMeta" local="id" foreign="ugallery" cardinality="one" owner="local" />
        </object>
     	
    	<object class="ugallery_metadata" table="ugallery_metadata" extends="xPDOSimpleObject">
            <field key="ugallery" dbtype="int" phptype="integer" null="false" default="0" index="index" />
    		<field key="price" dbtype="int" precision="11" phptype="integer" null="false" />
    		<field key="status" dbtype="tinytext" phptype="string" null="false" />
    		<field key="technic" dbtype="varchar" precision="255" phptype="string" null="false" />
    		<field key="meta_data" dbtype="text" phptype="string" null="false" />
                    ... a lot more fields here ...
    		<aggregate alias="ugalleryMetadata" local="ugallery" foreign="id" cardinality="one" owner="foreign" />
    	</object>
    	
    </model>
    


    Does someone have a hint, where I could search for a coding error?

    thanks a lot!


  • BobRay Reply #6, 4 months, 1 week ago

    Reply
    It's hard to tell without seeing more code, but it's possible that you want the variable returned from the get*() method rather than "this" and you might not want to use $content as a variable name since it is a field name:

    <?php
    $obj = $modx->getObject('MyObject', $c);
    $price = $obj->get('price');



    ---------------------------------------------------------------------------------------------------------------
    PLEASE, PLEASE specify the version of MODX you are using . . . PLEASE!
    MODx info for everyone: http://bobsguides.com/MODx.html


  • chrizz Reply #7, 4 months ago

    Reply
    Hi Bob,

    I tried to use the custom CRC tutorial.
    In a snippet I tried to access a field in my custom table with these lines:
    $oUG = $modx->getObject("ugallery_metadata", array());
    var_dump($oUG->get("price"));
    

    This works fine. But when I try to get the pagetitle the same way it returns null. I think the missing link between modResource (site_content) and my ugallery package is the reason.

    If I update or create a new resource using my custom CRC there is no possibility to access my custom table. If used mostly the code of the custom CRC tutorial.

    // filename: ugallerymeta.class.php
    
    require_once MODX_CORE_PATH.'model/modx/modprocessor.class.php';
    require_once MODX_CORE_PATH.'model/modx/processors/resource/create.class.php';
    require_once MODX_CORE_PATH.'model/modx/processors/resource/update.class.php';
    
    class ugalleryMeta extends modResource {
        
    	public $showInContextMenu = true;
        
        function __construct(xPDO & $xpdo) {
            parent :: __construct($xpdo);
            $this->set('class_key','ugallerymeta');
    		#echo "<pre>".print_r($this,true)."</pre>";
    		#die();
        }
    
        public static function getControllerPath(xPDO &$modx) {
            return $modx->getOption('ugallerymeta.core_path',null,$modx->getOption('core_path').'components/ugallerymeta/').'controllers/';
        }
    
        public function getContextMenuText() {
            $this->xpdo->lexicon->load('ugallerymeta:default');
            return array(
                'text_create' => $this->xpdo->lexicon('ugallerymeta'),
                'text_create_here' => $this->xpdo->lexicon('ugallerymeta_create_here'),
            );
        }
    
        public function getResourceTypeName() {
            $this->xpdo->lexicon->load('ugallerymeta:default');
            return $this->xpdo->lexicon('ugallerymeta');
        }
    
        public function getContent(array $options = array()) {
    		$content = parent::getContent($options);
            $year = date('Y');
            $content .= '<div class="copyright">© '.$year.'. All Rights Reserved. - KEKS</div>';
    		$content .= $this->get("price");
            return $content;
        }
    }
    
    
    class ugalleryMetaCreateProcessor extends modResourceCreateProcessor {
    }
    
    class ugalleryMetaUpdateProcessor extends modResourceUpdateProcessor {
        /**
         * Do any processing before the fields are set
         * @return boolean
         */
        public function beforeSet() {
            $beforeSet = parent::beforeSet();
            /**
            if ($this->getProperty('shouldBeTrue') == false) {
              $this->addFieldError('fieldname','The error message');
            }
            */
            return $beforeSet;
        }
    
        /**
         * Do any processing before the save of the Resource but after fields are set.
         * @return boolean
         */
        public function beforeSave() {
            $beforeSave = parent::beforeSave();
            if ($this->object->get('longtitle') == 'Send an Error') {
                $this->addFieldError('longtitle','Specify a different longtitle!');
            }
    		$this->object->set('content', "Replaced Content"); // works fine
    		$this->object->set('price', "123"); // no effect
            return $beforeSave;
        }
    
        /**
         * Do any custom after save processing
         * @return boolean
         */
        public function afterSave() {
            $afterSave = parent::afterSave();
            $this->modx->log(modX::LOG_LEVEL_DEBUG,'Saving a Copyrighted Page!');
            return $afterSave;
        }	
    }
    


    I think the mistake is between the php class, the xml schema and me...
    hopefully you have the time and you're in the mood to take a look at the code...
    thanks a lot!


  • BobRay Reply #8, 4 months ago

    Reply
    I think getObject() expects some criteria that specify a specific object in the array (not an empty array). It may not return a proper object without one.

    You can leave out the second argument with getCollection() and get all the objects, but you have to treat the return value as an array.



    ---------------------------------------------------------------------------------------------------------------
    PLEASE, PLEASE specify the version of MODX you are using . . . PLEASE!
    MODx info for everyone: http://bobsguides.com/MODx.html


  • chrizz Reply #9, 4 months ago

    Reply
    I think it's a little missunderstanding.
    Actually my problem is to link the table site_content with my custom table. Perhaps it's my mistake, but I thought, that I can insert a placeholder in my custom resources like .
    But even if I try to create or update a ugallerymeta resource my custom table keeps empty (even if I try to set the price field in the beforeSave method of the ugalleryMetaUpdateProcessor class which extends the modResourceUpdateProcessor)...



  • BobRay Reply #10, 4 months ago

    Reply
    This may not be related, but I've had trouble lately when I update or create DB records in code and then try to retrieve data immediately after that. I'm still trying to figure out why.


    ---------------------------------------------------------------------------------------------------------------
    PLEASE, PLEASE specify the version of MODX you are using . . . PLEASE!
    MODx info for everyone: http://bobsguides.com/MODx.html