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.

We've moved the forum!

Please use forum.silverstripe.org for any new questions (announcement).
The forum archive will stick around, but will be read only.

You can also use our Slack channel or StackOverflow to ask for help.
Check out our community overview for more options to contribute.

DataObjectManager Module /

Discuss the DataObjectManager module, and the related ImageGallery module.

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

Preview: DataObjectManager module


Go to End


379 Posts   95930 Views

Avatar
Ben Gribaudo

Community Member, 181 Posts

23 April 2009 at 12:24am

Edited: 23/04/2009 12:25am

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

Forum Moderator, 4102 Posts

23 April 2009 at 1:27am

@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

Community Member, 165 Posts

23 April 2009 at 7:48am

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

Community Member, 63 Posts

23 April 2009 at 8:29am

@ 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

Community Member, 33 Posts

24 April 2009 at 11:59am

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

Avatar
UncleCheese

Forum Moderator, 4102 Posts

24 April 2009 at 5:03pm

@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

Community Member, 21 Posts

25 April 2009 at 5:44am

@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

Community Member, 21 Posts

25 April 2009 at 5:50am

Edited: 25/04/2009 5:50am

@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);
}

Go to Top