Closed Nellyaa closed 1 year ago
Can you please post the full error stack trace? It'll appear with devMode
enabled, otherwise you should find it in the logs.
Absolutely, sorry!
Unknown Property – [yii\base\UnknownPropertyException](https://www.yiiframework.com/doc-2.0/yii-base-unknownpropertyexception.html)
Getting unknown property: craft\commerce\elements\db\VariantQuery::hasSales
1. in /var/www/vendor/yiisoft/yii2/base/Component.phpat line 154
145146147148149150151152153154155156157158159160161162163 if ($behavior->canGetProperty($name)) {
return $behavior->$name;
}
}
if (method_exists($this, 'set' . $name)) {
throw new InvalidCallException('Getting write-only property: ' . get_class($this) . '::' . $name);
}
throw new UnknownPropertyException('Getting unknown property: ' . get_class($this) . '::' . $name);
}
/**
* Sets the value of a component property.
*
* This method will check in the following order and act accordingly:
*
* - a property defined by a setter: set the property value
* - an event in the format of "on xyz": attach the handler to the event "xyz"
2. in /var/www/vendor/putyourlightson/craft-blitz/src/helpers/ElementQueryHelper.php at line 32– [yii\base\Component::__get](https://www.yiiframework.com/doc-2.0/yii-base-component.html#__get()-detail)('hasSales')
26272829303132333435363738 {
$params = [];
$defaultParams = self::getDefaultElementQueryParams($elementQuery->elementType);
foreach ($defaultParams as $key => $default) {
$value = $elementQuery->{$key};
if ($value !== $default) {
$params[$key] = $value;
}
}
3. in /var/www/vendor/putyourlightson/craft-blitz/src/services/GenerateCacheService.php at line 189– putyourlightson\blitz\helpers\ElementQueryHelper::getUniqueElementQueryParams(craft\commerce\elements\db\VariantQuery)
183184185186187188189190191192193194195
/**
* Saves an element query.
*/
public function saveElementQuery(ElementQuery $elementQuery): void
{
$params = json_encode(ElementQueryHelper::getUniqueElementQueryParams($elementQuery));
// Create a unique index from the element type and parameters for quicker indexing and less storage
$index = sprintf('%u', crc32($elementQuery->elementType . $params));
// Require a mutex for the element query index to avoid doing the same operation multiple times
$mutex = Craft::$app->getMutex();
4. in /var/www/vendor/putyourlightson/craft-blitz/src/services/GenerateCacheService.php at line 181– putyourlightson\blitz\services\GenerateCacheService::saveElementQuery(craft\commerce\elements\db\VariantQuery)
175176177178179180181182183184185186187
// Don't proceed if this is a relation query
if (ElementQueryHelper::isRelationQuery($elementQuery)) {
return;
}
$this->saveElementQuery($elementQuery);
}
/**
* Saves an element query.
*/
public function saveElementQuery(ElementQuery $elementQuery): void
5. in /var/www/vendor/putyourlightson/craft-blitz/src/services/GenerateCacheService.php at line 115– putyourlightson\blitz\services\GenerateCacheService::addElementQuery(craft\commerce\elements\db\VariantQuery)
109110111112113114115116117118119120121 // Register element query prepare event
Event::on(ElementQuery::class, ElementQuery::EVENT_BEFORE_PREPARE,
function(CancelableEvent $event) {
if (Craft::$app->getResponse()->getIsOk()) {
/** @var ElementQuery $elementQuery */
$elementQuery = $event->sender;
$this->addElementQuery($elementQuery);
}
}
);
}
/**
6. putyourlightson\blitz\services\GenerateCacheService::putyourlightson\blitz\services\{closure}(craft\events\CancelableEvent)
7. in /var/www/vendor/yiisoft/yii2/base/Event.php at line 312– call_user_func(Closure, craft\events\CancelableEvent)
8. in /var/www/vendor/yiisoft/yii2/base/Component.php at line 642– [yii\base\Event::trigger](https://www.yiiframework.com/doc-2.0/yii-base-event.html#trigger()-detail)('craft\elements\db\ElementQuery', 'beforePrepare', craft\events\CancelableEvent)
9. in /var/www/vendor/craftcms/cms/src/elements/db/ElementQuery.php at line 1897– [yii\base\Component::trigger](https://www.yiiframework.com/doc-2.0/yii-base-component.html#trigger()-detail)('beforePrepare', craft\events\CancelableEvent)
1891189218931894189518961897189818991900190119021903 * @see prepare()
* @see afterPrepare()
*/
protected function beforePrepare(): bool
{
$event = new CancelableEvent();
$this->trigger(self::EVENT_BEFORE_PREPARE, $event);
return $event->isValid;
}
/**
* This method is called at the end of preparing an element query for the query builder.
10. in /var/www/vendor/craftcms/commerce/src/elements/db/VariantQuery.php at line 889– craft\elements\db\ElementQuery::beforePrepare()
883884885886887888889890891892893894895 $this->subQuery->andWhere(['not', $hasSalesCondition]);
}
}
$this->_applyHasProductParam();
return parent::beforePrepare();
}
/**
* Normalizes the productId param to an array of IDs or null
*/
private function _normalizeProductId(): void
11. in /var/www/vendor/craftcms/cms/src/elements/db/ElementQuery.php at line 1294– craft\commerce\elements\db\VariantQuery::beforePrepare()
1288128912901291129212931294129512961297129812991300 ->innerJoin(['elements_sites' => Table::ELEMENTS_SITES], '[[elements_sites.id]] = [[subquery.elementsSitesId]]');
// Keep track of whether an element table is joined into the query
$this->_joinedElementTable = false;
// Give other classes a chance to make changes up front
if (!$this->beforePrepare()) {
throw new QueryAbortedException();
}
$this->subQuery
->addSelect([
'elementsId' => 'elements.id',
12. in /var/www/vendor/yiisoft/yii2/db/QueryBuilder.php at line 227– craft\elements\db\ElementQuery::prepare(craft\db\mysql\QueryBuilder)
13. in /var/www/vendor/yiisoft/yii2/db/Query.php at line 157– [yii\db\QueryBuilder::build](https://www.yiiframework.com/doc-2.0/yii-db-querybuilder.html#build()-detail)(craft\commerce\elements\db\VariantQuery)
14. in /var/www/vendor/yiisoft/yii2/db/Query.php at line 320– [yii\db\Query::createCommand](https://www.yiiframework.com/doc-2.0/yii-db-query.html#createCommand()-detail)(craft\db\Connection)
15. in /var/www/vendor/craftcms/cms/src/db/Query.php at line 309– [yii\db\Query::column](https://www.yiiframework.com/doc-2.0/yii-db-query.html#column()-detail)(null)
303304305306307308309310311312313314315 /**
* @inheritdoc
*/
public function column($db = null): array
{
try {
return parent::column($db);
} catch (QueryAbortedException) {
return [];
}
}
/**
16. in /var/www/vendor/craftcms/cms/src/elements/db/ElementQuery.php at line 1532– craft\db\Query::column(null)
1526152715281529153015311532153315341535153615371538 $this->from = ['elements' => Table::ELEMENTS];
$result = parent::column($db);
$this->from = null;
return $result;
}
return parent::column($db);
}
/**
* @inheritdoc
*/
public function exists($db = null): bool
17. in /var/www/vendor/craftcms/cms/src/elements/db/ElementQuery.php at line 1564– craft\elements\db\ElementQuery::column(null)
1558155915601561156215631564156515661567156815691570 * @inheritdoc
*/
public function ids(?Connection $db = null): array
{
$select = $this->select;
$this->select = ['elements.id' => 'elements.id'];
$result = $this->column($db);
$this->select($select);
return $result;
}
/**
18. in /var/www/vendor/craftcms/commerce/src/elements/db/VariantQuery.php at line 682– craft\elements\db\ElementQuery::ids()
676677678679680681682683684685686687688 $query->$attribute = $this->$attribute;
}
$query->andWhere(['commerce_products.promotable' => true]);
unset($query->hasSales);
$query->limit = null;
$variantIds = $query->ids();
$productIds = Product::find()
->andWhere(['promotable' => true])
->limit(null)
->ids();
19. in /var/www/vendor/craftcms/cms/src/elements/db/ElementQuery.php at line 1294– craft\commerce\elements\db\VariantQuery::beforePrepare()
1288128912901291129212931294129512961297129812991300 ->innerJoin(['elements_sites' => Table::ELEMENTS_SITES], '[[elements_sites.id]] = [[subquery.elementsSitesId]]');
// Keep track of whether an element table is joined into the query
$this->_joinedElementTable = false;
// Give other classes a chance to make changes up front
if (!$this->beforePrepare()) {
throw new QueryAbortedException();
}
$this->subQuery
->addSelect([
'elementsId' => 'elements.id',
20. in /var/www/vendor/yiisoft/yii2/db/QueryBuilder.php at line 227– craft\elements\db\ElementQuery::prepare(craft\db\mysql\QueryBuilder)
21. in /var/www/vendor/yiisoft/yii2/db/Query.php at line 157– [yii\db\QueryBuilder::build](https://www.yiiframework.com/doc-2.0/yii-db-querybuilder.html#build()-detail)(craft\commerce\elements\db\VariantQuery)
22. in /var/www/vendor/yiisoft/yii2/db/Query.php at line 320– [yii\db\Query::createCommand](https://www.yiiframework.com/doc-2.0/yii-db-query.html#createCommand()-detail)(craft\db\Connection)
23. in /var/www/vendor/craftcms/cms/src/db/Query.php at line 309– [yii\db\Query::column](https://www.yiiframework.com/doc-2.0/yii-db-query.html#column()-detail)(null)
303304305306307308309310311312313314315 /**
* @inheritdoc
*/
public function column($db = null): array
{
try {
return parent::column($db);
} catch (QueryAbortedException) {
return [];
}
}
/**
24. in /var/www/vendor/craftcms/cms/src/elements/db/ElementQuery.php at line 1532– craft\db\Query::column(null)
1526152715281529153015311532153315341535153615371538 $this->from = ['elements' => Table::ELEMENTS];
$result = parent::column($db);
$this->from = null;
return $result;
}
return parent::column($db);
}
/**
* @inheritdoc
*/
public function exists($db = null): bool
25. in /var/www/vendor/craftcms/commerce/src/elements/db/ProductQuery.php at line 923– craft\elements\db\ElementQuery::column()
917918919920921922923924925926927928929 } else {
return;
}
$variantQuery->limit = null;
$variantQuery->select('commerce_variants.productId');
$productIds = $variantQuery->asArray()->column();
// Remove any blank product IDs (if any)
$productIds = array_filter($productIds);
$this->subQuery->andWhere(['commerce_products.id' => array_values($productIds)]);
}
26. in /var/www/vendor/craftcms/commerce/src/elements/db/ProductQuery.php at line 813– craft\commerce\elements\db\ProductQuery::_applyHasVariantParam()
807808809810811812813814815816817818819 }
if (isset($this->defaultSku)) {
$this->subQuery->andWhere(Db::parseParam('commerce_products.defaultSku', $this->defaultSku));
}
$this->_applyHasVariantParam();
$this->_applyEditableParam();
$this->_applyRefParam();
return parent::beforePrepare();
}
27. in /var/www/vendor/craftcms/cms/src/elements/db/ElementQuery.php at line 1294– craft\commerce\elements\db\ProductQuery::beforePrepare()
1288128912901291129212931294129512961297129812991300 ->innerJoin(['elements_sites' => Table::ELEMENTS_SITES], '[[elements_sites.id]] = [[subquery.elementsSitesId]]');
// Keep track of whether an element table is joined into the query
$this->_joinedElementTable = false;
// Give other classes a chance to make changes up front
if (!$this->beforePrepare()) {
throw new QueryAbortedException();
}
$this->subQuery
->addSelect([
'elementsId' => 'elements.id',
28. in /var/www/vendor/yiisoft/yii2/db/QueryBuilder.php at line 227– craft\elements\db\ElementQuery::prepare(craft\db\mysql\QueryBuilder)
29. in /var/www/vendor/yiisoft/yii2/db/Query.php at line 157– [yii\db\QueryBuilder::build](https://www.yiiframework.com/doc-2.0/yii-db-querybuilder.html#build()-detail)(craft\commerce\elements\db\ProductQuery)
30. in /var/www/vendor/yiisoft/yii2/db/Query.php at line 249– [yii\db\Query::createCommand](https://www.yiiframework.com/doc-2.0/yii-db-query.html#createCommand()-detail)(craft\db\Connection)
31. in /var/www/vendor/craftcms/cms/src/db/Query.php at line 248– [yii\db\Query::all](https://www.yiiframework.com/doc-2.0/yii-db-query.html#all()-detail)(null)
242243244245246247248249250251252253254 /**
* @inheritdoc
*/
public function all($db = null): array
{
try {
return parent::all($db);
} catch (QueryAbortedException) {
return [];
}
}
/**
32. in /var/www/vendor/craftcms/cms/src/elements/db/ElementQuery.php at line 1492– craft\db\Query::all(null)
1486148714881489149014911492149314941495149614971498 if ($this->with) {
Craft::$app->getElements()->eagerLoadElements($this->elementType, $cachedResult, $this->with);
}
return $cachedResult;
}
return parent::all($db);
}
/**
* @inheritdoc
* @return ElementInterface|array|null
*/
33. in /var/www/vendor/craftcms/cms/src/db/Query.php at line 264– craft\elements\db\ElementQuery::all(null)
258259260261262263264265266267268269270 * If this parameter is not given, the `db` application component will be used.
* @return Collection A collection of the resulting elements.
* @since 4.0.0
*/
public function collect(?YiiConnection $db = null): Collection
{
return ElementCollection::make($this->all($db));
}
/**
* @inheritdoc
*/
public function one($db = null): mixed
34. in /var/www/vendor/twig/twig/src/Extension/CoreExtension.php at line 1607– craft\db\Query::collect()
35. in /var/www/vendor/craftcms/cms/src/helpers/Template.php at line 110– twig_get_attribute(craft\web\twig\Environment, Twig\Source, craft\commerce\elements\db\ProductQuery, 'collect', ...)
104105106107108109110111112113114115116 if (is_object($value) && get_class($value) === Markup::class) {
$arguments[$key] = (string)$value;
}
}
try {
return twig_get_attribute($env, $source, $object, $item, $arguments, $type, $isDefinedTest, $ignoreStrictCheck);
} catch (UnknownMethodException $e) {
// Copy twig_get_attribute()'s BadMethodCallException handling
if ($ignoreStrictCheck || !$env->isStrictVariables()) {
return null;
}
throw new RuntimeError($e->getMessage(), -1, $source);
36. in /var/www/templates/_views/listing.twig at line 17– craft\helpers\Template::attribute(craft\web\twig\Environment, Twig\Source, craft\commerce\elements\db\ProductQuery, 'collect', ...)
--------------------
38. in /var/www/vendor/twig/twig/src/Template.php at line 367– [Twig\Template::displayWithErrorHandling](http://twig.sensiolabs.org/api/2.x/Twig/Template.html#method_displayWithErrorHandling)(['category' => craft\elements\Category, 'variables' => ['category' => craft\elements\Category], 'craft' => craft\web\twig\variables\CraftVariable, 'currentSite' => craft\models\Site, ...], ['content' => [__TwigTemplate_def8a3dc189f07dd23d9d3bbc23b620e, 'block_content']])
39. in /var/www/vendor/twig/twig/src/Template.php at line 379– [Twig\Template::display](http://twig.sensiolabs.org/api/2.x/Twig/Template.html#method_display)(['category' => craft\elements\Category, 'variables' => ['category' => craft\elements\Category]])
40. in /var/www/vendor/twig/twig/src/TemplateWrapper.php at line 40– [Twig\Template::render](http://twig.sensiolabs.org/api/2.x/Twig/Template.html#method_render)(['category' => craft\elements\Category, 'variables' => ['category' => craft\elements\Category]], [])
41. in /var/www/vendor/twig/twig/src/Environment.php at line 277– [Twig\TemplateWrapper::render](http://twig.sensiolabs.org/api/2.x/Twig/TemplateWrapper.html#method_render)(['category' => craft\elements\Category, 'variables' => ['category' => craft\elements\Category]])
42. in /var/www/vendor/craftcms/cms/src/web/View.php at line 451– [Twig\Environment::render](http://twig.sensiolabs.org/api/2.x/Twig/Environment.html#method_render)('_views/listing', ['category' => craft\elements\Category, 'variables' => ['category' => craft\elements\Category]])
445446447448449450451452453454455456457
// Render and return
$renderingTemplate = $this->_renderingTemplate;
$this->_renderingTemplate = $template;
try {
$output = $this->getTwig()->render($template, $variables);
} finally {
$this->_renderingTemplate = $renderingTemplate;
$this->setTemplateMode($oldTemplateMode);
}
$this->afterRenderTemplate($template, $variables, $templateMode, $output);
43. in /var/www/vendor/craftcms/cms/src/web/View.php at line 504– craft\web\View::renderTemplate('_views/listing', ['category' => craft\elements\Category, 'variables' => ['category' => craft\elements\Category]])
498499500501502503504505506507508509510
$isRenderingPageTemplate = $this->_isRenderingPageTemplate;
$this->_isRenderingPageTemplate = true;
try {
$this->beginPage();
echo $this->renderTemplate($template, $variables);
$this->endPage();
} finally {
$this->_isRenderingPageTemplate = $isRenderingPageTemplate;
$this->setTemplateMode($oldTemplateMode);
$output = ob_get_clean();
}
44. in /var/www/vendor/craftcms/cms/src/web/TemplateResponseFormatter.php at line 56– craft\web\View::renderPageTemplate('_views/listing', ['category' => craft\elements\Category, 'variables' => ['category' => craft\elements\Category]], 'site')
50515253545556575859606162 ) {
$view->registerAssetBundle(ContentWindowAsset::class);
}
// Render and return the template
try {
$response->content = $view->renderPageTemplate($behavior->template, $behavior->variables, $behavior->templateMode);
} catch (Throwable $e) {
if (!$e->getPrevious() instanceof ExitException) {
// Bail on the template response
$response->format = Response::FORMAT_HTML;
throw $e;
}
45. in /var/www/vendor/yiisoft/yii2/web/Response.php at line 1098– craft\web\TemplateResponseFormatter::format(craft\web\Response)
46. in /var/www/vendor/craftcms/cms/src/web/Response.php at line 286– [yii\web\Response::prepare](https://www.yiiframework.com/doc-2.0/yii-web-response.html#prepare()-detail)()
280281282283284285286287288289290291292
/**
* @inheritdoc
*/
protected function prepare(): void
{
parent::prepare();
$this->_isPrepared = true;
}
/**
* Clear the output buffer to prevent corrupt downloads.
*
47. in /var/www/vendor/yiisoft/yii2/web/Response.php at line 339– craft\web\Response::prepare()
48. in /var/www/vendor/yiisoft/yii2/base/Application.php at line 390– [yii\web\Response::send](https://www.yiiframework.com/doc-2.0/yii-web-response.html#send()-detail)()
49. in /var/www/web/index.php at line 12– [yii\base\Application::run](https://www.yiiframework.com/doc-2.0/yii-base-application.html#run()-detail)()
6789101112// Load shared bootstrap
require dirname(__DIR__) . '/bootstrap.php';
// Load and run Craft
/** @var craft\web\Application $app */
$app = require CRAFT_VENDOR_PATH . '/craftcms/cms/bootstrap/web.php';
$app->run();
$_COOKIE = [
XXXXXXXXXXXXXXXX
];
$_SESSION = [
'a50e111d5f13061b3bc1c20c2a9c215d__flash' => [
'cp-notification-notice' => -1,
'cp-notice' => -1,
],
'a50e111d5f13061b3bc1c20c2a9c215d__auth_access' => [
'saveAssets:10',
],
'08b50206495ab19261c35e647aeb027a__token' => 'Is6q26T3sJbZh9K96b637iN7kwuPlWWyYhebaZJIP_WwNqx6B4md3osPayPdAjscN5fb6EdDPTx9tl67coGPbL9az7CAcOoMPpMk',
'08b50206495ab19261c35e647aeb027a__id' => 1,
'__authKey' => '["Is6q26T3sJbZh9K96b637iN7kwuPlWWyYhebaZJIP_WwNqx6B4md3osPayPdAjscN5fb6EdDPTx9tl67coGPbL9az7CAcOoMPpMk",null,"b9cbd8dc13f19f9e7eb854f472bfa274"]',
'cp-notification-notice' => [
'Plugin settings saved.',
[
'icon' => 'info',
'iconLabel' => 'Notice',
],
],
'cp-notice' => 'Plugin settings saved.',
];
That's strange. The VariantQuery
class definitely has a hasSales
property.
Can you check that this exists in your local copy?
https://github.com/craftcms/commerce/blob/52f542e4e51faa4820036f98945d6e8ade580bf6/src/elements/db/VariantQuery.php#L63-L66
Yeah, it does exist. The page works fine with Blitz disabled too. That wouldn't be the case if it wouldn't exist, I guess. :)
Ok thanks, I'll do some testing and let you know what I find.
So it turns out that Commerce unsets the hasSales
property at https://github.com/craftcms/commerce/blob/52f542e4e51faa4820036f98945d6e8ade580bf6/src/elements/db/VariantQuery.php#L680
I've added a workaround for this in https://github.com/putyourlightson/craft-blitz/commit/10f06d0827e01d2389135af6447a3b34fcdfd851, for the next release.
Just released in version 4.3.0.
Perfect, thank you for the blitz-like fix! Works like a charm now. :)
I'm currently playing with integrating Blitz into a Craft Commerce install and stumbled upon this. We have a page that lists all variants/products on sale, we utilize something akin to this query in Twig:
{{ craft.variants.hasSales(true).one().title }}
which works fine without Blitz enabled. But when I enable Blitz caching for this page I get an unknown property exception. Since it works when Blitz is disabled, I assume the problem lies with the Blitz plugin?
Reproduce:
Using: Craft Pro 4.3.7.1 Commerce 4.2.5.1 Blitz 4.2.3