We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!
    • 22295
    • 153 Posts
    $parent->addOne($child,"ChildAlias");
    vs.
    $child.save();


    any difference?
    (composite+aggregate relationship handled also in save, no?)


    save() saves the object.
    addOne/Many formalize the relationship , or what exactly?
    (in that order of execution?)
    Short clarification would be thankful, as I am trying to validate the data integrity in a complex schema. Just trying some test cases, mainly around composite delete.


    Thanks.

    BTW: api.modxcms.com --> is nice to work with as reference, but not linkable. would have been to be able in this post to link to:
    API Doc --> xpdo --> om --> Classes --> xPDOObject --> #save

      • 28215
      • 4,149 Posts
      Quote from: oori at Nov 29, 2009, 07:28 PM

      $parent->addOne($child,"ChildAlias");
      $child.save();

      any difference?(composite+aggregate relationship handled also in save, no?)
      Yes; save() saves the object; addOne just adds the object $child to $parent as a related object. It doesn’t save until $parent->save() is called. This allows you some transactional ability.


      BTW: api.modxcms.com --> is nice to work with as reference, but not linkable. would have been to be able in this post to link to:
      API Doc --> xpdo --> om --> Classes --> xPDOObject --> #save
      http://api.modxcms.com/xpdo/om/xPDOObject.html#save

      That said, a "direct link" anchor would be nice.
        shaun mccormick | bigcommerce mgr of software engineering, former modx co-architect | github | splittingred.com
        • 22295
        • 153 Posts
        Thanks.
        This is great, so i only call save() at the end, as single commit.

        One place I had to do a save() before the proces is done is in this scenario:
        (you’ll recognize this from Register snippet)


        /* create user and profile */
        $user = $modx->newObject('memberUser');
        $user->fromArray($fields);
        
        $profile = $modx->newObject('modUserProfile');
        $profile->fromArray($fields);
        
        // must save user first to get back id, otherwise internalKey can not be set later.
        if (!$user->save()) {
            return $modx->lexicon('register.user_err_save');
        }
        
        $profile->set('internalKey',$user->get('id'));
        //$profile->save();  //   <--  this one CAN be bypassed, as later on there's a $user->save()
        $user->addOne($profile,'Profile');   // <----    better then save()
        
        ....
        .... all the rest of my custom addOne/addMany related to extended $user
        ....
        // everything was ok?    let's commit to database
        $user->save();   /* final user save to update relationships */
        



        This is "almost perfect", as in case of error after the first $user save(), but before the final, one must take care to remove that user record.

        I have this issue in another place, So - whenever internalKey (or alike) is to be set refering to the "parent", a parent->save() must be done to get the PK of the parent.
        Would be utopic if save() could auto-populate all the (internalKey). as the relationship is mapped - is this not possible?


        Side question: is there anything like getPlaceholders (note the ’s’ at the end), that would be very nice for debugging. for example, on a complex structure using ’$modx->getObjectGraph’, then later $modx->toPlaceholders. any way to print out all placeholders?

        thanks.
          • 28215
          • 4,149 Posts
          Quote from: oori at Nov 30, 2009, 03:57 PM

          Side question: is there anything like getPlaceholders (note the ’s’ at the end), that would be very nice for debugging. for example, on a complex structure using ’$modx->getObjectGraph’, then later $modx->toPlaceholders. any way to print out all placeholders?
          Yes:

          print_r($modx->placeholders);
          


          (Note this will print out Settings as well, as they are just placeholders with an extra + prefix.)
            shaun mccormick | bigcommerce mgr of software engineering, former modx co-architect | github | splittingred.com
            • 22295
            • 153 Posts
            thanks... print_r($modx->placeholders) is a bless.

            a. I found the above and a bunch more useful info in: http://api.modxcms.com/modx/modX.html

            b. On the same subject: whith Many relationship - to/setPlaceholders add the object’s PK as a between the suffix and the name.
            for example, this:
            $modx->toPlaceholders($memberUser->MemberLinks,'MemberLinks');

            would produce these:
            [MemberLinks.55.title] .... [MemberLinks.56.title]
            among a bunch of other placeholders..
            (in this example this member has two links with pk-id’s 55 & 56)
            This works, and in one line i get all placeholders, quite cool.
            but - is it possible to change the number-prefix from PK to chronological order (or my own custom method)?
            I need this: [MemberLinks.1.title] .... [MemberLinks.2.title]
            Simply - to sort 1,2,3,4... instead of PK.

            Actually - I don’t understand how one could use the PK based naming for template designs...
            The current solution i see is using foreach to iterate one by one, then the number-prefix is not added by modx. but, we’re all about code-aesthetics here, no?
            i thought, usort($memberUser->MemberLinks,"cmpFunc"), but doesn’t run..



            c. In regards to the main question (internalKey,save(),db transactional) - As I examined your code (both login addon and the build-in connectors), I see there’s no trick solution there. I guess this one should simply be resolved in my code itself (handle error --> remove created objects).
            I would be happy to know if you have a better idea to tackle this.

            well, this solves it easy: $user->remove() after error occurs...


            Thanks again for your quick replies!
              • 22295
              • 153 Posts
              (I answer myself to question b)

              this function resolves it:

              /*  same as toPlaceholders, but naming in 1.2.3.4.. order, and not PK-based (as toPlaceholderS)  */
              function chronologicalPlaceholder($parentObj,$alias,$prefix) {
              	global $modx;
              	if (!isset($prefix)) {$prefix = $alias;}	// default to use alias as placeholder prefix
              	$childs = $parentObj->getMany($alias);	// get all children
              	sort($childs);			//change array's keys  to 0,1,2,etc...
              	array_unshift($childs,array());   	// add empty one, simply so the numbering will start from 1 and not 0
              	$modx->toPlaceholders($childs,$prefix,".");	// generate modx placeholders for templates
              	return $childs;	// return the array, needed for recursive placeholder (grandchildren relationship or more)
              }





              called like this:
              /* add your schema */
              $model_path = $modx->getOption('core_path', $properties, MODX_CORE_PATH).'components/yourName/model/';
              $modx->addPackage('yourSchemaName',$model_path);
              
              $memberSchemaDef = '{"Profile":{},"MemberLinks":{}}';
              // and so on.... add all your salat here...   note:  doesn't support grandchildren or deeper (although looks like it should, by design...)
              
              
              /* get extended user object */
              $memberUser = $modx->getObjectGraph('memberUser', $memberSchemaDef , $userId);
              if (!isset($memberUser)) {return;}   // if empty?  quit.
              
              $modx->toPlaceholders($memberUser->Profile,'Profile');   // simple example, "profile" has 'one' relationship with modUser
              chronologicalPlaceholder($memberUser,"MemberResidencies");   // has 'many' relationship with modUser (well actually to "memberUser" object that extends "modUser"
              



              This will dump the placeholders in 1,2,3,4... order






              btw, for grandchildren, i use this:
              $skGroups = chronologicalPlaceholder($memberUser,"MemberSkillGroups");   
              foreach ($skGroups as $i => $skGroup) {
              	if (count($skGroup) > 0) {    // has any professions?
              		chronologicalPlaceholder($skGroup,"Professions","MemberSkillGroups.".$i.".Profession"); 
              	}
              }
              


              (where the logic is: MemberUser [has many] MemberSkillGroups [has many] Professions)
              for example, this would produce a placeholder that looks like this:
              [MemberSkillGroups.1.Profession.2.name]

              For my case, the custom user data is presented all around the site in fragments (in the user’s profile page - all info, in other places - just some info about him).
              The above is very comfortable for template design, as it’s static name(unlike the toPlaceholders which names then based on the PK).


              Good luck.