public function doAllChildrenIncludingDeleted($context = null) { if (!$this->owner) { user_error('Hierarchy::doAllChildrenIncludingDeleted() called without $this->owner'); } $baseClass = ClassInfo::baseDataClass($this->owner->class); if ($baseClass) { $stageChildren = $this->owner->stageChildren(true); $stageChildren = $this->RemoveNewsPostsFromSiteTree($stageChildren); // Add live site content that doesn't exist on the stage site, if required. if ($this->owner->hasExtension('Versioned')) { // Next, go through the live children. Only some of these will be listed $liveChildren = $this->owner->liveChildren(true, true); if ($liveChildren) { $liveChildren = $this->RemoveNewsPostsFromSiteTree($liveChildren); $merged = new ArrayList(); $merged->merge($stageChildren); $merged->merge($liveChildren); $stageChildren = $merged; } } $this->owner->extend("augmentAllChildrenIncludingDeleted", $stageChildren, $context); } else { user_error("Hierarchy::AllChildren() Couldn't determine base class for '{$this->owner->class}'", E_USER_ERROR); } return $stageChildren; }
public function stageChildren($showAll = false) { $children = new ArrayList(); $repo = $this->source->getRemoteRepository(); try { if ($repo->isConnected()) { $ssId = $this->getSS_ID(); if (!$ssId) { $ssId = '0'; } $kids = $repo->getChildren(array('ClassName' => ClassInfo::baseDataClass($this->getType()), 'ParentID' => $this->getSS_ID())); if (!$kids) { throw new Exception("No kids and null object returned for children of " . $this->getSS_ID()); } // Even though it returns actual dataobjects, we need to wrap them for sanity and safety's sake foreach ($kids as $childItem) { $item = $this->source->getObject($childItem); $children->push($item); } } } catch (Exception $fre) { SS_Log::log($fre, SS_Log::WARN); return $children; } return $children; }
/** * Get the appropriate {@link CatalogueProductController} or * {@link CatalogueProductController} for handling the relevent * object. * * @param $object Either Product or Category object * @param string $action * @return CatalogueController */ protected static function controller_for($object, $action = null) { if ($object->class == 'CatalogueProduct') { $controller = "CatalogueProductController"; } elseif ($object->class == 'CatalogueCategory') { $controller = "CatalogueCategoryController"; } else { $ancestry = ClassInfo::ancestry($object->class); while ($class = array_pop($ancestry)) { if (class_exists($class . "_Controller")) { break; } } // Find the controller we need, or revert to a default if ($class !== null) { $controller = "{$class}_Controller"; } elseif (ClassInfo::baseDataClass($object->class) == "CatalogueProduct") { $controller = "CatalogueProductController"; } elseif (ClassInfo::baseDataClass($object->class) == "CatalogueCategory") { $controller = "CatalogueCategoryController"; } } if ($action && class_exists($controller . '_' . ucfirst($action))) { $controller = $controller . '_' . ucfirst($action); } return class_exists($controller) ? Injector::inst()->create($controller, $object) : $object; }
public function testApplyReplationDeepInheretence() { //test has_one relation $newDQ = new DataQuery('DataQueryTest_E'); //apply a relation to a relation from an ancestor class $newDQ->applyRelation('TestA'); $this->assertTrue($newDQ->query()->isJoinedTo('DataQueryTest_C')); $this->assertContains('"DataQueryTest_A"."ID" = "DataQueryTest_C"."TestAID"', $newDQ->sql($params)); //test many_many relation //test many_many with separate inheritance $newDQ = new DataQuery('DataQueryTest_C'); $baseDBTable = ClassInfo::baseDataClass('DataQueryTest_C'); $newDQ->applyRelation('ManyTestAs'); //check we are "joined" to the DataObject's table (there is no distinction between FROM or JOIN clauses) $this->assertTrue($newDQ->query()->isJoinedTo($baseDBTable)); //check we are explicitly selecting "FROM" the DO's table $this->assertContains("FROM \"{$baseDBTable}\"", $newDQ->sql()); //test many_many with shared inheritance $newDQ = new DataQuery('DataQueryTest_E'); $baseDBTable = ClassInfo::baseDataClass('DataQueryTest_E'); //check we are "joined" to the DataObject's table (there is no distinction between FROM or JOIN clauses) $this->assertTrue($newDQ->query()->isJoinedTo($baseDBTable)); //check we are explicitly selecting "FROM" the DO's table $this->assertContains("FROM \"{$baseDBTable}\"", $newDQ->sql(), 'The FROM clause is missing from the query'); $newDQ->applyRelation('ManyTestGs'); //confirm we are still joined to the base table $this->assertTrue($newDQ->query()->isJoinedTo($baseDBTable)); //double check it is the "FROM" clause $this->assertContains("FROM \"{$baseDBTable}\"", $newDQ->sql(), 'The FROM clause has been removed from the query'); //another (potentially less crude check) for checking "FROM" clause $fromTables = $newDQ->query()->getFrom(); $this->assertEquals('"' . $baseDBTable . '"', $fromTables[$baseDBTable]); }
protected function onBeforeWrite() { if ($this->isChanged('ParentClass')) { $this->ParentClass = ClassInfo::baseDataClass($this->ParentClass); } parent::onBeforeWrite(); }
public function getManipulatedData(GridField $gridField, SS_List $list) { if (!$list instanceof RelationList) { user_error('GridFieldManyRelationHandler requires the GridField to have a RelationList. Got a ' . get_class($list) . ' instead.', E_USER_WARNING); } $state = $this->getState($gridField); // We don't use setupState() as we need the list if ($state->FirstTime) { $state->RelationVal = array_values($list->getIdList()) ?: array(); } if (!$state->ShowingRelation && $this->useToggle) { return $list; } $query = clone $list->dataQuery(); try { $query->removeFilterOn($this->cheatList->getForeignIDFilter($list)); } catch (InvalidArgumentException $e) { /* NOP */ } $orgList = $list; $list = new DataList($list->dataClass()); $list = $list->setDataQuery($query); if ($orgList instanceof ManyManyList) { $joinTable = $this->cheatManyList->getJoinTable($orgList); $baseClass = ClassInfo::baseDataClass($list->dataClass()); $localKey = $this->cheatManyList->getLocalKey($orgList); $query->leftJoin($joinTable, "\"{$joinTable}\".\"{$localKey}\" = \"{$baseClass}\".\"ID\""); $list = $list->setDataQuery($query); } return $list; }
/** * @return array */ public function find() { $base_entity = singleton($this->table_name); $relation_name = $this->alias->getName(); $class_name = ClassInfo::baseDataClass($this->table_name); $subclasses = array_keys(ClassInfo::subclassesFor($class_name)); do { // relationships ... $has_many = Config::inst()->get($class_name, 'has_many'); $has_many_many = Config::inst()->get($class_name, 'many_many'); $has_one = Config::inst()->get($class_name, 'has_one'); $belongs_many_many = Config::inst()->get($class_name, 'belongs_many_many'); if (!is_null($has_many) && array_key_exists($relation_name, $has_many)) { break; } if (!is_null($has_one) && array_key_exists($relation_name, $has_one)) { break; } if (!is_null($has_many_many) && array_key_exists($relation_name, $has_many_many)) { break; } if (!is_null($belongs_many_many) && array_key_exists($relation_name, $belongs_many_many)) { break; } $class_name = array_pop($subclasses); if (is_null($class_name)) { // we arrive to the end of the hierarchy and didnt find any relation with that name throw new InvalidArgumentException(sprintf(' relation %s does not exist for %s', $relation_name, $this->table_name)); } $base_entity = singleton($class_name); } while (true); return array($base_entity, $has_one, $has_many, $has_many_many, $belongs_many_many); }
public function handleBatchAction($request) { // This method can't be called without ajax. if (!$request->isAjax()) { $this->parentController->redirectBack(); return; } // Protect against CSRF on destructive action if (!SecurityToken::inst()->checkRequest($request)) { return $this->httpError(400); } $actions = $this->batchActions(); $actionClass = $actions[$request->param('BatchAction')]['class']; $actionHandler = new $actionClass(); // Sanitise ID list and query the database for apges $ids = preg_split('/ *, */', trim($request->requestVar('csvIDs'))); foreach ($ids as $k => $v) { if (!is_numeric($v)) { unset($ids[$k]); } } if ($ids) { if (class_exists('Translatable') && SiteTree::has_extension('Translatable')) { Translatable::disable_locale_filter(); } $pages = DataObject::get($this->recordClass, sprintf('"%s"."ID" IN (%s)', ClassInfo::baseDataClass($this->recordClass), implode(", ", $ids))); if (class_exists('Translatable') && SiteTree::has_extension('Translatable')) { Translatable::enable_locale_filter(); } $record_class = $this->recordClass; if ($record_class::has_extension('Versioned')) { // If we didn't query all the pages, then find the rest on the live site if (!$pages || $pages->Count() < sizeof($ids)) { foreach ($ids as $id) { $idsFromLive[$id] = true; } if ($pages) { foreach ($pages as $page) { unset($idsFromLive[$page->ID]); } } $idsFromLive = array_keys($idsFromLive); $sql = sprintf('"%s"."ID" IN (%s)', $this->recordClass, implode(", ", $idsFromLive)); $livePages = Versioned::get_by_stage($this->recordClass, 'Live', $sql); if ($pages) { // Can't merge into a DataList, need to condense into an actual list first // (which will retrieve all records as objects, so its an expensive operation) $pages = new ArrayList($pages->toArray()); $pages->merge($livePages); } else { $pages = $livePages; } } } } else { $pages = new ArrayList(); } return $actionHandler->run($pages); }
function ItemEditForm() { $form = parent::ItemEditForm(); $actions = $form->Actions(); $majorActions = CompositeField::create()->setName('MajorActions')->setTag('fieldset')->addExtraClass('ss-ui-buttonset'); $rootTabSet = new TabSet('ActionMenus'); $moreOptions = new Tab('MoreOptions', _t('SiteTree.MoreOptions', 'More options', 'Expands a view for more buttons')); $rootTabSet->push($moreOptions); $rootTabSet->addExtraClass('ss-ui-action-tabset action-menus'); // Render page information into the "more-options" drop-up, on the top. $baseClass = ClassInfo::baseDataClass($this->record->class); $live = Versioned::get_one_by_stage($this->record->class, 'Live', "\"{$baseClass}\".\"ID\"='{$this->record->ID}'"); $existsOnLive = $this->record->getExistsOnLive(); $published = $this->record->isPublished(); $moreOptions->push(new LiteralField('Information', $this->record->customise(array('Live' => $live, 'ExistsOnLive' => $existsOnLive))->renderWith('SiteTree_Information'))); $actions->removeByName('action_doSave'); $actions->removeByName('action_doDelete'); if ($this->record->canEdit()) { if ($this->record->IsDeletedFromStage) { if ($existsOnLive) { $majorActions->push(FormAction::create('revert', _t('CMSMain.RESTORE', 'Restore'))); if ($this->record->canDelete() && $this->record->canDeleteFromLive()) { $majorActions->push(FormAction::create('unpublish', _t('CMSMain.DELETEFP', 'Delete'))->addExtraClass('ss-ui-action-destructive')); } } else { if (!$this->record->isNew()) { $majorActions->push(FormAction::create('restore', _t('CMSMain.RESTORE', 'Restore'))->setAttribute('data-icon', 'decline')); } else { $majorActions->push(FormAction::create('save', _t('SiteTree.BUTTONSAVED', 'Saved'))->addExtraClass('ss-ui-alternate ss-ui-action-constructive')->setAttribute('data-icon', 'accept')->setAttribute('data-icon-alternate', 'addpage')->setAttribute('data-text-alternate', _t('CMSMain.SAVEDRAFT', 'Save draft'))->setUseButtonTag(true)); $majorActions->push(FormAction::create('publish', _t('SiteTree.BUTTONPUBLISHED', 'Published'))->addExtraClass('ss-ui-alternate ss-ui-action-constructive')->setAttribute('data-icon', 'accept')->setAttribute('data-icon-alternate', 'disk')->setAttribute('data-text-alternate', _t('SiteTree.BUTTONSAVEPUBLISH', 'Save & publish'))->setUseButtonTag(true)); } } } else { if ($this->record->canDelete() && !$published) { $moreOptions->push(FormAction::create('delete', _t('SiteTree.BUTTONDELETE', 'Delete draft'))->addExtraClass('ss-ui-action-destructive')->setUseButtonTag(true)); } $majorActions->push(FormAction::create('save', _t('SiteTree.BUTTONSAVED', 'Saved'))->setAttribute('data-icon', 'accept')->setAttribute('data-icon-alternate', 'addpage')->setAttribute('data-text-alternate', _t('CMSMain.SAVEDRAFT', 'Save draft'))->setUseButtonTag(true)); } } $publish = FormAction::create('publish', $published ? _t('SiteTree.BUTTONPUBLISHED', 'Published') : _t('SiteTree.BUTTONSAVEPUBLISH', 'Save & publish'))->setAttribute('data-icon', 'accept')->setAttribute('data-icon-alternate', 'disk')->setAttribute('data-text-alternate', _t('SiteTree.BUTTONSAVEPUBLISH', 'Save & publish'))->setUseButtonTag(true); if (!$published || $this->record->stagesDiffer('Stage', 'Live') && $published) { $publish->addExtraClass('ss-ui-alternate'); } if ($this->record->canPublish() && !$this->record->IsDeletedFromStage) { $majorActions->push($publish); } if ($published && $this->record->canPublish() && !$this->record->IsDeletedFromStage && $this->record->canDeleteFromLive()) { $moreOptions->push(FormAction::create('unpublish', _t('SiteTree.BUTTONUNPUBLISH', 'Unpublish'), 'delete')->addExtraClass('ss-ui-action-destructive')->setUseButtonTag(true)); } if ($this->record->stagesDiffer('Stage', 'Live') && !$this->record->IsDeletedFromStage && $this->record->isPublished() && $this->record->canEdit()) { $moreOptions->push(FormAction::create('rollback', _t('SiteTree.BUTTONCANCELDRAFT', 'Cancel draft changes'))->setDescription(_t('SiteTree.BUTTONCANCELDRAFTDESC', 'Delete your draft and revert to the currently published page'))->setUseButtonTag(true)); } $actions->push($majorActions); $actions->push($rootTabSet); if ($this->record->hasMethod('getCMSValidator')) { $form->setValidator($this->record->getCMSValidator()); } return $form; }
/** * @param SQLQuery $query * @param DataQuery $dataQuery */ function augmentSQL(SQLQuery &$query, DataQuery &$dataQuery = null) { $baseTable = ClassInfo::baseDataClass($dataQuery->dataClass()); if (class_exists('Subsite')) { $currentSubsiteID = Subsite::currentSubsiteID(); $query->addWhere("\"{$baseTable}\".\"SubsiteID\" = '{$currentSubsiteID}'"); } }
/** * @covers ClassInfo::baseDataClass() */ public function testBaseDataClass() { $this->assertEquals('ClassInfoTest_BaseClass', ClassInfo::baseDataClass('ClassInfoTest_BaseClass')); $this->assertEquals('ClassInfoTest_BaseClass', ClassInfo::baseDataClass('ClassInfoTest_ChildClass')); $this->assertEquals('ClassInfoTest_BaseClass', ClassInfo::baseDataClass('ClassInfoTest_GrandChildClass')); $this->setExpectedException('InvalidArgumentException'); ClassInfo::baseDataClass('DataObject'); }
public function onAfterPublish() { if (isset($this->owner->temp__ChangeablePublishDateValue)) { $this->owner->LastEdited = $this->owner->temp__ChangeablePublishDateValue; unset($this->owner->temp__ChangeablePublishDateValue); $table_name = ClassInfo::baseDataClass($this->owner->ClassName); //Get the class name which holds the 'LastEdited' field. Might be for example 'SiteTree'. DB::query('UPDATE ' . $table_name . " SET PublishDate = '" . Convert::raw2sql($this->owner->PublishDate) . "' WHERE ID = " . intval($this->owner->ID) . ' LIMIT 1'); } }
/** * Get the products customers also bought * (Haha so many sub queries...) * * @return \SS_List */ public function CustomersAlsoBought() { if (($orderItemClass = $this->owner->config()->order_item) && ($orderItem = singleton($orderItemClass)) && ($buyableRel = $orderItem->owner->config()->buyable_relationship)) { $buyableRel = $buyableRel . 'ID'; $baseClass = \ClassInfo::baseDataClass($this->owner); // Had to use EXISTS because IN () not compatible with SS DataModel return $this->owner->get()->where('EXISTS(' . \DataList::create($orderItemClass)->where('EXISTS(' . str_replace(['FROM "OrderAttribute"', '"OrderAttribute".', 'OrderAttribut||e'], ['FROM "OrderAttribute" AS "OrderAttribute1"', '"OrderAttribute1".', 'OrderAttribute'], \DataList::create($orderItemClass)->leftJoin('Order', "\"OrderAttribute\".\"OrderID\" = \"Order\".\"ID\"")->where("\"{$buyableRel}\" = {$this->owner->ID}")->where('"Order"."Status" != \'Cart\'')->where('"OrderAttribute1"."OrderID" = "OrderAttribut||e"."OrderID"')->dataQuery()->getFinalisedQuery(['"OrderAttribute"."OrderID"'])->sql()) . ')')->where("\"{$buyableRel}\" != " . $this->owner->ID)->where("\"{$baseClass}\".\"ID\" = \"{$orderItemClass}\".\"{$buyableRel}\"")->dataQuery()->getFinalisedQuery([$buyableRel])->sql() . ')'); } return \ArrayList::create(); }
/** * Return an existing or new ViewCount record. * * @return ViewCount */ public function ViewCount() { $data = array('RecordID' => $this->owner->ID, 'RecordClass' => ClassInfo::baseDataClass($this->owner->ClassName)); $count = ViewCount::get()->filter($data)->First(); if (!$count) { $count = new ViewCount(); $count->update($data); } return $count; }
/** * @covers ClassInfo::baseDataClass() */ public function testBaseDataClass() { $this->assertEquals('ClassInfoTest_BaseClass', ClassInfo::baseDataClass('ClassInfoTest_BaseClass')); $this->assertEquals('ClassInfoTest_BaseClass', ClassInfo::baseDataClass('classinfotest_baseclass')); $this->assertEquals('ClassInfoTest_BaseClass', ClassInfo::baseDataClass('ClassInfoTest_ChildClass')); $this->assertEquals('ClassInfoTest_BaseClass', ClassInfo::baseDataClass('CLASSINFOTEST_CHILDCLASS')); $this->assertEquals('ClassInfoTest_BaseClass', ClassInfo::baseDataClass('ClassInfoTest_GrandChildClass')); $this->assertEquals('ClassInfoTest_BaseClass', ClassInfo::baseDataClass('ClassInfoTest_GRANDChildClass')); $this->setExpectedException('InvalidArgumentException'); ClassInfo::baseDataClass('DataObject'); }
/** * @refactor move to SQLQuery * @todo fix hack */ protected function applyBaseTableFields() { $classes = ClassInfo::dataClassesFor($this->modelClass); $fields = array("`" . ClassInfo::baseDataClass($this->modelClass) . '`.*'); if ($this->modelClass != $classes[0]) { $fields[] = '`' . $classes[0] . '`.*'; } //$fields = array_keys($model->db()); $fields[] = '`' . $classes[0] . '`.ClassName AS RecordClassName'; return $fields; }
/** * @return JoinSpecification[] */ public function build() { $specs = array(); $relation_name = $this->alias->getName(); $child_class = $this->relations[$relation_name]; $child_hierarchy = ClassInfo::dataClassesFor($child_class); $base_child_class = array_shift($child_hierarchy); $class_name = ClassInfo::baseDataClass($this->base_entity); $specs[] = new JoinSpecification($child_class, $child_class . '.ID = ' . $class_name . '.' . $relation_name . 'ID'); $this->base_table = $base_child_class; return $specs; }
/** * Duplicated & renamed from the Hierarchy::liveChildren() because we're overriding the original method: * Return children from the live site, if it exists. * * @param boolean $showAll Include all of the elements, even those not shown in the menus. * (only applicable when extension is applied to {@link SiteTree}). * @param boolean $onlyDeletedFromStage Only return items that have been deleted from stage * @return SS_List */ public function hierarchyLiveChildren($showAll = false, $onlyDeletedFromStage = false) { if (!$this->owner->hasExtension('Versioned')) { throw new Exception('Hierarchy->liveChildren() only works with Versioned extension applied'); } $baseClass = ClassInfo::baseDataClass($this->owner->class); $children = $baseClass::get()->filter('ParentID', (int) $this->owner->ID)->exclude('ID', (int) $this->owner->ID)->setDataQueryParam(array('Versioned.mode' => $onlyDeletedFromStage ? 'stage_unique' : 'stage', 'Versioned.stage' => 'Live')); if (!$showAll) { $children = $children->filter('ShowInMenus', 1); } return $children; }
/** * Add in rating information * * @param SQLQuery $query * @param DataQuery $dataQuery */ public function augmentSQL(SQLQuery &$query) { $base = ClassInfo::baseDataClass($this->owner); $simple = DB::getConn() instanceof SQLite3Database ? true : false; if ($simple) { $bound = '((Up / Down) / (Up + Down))'; } else { $bound = '((Up + 1.9208) / (Up + Down) - ' . '1.96 * SQRT((Up * Down) / (Up + Down) + 0.9604) / ' . '(Up + Down)) / (1 + 3.8416 / (Up + Down)) / SQRT(HOUR(TIMEDIFF(NOW(), ' . $base . '.Created)) + 1)'; } $query->selectField($bound, 'WilsonRating'); $query->selectField('(Up + Down)', 'ActiveRating'); $query->selectField('(Up - Down)', 'PositiveRating'); }
/** * Augments (@link Hierarchy::liveChildren()} by hiding excluded child classnames * * @param boolean $showAll Include all of the elements, even those not shown in the menus. * (only applicable when extension is applied to {@link SiteTree}). * @param boolean $onlyDeletedFromStage Only return items that have been deleted from stage * @return SS_List */ public function liveChildren($showAll = false, $onlyDeletedFromStage = false) { $baseClass = ClassInfo::baseDataClass($this->owner->class); $children = $baseClass::get()->filter('ParentID', (int) $this->owner->ID)->exclude('ID', (int) $this->owner->ID)->setDataQueryParam(array('Versioned.mode' => $onlyDeletedFromStage ? 'stage_unique' : 'stage', 'Versioned.stage' => 'Live')); if (!$showAll) { $children = $children->filter('ShowInMenus', 1); } if ($this->shouldFilter()) { // Filter the SiteTree return $children->exclude("ClassName", $this->owner->getExcludedSiteTreeClassNames()); } return $children; }
function handleAction($request) { // This method can't be called without ajax. if (!$this->parentController->isAjax()) { $this->parentController->redirectBack(); return; } $actions = $this->batchActions(); $actionClass = $actions[$request->param('BatchAction')]['class']; $actionHandler = new $actionClass(); // Sanitise ID list and query the database for apges $ids = split(' *, *', trim($request->requestVar('csvIDs'))); foreach ($ids as $k => $v) { if (!is_numeric($v)) { unset($ids[$k]); } } if ($ids) { if (Object::has_extension('SiteTree', 'Translatable')) { Translatable::disable_locale_filter(); } $pages = DataObject::get($this->recordClass, sprintf('"%s"."ID" IN (%s)', ClassInfo::baseDataClass($this->recordClass), implode(", ", $ids))); if (Object::has_extension('SiteTree', 'Translatable')) { Translatable::enable_locale_filter(); } if (Object::has_extension($this->recordClass, 'Versioned')) { // If we didn't query all the pages, then find the rest on the live site if (!$pages || $pages->Count() < sizeof($ids)) { foreach ($ids as $id) { $idsFromLive[$id] = true; } if ($pages) { foreach ($pages as $page) { unset($idsFromLive[$page->ID]); } } $idsFromLive = array_keys($idsFromLive); $sql = sprintf('"%s"."ID" IN (%s)', $this->recordClass, implode(", ", $idsFromLive)); $livePages = Versioned::get_by_stage($this->recordClass, 'Live', $sql); if ($pages) { $pages->merge($livePages); } else { $pages = $livePages; } } } } else { $pages = new DataObjectSet(); } return $actionHandler->run($pages); }
/** * @return JoinSpecification[] */ public function build() { $specs = array(); $relation_name = $this->alias->getName(); $class_name = ClassInfo::baseDataClass($this->base_entity); $child_class = $this->relations[$relation_name]; $child_hierarchy = ClassInfo::dataClassesFor($child_class); $base_child_class = array_shift($child_hierarchy); $join_field = $this->base_entity->getRemoteJoinField($relation_name, 'has_many'); $specs[] = new JoinSpecification($base_child_class, $base_child_class . '.' . $join_field . ' = ' . $class_name . '.ID'); $this->base_table = $base_child_class; $this->query->addAndCondition(QueryCriteria::equal("{$base_child_class}.ClassName", $child_class)); return $specs; }
/** * @return JoinSpecification[] */ public function build() { $specs = array(); $class_name = ClassInfo::baseDataClass($this->base_entity); $relation_name = $this->alias->getName(); $child = $this->relations[$relation_name]; $child_many_many = Config::inst()->get($child, 'many_many'); $child_many_many_classes = array_flip($child_many_many); $component_name = $child_many_many_classes[$class_name]; list($parent_class, $component_class, $child_join_field, $join_field, $join_table) = Singleton($child)->many_many($component_name); $specs[] = new JoinSpecification($join_table, $join_table . '`.' . $join_field . ' = `' . $class_name . '`.ID'); $specs[] = new JoinSpecification($child, $child . '`.ID = `' . $join_table . '`.' . $child_join_field); $this->base_table = $class_name; return $specs; }
/** * Create a new ManyManyList object. * * A ManyManyList object represents a list of DataObject records that correspond to a many-many * relationship. In addition to, * * Generation of the appropriate record set is left up to the caller, using the normal * {@link DataList} methods. Addition arguments are used to support {@@link add()} * and {@link remove()} methods. * * @param string $dataClass The class of the DataObjects that this will list. * @param string $joinTable The name of the table whose entries define the content of this many_many relation. * @param string $localKey The key in the join table that maps to the dataClass' PK. * @param string $foreignKey The key in the join table that maps to joined class' PK. * @param string $extraFields A map of field => fieldtype of extra fields on the join table. * * @example new ManyManyList('Group','Group_Members', 'GroupID', 'MemberID'); */ public function __construct($dataClass, $joinTable, $localKey, $foreignKey, $extraFields = array()) { parent::__construct($dataClass); $this->joinTable = $joinTable; $this->localKey = $localKey; $this->foreignKey = $foreignKey; $this->extraFields = $extraFields; $baseClass = ClassInfo::baseDataClass($dataClass); // Join to the many-many join table $this->dataQuery->innerJoin($joinTable, "\"{$joinTable}\".\"{$this->localKey}\" = \"{$baseClass}\".\"ID\""); // Query the extra fields from the join table if ($extraFields) { $this->dataQuery->selectFromTable($joinTable, array_keys($extraFields)); } }
public function getList($buyable, $limit = 4) { if (($categories = $buyable->CategoryIDs) && $buyable->get()->filter('ParentID', $categories)->exclude('ID', $buyable->ID)->exists()) { $list = $buyable->get()->exclude('ID', $buyable->ID); $any = ['ParentID' => $categories]; // Go through the Product Categories attached via many many to buyable and add them as well if ($component = $buyable->many_many('ProductCategories')) { list($parentClass, $componentClass, $parentField, $componentField, $relationTable) = $component; $baseClass = \ClassInfo::baseDataClass($buyable); // Join ProductCategories_Products table to find any products that also belong to these categories $list = $list->leftJoin($relationTable, "\"{$relationTable}\".\"{$parentField}\" = \"{$baseClass}\".\"ID\""); $any["{$relationTable}.{$componentField}"] = $categories; } return $list->filterAny($any); } return null; }
public function handleSave(GridField $grid, DataObjectInterface $record) { $data = $grid->Value(); $base = ClassInfo::baseDataClass($record); if (isset($data['GridFieldEditableColumns'])) { // go through every warehouse and make sure the have either 0 stock // or take the value from this $warehouses = ProductWarehouse::get(); foreach ($warehouses as $warehouse) { $stock = $record->getStockForWarehouse($warehouse); $quantity = null; if (isset($data['GridFieldEditableColumns'][$stock->ID])) { if (isset($data['GridFieldEditableColumns'][$stock->ID]['Quantity'])) { $quantity = (int) $data['GridFieldEditableColumns'][$stock->ID]['Quantity']; } } $stock->Quantity = $quantity; $stock->write(); } } }
/** * Render the Nivo Slider * * @return string HTML **/ public function forTemplate() { $classes = array_reverse(ClassInfo::ancestry($this->ClassName)); $baseClass = ClassInfo::baseDataClass($this->ClassName); $templates = array(); foreach ($classes as $class) { $templates[] = $class; if ($class == $baseClass) { break; } } // Require nivo slider assets Requirements::css(NivoSlider::get_module_folder() . '/css/nivo-slider.css'); Requirements::javascript(NivoSlider::get_module_folder() . '/javascript/jquery-1.9.0.min.js'); Requirements::javascript(NivoSlider::get_module_folder() . '/javascript/jquery.nivo.slider.pack.js'); Requirements::customScript('$(window).ready(function() { $("#' . $this->ClassName . '-' . $this->ID . '").nivoSlider({ effect: "' . $this->Effect . '", animSpeed: ' . $this->AnimationSpeed . ', pauseTime: ' . $this->PauseTime . ', startSlide: ' . $this->StartSlide . ', slices: ' . $this->Slices . ', boxCols: ' . $this->BoxCols . ', boxRwos: ' . $this->BoxRows . ', directionNav: ' . $this->DirectionNav . ', controlNav: ' . $this->ControlNav . ', controlNavThumbs: ' . $this->ControlNavThumbs . ', pauseOnHover: ' . $this->PauseOnHover . ', manualAdvance: ' . $this->ManualAdvance . ', prevText: "' . $this->PrevText . '", nextText: "' . $this->NextText . '", randomStart: ' . $this->RandomStart . ' }); });'); // Setup our theme $theme = new $this->Theme(); $theme->beforeRender(); return $this->customise(array("ThemeTitle" => $theme->getTitle(), "ThemeCSSClass" => $theme->getCssClass()))->renderWith($templates); }
function dodataobjectsort() { $i = 0; $extraSet = ''; $extraWhere = ''; $sortField = $this->SortFieldForDataObjectSorter(); $baseDataClass = ClassInfo::baseDataClass($this->owner->ClassName); if ($baseDataClass) { if (isset($_REQUEST["dos"])) { foreach ($_REQUEST['dos'] as $position => $id) { $id = intval($id); $object = $baseDataClass::get()->byID($id); //we add one because position 0 is not good. $position = intval($position) + 1; if ($object && $object->canEdit()) { if ($object->{$sortField} != $position) { $object->{$sortField} = $position; //hack for site tree if ($object instanceof SiteTree) { $object->writeToStage('Stage'); $object->Publish('Stage', 'Live'); } else { $object->write(); } } else { } } else { return _t("DataObjectSorter.NOACCESS", "You do not have access rights to make these changes."); } } } else { return _t("DataObjectSorter.ERROR2", "Error 2"); } } else { return _t("DataObjectSorter.ERROR1", "Error 1"); } return _t("DataObjectSorter.UPDATEDRECORDS", "Updated record(s)"); }
/** * Return children from the stage site * * @param showAll Inlcude all of the elements, even those not shown in the menus. * (only applicable when extension is applied to {@link SiteTree}). * @return DataObjectSet */ public function filteredStageChildren($showAll = false, $filter = '', $sort = '"Sort" ASC') { $extraFilter = $filter; if ($this->owner->db('ShowInMenus')) { $extraFilter .= $showAll ? '' : " AND \"ShowInMenus\"=1"; } $baseClass = ClassInfo::baseDataClass($this->owner->class); $sort = explode(' ', $sort); if (strpos($sort[0], '"') === false) { $sort[0] = '"' . Convert::raw2sql($sort[0]) . '"'; } $sort[1] = strtolower($sort[1]) == 'asc' ? 'ASC' : 'DESC'; $sort = $sort[0] . ' ' . $sort[1]; if (strlen($extraFilter)) { $extraFilter = ' AND ' . $extraFilter; } $staged = DataObject::get($baseClass, "\"{$baseClass}\".\"ParentID\" = " . (int) $this->owner->ID . " AND \"{$baseClass}\".\"ID\" != " . (int) $this->owner->ID . $extraFilter, $sort); if (!$staged) { $staged = new ArrayList(); } $this->owner->extend("augmentStageChildren", $staged, $showAll); return $staged; }
public function addDirtyIDs($class, $statefulids, $index) { $base = ClassInfo::baseDataClass($class); $forclass = isset($this->dirty[$base]) ? $this->dirty[$base] : array(); foreach ($statefulids as $statefulid) { $id = $statefulid['id']; $state = $statefulid['state']; $statekey = serialize($state); if (!isset($forclass[$statekey])) { $forclass[$statekey] = array('state' => $state, 'ids' => array($id => array($index))); } else { if (!isset($forclass[$statekey]['ids'][$id])) { $forclass[$statekey]['ids'][$id] = array($index); } else { if (array_search($index, $forclass[$statekey]['ids'][$id]) === false) { $forclass[$statekey]['ids'][$id][] = $index; // dirty count stays the same } } } } $this->dirty[$base] = $forclass; }