Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ActiveQuery needs AFTER_FIND event #10427

Closed
tanakahisateru opened this issue Dec 18, 2015 · 5 comments
Closed

ActiveQuery needs AFTER_FIND event #10427

tanakahisateru opened this issue Dec 18, 2015 · 5 comments

Comments

@tanakahisateru
Copy link
Contributor

I want to operate models just after fetching for individual queries. But sometimes ActiveQuery would be evaluated lazily.

I propose to trigger ActiveQuery::EVENT_AFTER_FIND event against to ActiveQuery's listener.

$dataProvider->query = $foo->getRelation('bars');
$dataProvider->query->on(ActiveQuery::EVENT_AFTER_FIND, function($event) use($foo) {
    foreach ($event->models as $bar) {
        // Manual relation setup needed because:
        // - inverseOf() is ignored because this is not a property access.
        // - To use eager loading ->with('foo') creates another instance from $foo.
        $bar->populateRelation('foo', $foo);

        // Users can do any other preparations. ActiveRecord::EVENT_AFTER_FIND is
        // too common and it can't use contextual variables of query time.
    }
});

Currently I should do:

<div class="bars-list">
    <?= \yii\widgets\ListView::widget([
        'dataProvider' => $dataProvider,
        'itemView' => function($bar) use($foo) {
            /** @var ActiveRecord $bar */
            $bar->populateRelation('foo', $foo);
            return $bar->foo ...; // Though safe for N+1 problem but ugly.
        },
    ]); ?>
</div>
<div class="bars-grid">
    <?= \yii\grid\GridView::widget([
        'dataProvider' => $dataProvider,
        'beforeRow' => function($bar) use($foo) {
            /** @var ActiveRecord $bar */
            $bar->populateRelation('foo', $foo);
        },
        'columns' => [
            'bar.name',
            'bar.foo.name',
            'bar.foo.other_property',
        ],
    ]); ?>
</div>

I want to move them to search model class from view template.

@fernandezekiel
Copy link
Contributor

why not just eager load those models in the dataprovider's query object?

@tanakahisateru
Copy link
Contributor Author

just In my case, eager loading can reduce SQL, but what I wanted is the SAME object of $foo. The first $foo already has various cached data, otherwise eagerly loaded ->foo is not and should do them again.

Yii can assign backward relation via inversedOf method. It supports to recycle first object.

But generally, this issue indicates that no one can assign model's AFTER_FIND handler dynamically in caller context. That event can be assigned only static context. One of Yii's advantage is dynamic event/behavior assigning in caller context instead of method overriding.

@cebe cebe added this to the 2.0.x milestone Dec 20, 2015
@dynasource
Copy link
Member

related to #7268

@dynasource
Copy link
Member

and #7187

@samdark
Copy link
Member

samdark commented Jun 18, 2019

Won't be implemented in 2.0.

@samdark samdark closed this as completed Jun 18, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants