We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!
    • 30585
    • 833 Posts
    Hi all,

    I'm using a form to save quotation requests into two related database tables: modx_quotes_customers and modx_quotes_requests. When submitted, the form is either reloading or producing a 500 ERROR and in both cases, no objects are saved. When I remove the hook from the Formit call, the form processes without a glitch.

    I'm hoping someone can shed some light on what may be wrong with my logic.

    The hook:
    <?php
    
    /** @var ecQuotes $ecquotes */
    $ecq = $modx->getService('ecquotes', 'ecQuotes', $modx->getOption('ecquotes.core_path', null, $modx->getOption('core_path') . 'components/ecquotes/') . 'model/ecquotes/', $scriptProperties);
    
    if (!($ecq instanceof ecQuotes)) {
        $ecq->logError($snippet, 'Failed to load class: ecQuotes.');
        return '';
    }
    
    $formFields = array();
    $formFields = $hook->getValues();
    $custFields = $ecq->getCustomerFields($formFields);
    $reqFields  = $ecq->getRequestFields($formFields);
    
    $custObj = $modx->newObject('QuoteCustomer', $custFields);
    $reqObj  = $modx->newObject('QuoteRequest', $reqFields);
    $reqObj->addOne($custObj);
    
    if (!is_object($reqObj) || !($reqObj instanceof xPDOObject)) {
      $ecq->logError($snippet, 'Failed to create object.');
      return false;
    }
    
    if (!$reqObj->save()) {
        $ecq->logError($snippet, 'An error occured while saving object: QuoteRequest.');
        return false;
    }
    
    return true;


    The getCustomerFields() method (which is similar to the getRequestFields method, except the fields are different):

        
      /**
         * Get customer form field values
         *
         * @param array $fields a collection of the Formit fields
         */
        public function getCustomerFields(array $fields)
        {
            $this->custFields = array(
                'firstname' => $fields['firstname'],
                'lastname' => $fields['lastname'],
                'email' => $fields['email'],
                'phone' => $fields['phone'],
                'company' => $fields['company'],
                'website' => $fields['website']
            );
            return $this->custFields;
        }


    Schema and form code available upon request.

    Thanks in advance!

    This question has been answered by BobRay. See the first response.

    [ed. note: treigh last edited this post 7 years, 3 months ago.]
      A MODx Fanatic
      • 3749
      • 24,544 Posts
      For some objects, you can't include all the fields in the newObect() call.

      Try this:

      $custObj = $modx->newObject('QuoteCustomer');
      $custObj->fromArray($custFields);
      

      If that doesn't work, instead of fromArray(), try this:

      $custObj = $modx->newObject('QuoteCustomer');
      $custObj->set('firstname', $fields['firstname']);
      $custObj->set('lastname', $fields['lastname']);
      // etc.




        Did I help you? Buy me a beer
        Get my Book: MODX:The Official Guide
        MODX info for everyone: http://bobsguides.com/modx.html
        My MODX Extras
        Bob's Guides is now hosted at A2 MODX Hosting
        • 30585
        • 833 Posts
        Thanks for this Bob. I'll give it a spin right away and report back.
          A MODx Fanatic
          • 30585
          • 833 Posts
          Hi Bob, I've tried all your suggestions, but so far no luck. I even tried hard-coding form values, but nothing:
          $reqObj = $modx->newObject('QuoteRequest');
          $reqObj->set('servicedate', 1482813786);
          $reqObj->set('city_pickup', 'Townsville');
          
          $custObj = $modx->newObject('QuoteCustomer');
          $custObj->set('firstname', 'John');
          $custObj->set('lastname', 'Doe');


          Strange enough, I was able to create and save objects with a test snippet.

          [ed. note: treigh last edited this post 7 years, 3 months ago.]
            A MODx Fanatic
          • discuss.answer
            • 3749
            • 24,544 Posts
            It sounds like addOne() is failing. That suggests that either it needs the object's alias as the second argument to addOne, or that your schema doesn't set up the related object properly (e.g., improper foreign key or cardinality). Note that when you change the schema, you have to regenerate the class and map files -- MODX ignores the schema at run time.

            Another option, is to set the foreign key field of the related object yourself and just call:

            $custObj->save();


            It's preferable, though, to get the related object set up properly so things like getObjectGraph() will work on it.
              Did I help you? Buy me a beer
              Get my Book: MODX:The Official Guide
              MODX info for everyone: http://bobsguides.com/modx.html
              My MODX Extras
              Bob's Guides is now hosted at A2 MODX Hosting
              • 30585
              • 833 Posts
              That sounds right. After further tweaks, I'm now getting this error:

              [2016-12-27 00:31:04] (ERROR @ /Users/path/core/xpdo/xpdo.class.php : 643) Could not load class: QuoteCustomer from mysql.quotecustomer.
              [2016-12-27 00:31:04] (ERROR @ /Users/path/core/xpdo/xpdo.class.php : 643) Could not load class: QuoteRequest from mysql.quoterequest.
              

              I'll examine the schema and regenerate files.
                A MODx Fanatic
                • 30585
                • 833 Posts
                Hi Bob, if you're still around, this exact same code fails in the hook, but it creates and saves objects just fine when used as a normal snippet:

                $custObj = $modx->newObject('QuoteCustomer', array(
                'firstname' => 'John',
                'lastname' => 'Doe',
                'email' => '[email protected]',
                'phone' => '212-555-5555'
                ));
                $reqObj = $modx->newObject('QuoteRequest', array(
                'servicedate' => strtotime('2016-12-29'),
                'streetnumber_pickup' => 6,
                'streetname_pickup' => 'Avenue Road'
                ));
                
                $reqObj->addOne($custObj);
                
                if (!is_object($reqObj) || !($reqObj instanceof xPDOObject)) {
                  $ecq->logError($snippet, 'Failed to create object.');
                  return false;
                }
                 
                if (!$reqObj->save()) {
                    $ecq->logError($snippet, 'An error occured while saving object: QuoteRequest.');
                    return false;
                }
                return true;
                


                I should probably just drop this silly hook business and use a regular snippet to save the data, then use Formit for via runSnippet for the rest.

                ---

                For the record, here's a snapshot of the schema file and I can't see a relationship issues in it:

                <?xml version="1.0" encoding="UTF-8"?>
                <model package="ecquotes" baseClass="xPDOObject" platform="mysql" defaultEngine="MyISAM" version="1.1">
                    <object class="QuoteCustomer" table="ecquotes_customers" extends="xPDOSimpleObject">
                        <field key="firstname" dbtype="varchar" precision="100" phptype="string" null="false" default=""/>
                        <field key="lastname" dbtype="varchar" precision="100" phptype="string" null="false" default=""/>
                        ...
                
                        <composite alias="Request" class="QuoteRequest" local="id" foreign="customer" cardinality="many" owner="local"/>
                        <composite alias="Process" class="QuoteProcess" local="id" foreign="customer" cardinality="many" owner="local"/>
                        <composite alias="Booking" class="QuoteBooking" local="id" foreign="customer" cardinality="many" owner="local"/>
                    </object>
                    <object class="QuoteRequest" table="ecquotes_requests" extends="xPDOSimpleObject">
                        <field key="customer" dbtype="int" precision="10" phptype="integer" null="false" default=""/>
                        ...
                        <aggregate alias="Customer" class="QuoteCustomer" local="customer" foreign="id" cardinality="one" owner="foreign"/>
                        <composite alias="Process" class="QuoteProcess" local="id" foreign="request" cardinality="many" owner="local"/>
                        <composite alias="Booking" class="QuoteBooking" local="id" foreign="request" cardinality="many" owner="local"/>
                    </object>
                ...
                </model>
                
                  A MODx Fanatic
                  • 3749
                  • 24,544 Posts
                  FYI, if you want to do further checking, newObject() returns null if it fails, addOne() returns false if it fails.

                  I'm curious about what exactly is failing here.

                  I'm also wondering if loading the classes would help. The class autoloader may not be available in a plugin.
                    Did I help you? Buy me a beer
                    Get my Book: MODX:The Official Guide
                    MODX info for everyone: http://bobsguides.com/modx.html
                    My MODX Extras
                    Bob's Guides is now hosted at A2 MODX Hosting
                    • 30585
                    • 833 Posts
                    Thanks for the tips Bob. I'll do some additional checks this evening to see what's really going on and I'll be sure to report back.
                      A MODx Fanatic