Skip to main content

This site requires you to update your browser. Your browsing experience maybe affected by not having the most up to date version.

DataObjectManager Module

Discuss the DataObjectManager module, and the related ImageGallery module.

Moderators: martimiz, UncleCheese, Sean, biapar, Willr, Ingo, swaiba, simon_w

Preview: DataObjectManager module


Reply

379 Posts   61590 Views

Avatar
Ben Gribaudo

23 April 2009 at 12:24am (Last edited: 23 April 2009 12:25am), Community Member, 181 Posts

Hi Uncle Cheese,

I've run across a bug re ManyManyDataObjectManager's field list. Setting one up like this:

      $tablefield = new ManyManyDataObjectManager(
         $this,
         'Qualities',
         'QualityHomePage',
         array(
            'Title' => 'Quality',
            'Primary' => 'Primary'
         ),
         'getCMSFields_forPopup'
      );
      $tablefield->setParentClass('QuoteModel');
      $fields->addFieldToTab('Root.Main', $tablefield);


causes a SQL error. The problem is that the field array contains a field name of "Primary", which is a MySQL reserved word. MySQL requires that reserved words be escaped when used as field names in SQL. This isn't being done. The query being run looks like:

SELECT `SiteTree`.*, `QualityHomePage`.*, `SiteTree`.ID, if(`SiteTree`.ClassName,`SiteTree`.ClassName,'SiteTree') AS RecordClassName,
Primary,
IF(`QuoteModelID` IS NULL, '0', '1') AS Checked FROM `SiteTree` LEFT JOIN `QualityHomePage` ON `QualityHomePage`.ID = `SiteTree`.ID LEFT JOIN `QuoteModel_Qualities` ON (`SiteTree`.`ID` = `QualityHomePageID` AND `QuoteModelID` = '4') WHERE (`SiteTree`.ClassName IN ('QualityHomePage')) GROUP BY `SiteTree`.ID ORDER BY Sort LIMIT 0, 10

If I change the field type to ManyManyComplexTableField but don't otherwise change the arguments passed to the field's constructor, the resulting query looks like:

SELECT `SiteTree`.*, `QualityHomePage`.*, `SiteTree`.ID, if(`SiteTree`.ClassName,`SiteTree`.ClassName,'SiteTree') AS RecordClassName,
`Primary`,
IF(`QuoteModelID` IS NULL, '0', '1') AS Checked FROM `SiteTree` LEFT JOIN `QualityHomePage` ON `QualityHomePage`.ID = `SiteTree`.ID LEFT JOIN `QuoteModel_Qualities` ON (`SiteTree`.`ID` = `QualityHomePageID` AND `QuoteModelID` = '4') WHERE (`SiteTree`.ClassName IN ('QualityHomePage')) GROUP BY `SiteTree`.ID ORDER BY Sort LIMIT 0,10

So, ManyManyComplexTableField properly escapes the field with tick marks while ManyManyDataObjectManager doesn't. Would you be willing to fix this?

Thank you,
Ben

Avatar
UncleCheese

23 April 2009 at 1:27am 4085 Posts

@Ben - Thanks for flushing that out. I'll look into it. My guess is that it goes all the way up to DOM, since MMDOM differs only marginally from MMCTF.

@robinp - My apologies. In my previous message, I had mixed up your name with cmswarrior. The message to you was directed at him/her, and vice-versa. Glad you got it working. I'd like to make that a config setting but it's a little tricky converting PHP to Javascript. Did you find a setting that was more comfortable for you?

Avatar
micahsheets

23 April 2009 at 7:48am Community Member, 164 Posts

For anyone who cares, here is the solution I came up with for allowing a Prev and Next navigation of Testimonials while having the initial one be random.

I added this code to my TestimonialPage.php

   public function currentTestimonial() {
      $testimonials = DataObject::get("Testimonial","ClassName = 'Testimonial'");
      $tID = (int)$this->urlParams['Action'];
      if ($tID > $testimonials->Count()) {
         $tID = 1;
      }
      else if ($tID <= 0){
         $tID = $testimonials->Count();
      }
      
      if ($tID == 0){
         $tID = rand(1,$testimonials->Count());
         return $testimonials->find('ID',$tID);
      }
      else {
         return $testimonials->find('ID',$tID);
      }
   }
   
   protected function adjacentTestimonial($dir){
      $testimonials = DataObject::get("Testimonial","ClassName = 'Testimonial'");
      $i = (int)$this->urlParams['Action'];
      $t = $dir == "next" ? $i+1 : $i-1;
      if ($t > $testimonials->Count()) {
         $t = 1;
      }
      else if ($t <= 0){
         $t = $testimonials->Count();
      }
      return "/testimonials/$t";
   }
   
   public function NextTestimonial()
   {
      return $this->adjacentTestimonial("next");
   }

   public function PrevTestimonial()
   {
      return $this->adjacentTestimonial("prev");
   }

Works like a charm for my purposes. I don't know if there are any security issues with this. I did set it so that if someone types an incorrect value into the Action urlParam it will just put them at the first Testimonial.

Avatar
vstrazz

23 April 2009 at 8:29am Community Member, 63 Posts

@ UncleCheese I have tried to create a DataObjectManager in page.php that could be used in every page created in the CMS and all Sub classes of page.php

The problem is on regular pages the objects for that page appear in the manager correctly and any other page types all objects created in the CMS appear in the manager.

any ideas?

I did notice by adding

static $has_one = array (
"Home" => "HomePage",
);

to the "Feature" made the HomePage page type only show it's own objects.

here's the code

page.php

static $has_many = array(
"Featured" => "Feature"
);

function getCMSFields() {
      $fields = parent::getCMSFields();

$fields->addFieldToTab("Root.Content.Features", new DataObjectManager(
$this,
'Featured',
'Feature',
array(
'Title' => 'Title',
'Redirect'=> 'Links to'
),
'getCMSFields_forPopup'
));
      
      return $fields;
}

feature.php

class Feature extends DataObject
{
static $db = array (
'Title' => 'Text',
'Content' => 'HTMLText',
"Redirect" => "Varchar(255)",
"External" => "Boolean"

);

static $has_one = array (
'Pager' => 'Page',
"Home" => "HomePage",
"FeatureImage" => "Image",
"LinkTo" => "SiteTree"
);

public function getCMSFields_forPopup()
{
return new FieldSet(
new TextField('Title'),
new TextareaField('Content'),
new TextField("Redirect", "Link to this page"),
new CheckboxField("External", "Open link in New Window?"),
new ImageField("FeatureImage")
);
}
}

Avatar
robinp

24 April 2009 at 11:59am Community Member, 33 Posts

@UncleCheese yes I found setting that is working well for the large data based :-)

Avatar
UncleCheese

24 April 2009 at 5:03pm 4085 Posts

@vstrazz - If you want to use your dataobject manager on a subclass, make sure you set the parent class to clear up the ambiguity.

$manager->setParentClass("Page");

Avatar
hu

25 April 2009 at 5:44am Community Member, 21 Posts

@UncleCheese: Can you please change this in FileDataObjectManager.php. The getUploadFolder() {...} never get called.

public function UploadForm() {
   // Sync up the DB
   singleton('Folder')->syncChildren();
   $className = $this->sourceClass();
   $childData = new $className();
   $validator = $this->getValidatorFor($childData);
   if($this->Can('upload')) {
      SWFUploadConfig::addPostParams(array(
         'dataObjectClassName' => $this->sourceClass(),
         'dataObjectFieldName' => $this->dataObjectFieldName,
         'fileFieldName' => $this->fileFieldName,
         'fileClassName' => $this->fileClassName,
         'parentIDName' => $this->getParentIdName( $this->getParentClass(), $this->sourceClass() ),
         'controllerID' => $this->controllerID,
'OverrideUploadFolder' => $this->uploadFolder
         'OverrideUploadFolder' => $this->getUploadFolder()
      ));
}

Avatar
hu

25 April 2009 at 5:50am (Last edited: 25 April 2009 5:50am), Community Member, 21 Posts

@UncleCheese: And what do you think about the following feature:

...
$managerImages = new ImageDataObjectManager(
...
);      
$managerImages->setUploadFolder('Uploads/[ID]');
...

FileDataObjectManager.php

public function getUploadFolder()
{
   return str_replace("[ID]", $this->controllerID, $this->uploadFolder);
}