我正在使用Silverstripe Swipestripe模块进行在线商店。由于客户拥有的产品数量,当他们想要对产品进行更改(这种情况经常发生)时,通过网站树导航到每个单独的产品是不切实际的,所以我要这样做。喜欢使用modeladmin列出所有产品,并允许他们按名称/股票代码搜索产品。
我认为这可以像DataObjects一样解决(并且搜索似乎表明人们已经完成了这一点),但是当我在ModelAdmin视图中导航到产品时,我得到:
致命错误:在非对象中调用成员函数stat() 第3192行的/path/to/folder/wwwroot/framework/model/DataObject.php
<?php
class ProductAdmin extends ModelAdmin
{
private static $managed_models = array('Product');
private static $url_segment = 'product';
private $menu_title = 'Products';
}
有趣的是,页面类的页面和其他扩展可以正常工作。
以下是Product类的代码:
class Product extends Page {
/**
* Flag for denoting if this is the first time this Product is being written.
*
* @var Boolean
*/
protected $firstWrite = false;
/**
* DB fields for Product.
*
* @var Array
*/
private static $db = array(
'Price' => 'Decimal(19,4)',
'Currency' => 'Varchar(3)',
'StockCode' => 'Varchar(255)',
'Stock' => 'Int',
'Featured' => 'Boolean',
'YouTubeID' => 'Varchar(255)'
);
/**
* Actual price in base currency, can decorate to apply discounts etc.
*
* @return Price
*/
public function Amount() {
// TODO: Multi currency
$shopConfig = ShopConfig::current_shop_config();
$amount = new Price();
$amount->setAmount($this->Price);
$amount->setCurrency($shopConfig->BaseCurrency);
$amount->setSymbol($shopConfig->BaseCurrencySymbol);
//Transform amount for applying discounts etc.
$this->extend('updateAmount', $amount);
return $amount;
}
/**
* Display price, can decorate for multiple currency etc.
*
* @return Price
*/
public function Price() {
$amount = $this->Amount();
//Transform price here for display in different currencies etc.
$this->extend('updatePrice', $amount);
return $amount;
}
/**
* Has many relations for Product.
*
* @var Array
*/
private static $has_many = array(
'Attributes' => 'Attribute',
'Options' => 'Option',
'Variations' => 'Variation'
);
/**
* Defaults for Product
*
* @var Array
*/
private static $defaults = array(
'ParentID' => -1,
'Stock' => 999
);
/**
* Summary fields for displaying Products in the CMS
*
* @var Array
*/
private static $summary_fields = array(
'Amount.Nice' => 'Price',
'Title' => 'Title'
);
private static $searchable_fields = array(
'Title' => array(
'field' => 'TextField',
'filter' => 'PartialMatchFilter',
'title' => 'Name'
)
);
/**
* Set firstWrite flag if this is the first time this Product is written.
*
* @see SiteTree::onBeforeWrite()
* @see Product::onAfterWrite()
*/
public function onBeforeWrite() {
parent::onBeforeWrite();
if (!$this->ID) $this->firstWrite = true;
//Save in base currency
$shopConfig = ShopConfig::current_shop_config();
$this->Currency = $shopConfig->BaseCurrency;
}
/**
* Unpublish products if they get deleted, such as in product admin area
*
* @see SiteTree::onAfterDelete()
*/
public function onAfterDelete() {
parent::onAfterDelete();
if ($this->isPublished()) {
$this->doUnpublish();
}
}
/**
* Set some CMS fields for managing Products
*
* @see Page::getCMSFields()
* @return FieldList
*/
public function getCMSFields() {
$shopConfig = ShopConfig::current_shop_config();
$fields = parent::getCMSFields();
//Product fields
$fields->addFieldToTab('Root.Main', new PriceField('Price'), 'Content');
$fields->addFieldToTab('Root.Main', new TextField('StockCode'), 'Price');
$fields->addFieldToTab('Root.Main', new TextField('Stock'), 'Price');
$fields->addFieldToTab('Root.Main', new CheckBoxField('Featured'), 'Content');
$fields->addFieldToTab('Root.Images', new TextField('YouTubeID', 'YouTube Video ID (Taken from the end of the video url. ie https://www.youtube.com/watch?v=ABC123 would be ABC123)'));
//Replace URL Segment field
if ($this->ParentID == -1) {
$urlsegment = new SiteTreeURLSegmentField("URLSegment", 'URLSegment');
$baseLink = Controller::join_links(Director::absoluteBaseURL(), 'product/');
$url = (strlen($baseLink) > 36) ? "..." .substr($baseLink, -32) : $baseLink;
$urlsegment->setURLPrefix($url);
$fields->replaceField('URLSegment', $urlsegment);
}
if ($this->isInDB()) {
//Product attributes
$listField = new GridField(
'Attributes',
'Attributes',
$this->Attributes(),
GridFieldConfig_BasicSortable::create()
);
$fields->addFieldToTab('Root.Attributes', $listField);
//Product variations
$attributes = $this->Attributes();
if ($attributes && $attributes->exists()) {
//Remove the stock level field if there are variations, each variation has a stock field
$fields->removeByName('Stock');
$variationFieldList = array();
foreach ($attributes as $attribute) {
$variationFieldList['AttributeValue_'.$attribute->ID] = $attribute->Title;
}
$variationFieldList = array_merge($variationFieldList, singleton('Variation')->summaryFields());
$config = GridFieldConfig_HasManyRelationEditor::create();
$dataColumns = $config->getComponentByType('GridFieldDataColumns');
$dataColumns->setDisplayFields($variationFieldList);
$listField = new GridField(
'Variations',
'Variations',
$this->Variations(),
$config
);
$fields->addFieldToTab('Root.Variations', $listField);
}
}
//Ability to edit fields added to CMS here
$this->extend('updateProductCMSFields', $fields);
if ($warning = ShopConfig::base_currency_warning()) {
$fields->addFieldToTab('Root.Main', new LiteralField('BaseCurrencyWarning',
'<p class="message warning">'.$warning.'</p>'
), 'Title');
}
return $fields;
}
/**
* Get the URL for this Product, products that are not part of the SiteTree are
* displayed by the {@link Product_Controller}.
*
* @see SiteTree::Link()
* @see Product_Controller::show()
* @return String
*/
public function Link($action = null) {
if ($this->ParentID > -1) {
return parent::Link($action);
}
return Controller::join_links(Director::baseURL() . 'product/', $this->RelativeLink($action));
}
/**
* A product is required to be added to a cart with a variation if it has attributes.
* A product with attributes needs to have some enabled {@link Variation}s
*
* @return Boolean
*/
public function requiresVariation() {
$attributes = $this->Attributes();
return $attributes && $attributes->exists();
}
/**
* Get options for an Attribute of this Product.
*
* @param Int $attributeID
* @return ArrayList
*/
public function getOptionsForAttribute($attributeID) {
$options = new ArrayList();
$variations = $this->Variations();
if ($variations && $variations->exists()) foreach ($variations as $variation) {
if ($variation->isEnabled()) {
$option = $variation->getOptionForAttribute($attributeID);
if ($option) $options->push($option);
}
}
$options = $options->sort('SortOrder');
return $options;
}
/**
* Validate the Product before it is saved in {@link ShopAdmin}.
*
* @see DataObject::validate()
* @return ValidationResult
*/
public function validate() {
$result = new ValidationResult();
//If this is being published, check that enabled variations exist if they are required
$request = Controller::curr()->getRequest();
$publishing = ($request && $request->getVar('action_publish')) ? true : false;
if ($publishing && $this->requiresVariation()) {
$variations = $this->Variations();
if (!in_array('Enabled', $variations->map('ID', 'Status')->toArray())) {
$result->error(
'Cannot publish product when no variations are enabled. Please enable some product variations and try again.',
'VariationsDisabledError'
);
}
}
return $result;
}
}
任何人都可以建议我在这里做错了什么,或者另外一种方法来做我想要达到的目标吗?
干杯
答案 0 :(得分:1)
以防任何人仍然遇到同样的问题。 因此,如果您已为swipestripe安装了Product Categories模块,则会发生这种情况。 原因是该模块中ProductCategory.php文件中的ProductCategory_Extension类中的私有静态$ searchable_fields。只需注释掉该字段即可。 这是因为dataobject类尝试将类别作为一个类 - 这显然不存在。
如果我有时间,我会解决它并推送到github。只是想在这里更新,以便其他人不要浪费时间去理解为什么它不起作用。