Solved thread

This post is marked as solved. If you think the information contained on this thread must be part of the official documentation, please contribute submitting a pull request to its repository.

Model snapshot

Hi,

I can't find why the subscribed value is not detected as changed by getChangedFields().

Here is the relevant code:

$subscription = GkNewsCommentsAccess::findFirst([
    'conditions' => 'news_id = ?1 and user_id=?2',
    'bind' => [1 => $newsid, 2 => $userid]
]);

$this->logger->debug('isSubscribed: '. $subscription->subscribed);
$this->logger->debug('getSnapshotData before: '. print_r($subscription->getSnapshotData(), TRUE));
$this->logger->debug('getChangedFields before: '. print_r($subscription->getChangedFields(), TRUE));

$subscription->subscribed = $subscribe; // changing value
$subscription->save();

$this->logger->debug('isSubscribed: '. $subscription->subscribed);
$this->logger->debug('getSnapshotData after: '. print_r($subscription->getSnapshotData(), TRUE));
$this->logger->debug('getChangedFields after: '. print_r($subscription->getChangedFields(), TRUE));

The debug output is as:

DEBUG isSubscribed: 1
DEBUG getSnapshotData before: Array ( [news_id] => 177 [user_id] => 26422 [read] => 2017-05-20 02:28:24 [post] => [subscribed] => 1 )
DEBUG getChangedFields before: Array ( )
DEBUG isSubscribed: 0
DEBUG getSnapshotData after: Array ( [news_id] => 177 [user_id] => 26422 [read] => 2017-05-20T02:29:08+02:00 [post] => [subscribed] => 0 )
DEBUG getChangedFields after: Array ( )

I expect the getChangedFields after to be as Array ( [0] => read, [1] => subscribed )

However, if I change value of user_id or news_idthis is detected as changed by getChangedFields()

Am I doing something wrong? Reading from model.zep, I expect it to work.

Thanks for your help.

  • PHALCON_VERSION=3.1.2
  • I have $this->keepSnapshots(true); in Model initialize()

My actual function is:

    protected function updateSubscription(bool $subscribe) {
        $subscription = new GkNewsCommentsAccess();
        $subscription->news_id = $this->dispatcher->getParam('news_id');
        $subscription->user_id = $this->session->user_id;
        $subscription->subscribed = ($subscribe?'1':'0');

        if (!$subscription->save()) {
            $this->flashSession->warning($this->di->getTranslation()
                ->_('news_comment_failed_save_subscription'));
            foreach ($subscription->getMessages() as $message) {
                $this->flashSession->error($message);
            }
            return;
        }

        if ($subscription->hasSnapshotData() && !$subscription->hasChanged('subscribed')) {
            return;
        }

        if ($subscribe) {
            $this->flashSession->success($this->di->getTranslation()
                ->_('news_comment_you_are_successfully_subscribed'));
        } else {
            $this->flashSession->success($this->di->getTranslation()
                ->_('news_comment_you_are_successfully_un_subscribed'));
        }
    }


638

If I also print the status before saving I see the expected result, but after save results, are bad (from my point of view)

$subscription = GkNewsCommentsAccess::findFirst([
    'conditions' => 'news_id = ?1 and user_id=?2',
    'bind' => [1 => $newsid, 2 => $userid]
]);

$this->logger->debug('isSubscribed: '. $subscription->subscribed);
$this->logger->debug('getSnapshotData before: '. print_r($subscription->getSnapshotData(), TRUE));
$this->logger->debug('getChangedFields before: '. print_r($subscription->getChangedFields(), TRUE));

$subscription->subscribed = $subscribe; // changing value
$subscription->user_id = 99999;

$this->logger->debug('getSnapshotData after1: '. print_r($subscription->getSnapshotData(), TRUE));
$this->logger->debug('getChangedFields after1: '. print_r($subscription->getChangedFields(), TRUE));

$subscription->save();

$this->logger->debug('isSubscribed: '. $subscription->subscribed);
$this->logger->debug('getSnapshotData after2: '. print_r($subscription->getSnapshotData(), TRUE));
$this->logger->debug('getChangedFields after2: '. print_r($subscription->getChangedFields(), TRUE));

The debug output is as:

DEBUG isSubscribed: 0
DEBUG getSnapshotData before: Array ( [news_id] => 177 [user_id] => 26422 [read] => 2017-05-20 02:29:08 [post] => [subscribed] => 0 )
DEBUG getChangedFields before: Array ( )
DEBUG isSubscribed: 1
DEBUG getSnapshotData after1: Array ( [news_id] => 177 [user_id] => 26422 [read] => 2017-05-20 02:29:08 [post] => [subscribed] => 0 )
DEBUG getChangedFields after1: Array ( [0] => user_id [1] => subscribed )
DEBUG isSubscribed: 1
DEBUG getSnapshotData after2: Array ( [news_id] => 177 [user_id] => 26422 [read] => 2017-05-20T03:16:39+02:00 [post] => [subscribed] => 1 )
DEBUG getChangedFields after2: Array ( [0] => user_id )

What's strange is that user_id is still detected as changed after save, wheras it's not the case for subscribed.



638

Hum only primary keys are keeped showed in getChangedFields() :(



638

FTR, here is my current full function.

    protected function updateSubscription(bool $subscribe) {
        $newsid = $this->dispatcher->getParam('news_id');
        $userid = $this->session->user_id;
        $changed = FALSE;

        $subscription = GkNewsCommentsAccess::findFirst(['conditions' => 'news_id = ?1 and user_id=?2', 'bind' => [1 => $newsid, 2 => $userid]]);
        if (!$subscription) {
            $subscription = new GkNewsCommentsAccess();
            $subscription->news_id = $newsid;
            $subscription->user_id = $userid;
            $changed = TRUE;
        }
        $subscription->subscribed = ($subscribe?'1':'0');

        if ($subscription->hasSnapshotData() && $subscription->hasChanged('subscribed')) {
            $changed = TRUE;
        }

        if (!$subscription->save()) {
            $this->flashSession->warning($this->di->getTranslation()
                ->_('news_comment_failed_save_subscription'));
            foreach ($subscription->getMessages() as $message) {
                $this->flashSession->error($message);
            }
            return;
        }

        if (!$changed) {
            return;
        }

        if ($subscribe) {
            $this->flashSession->success($this->di->getTranslation()
                ->_('news_comment_you_are_successfully_subscribed'));
        } else {
            $this->flashSession->success($this->di->getTranslation()
                ->_('news_comment_you_are_successfully_un_subscribed'));
        }
    }

or, whithout Snapshot

    protected function updateSubscription(bool $subscribe) {
        $newsid = $this->dispatcher->getParam('news_id');
        $userid = $this->session->user_id;

        $subscription = GkNewsCommentsAccess::findFirst(['conditions' => 'news_id = ?1 and user_id=?2', 'bind' => [1 => $newsid, 2 => $userid]]);
        if (!$subscription) {
            $subscription = new GkNewsCommentsAccess();
            $subscription->news_id = $newsid;
            $subscription->user_id = $userid;
        }
        $oldSubscribed = $subscription->subscribed;
        $subscription->subscribed = ($subscribe?'1':'0');

        if (!$subscription->save()) {
            $this->flashSession->warning($this->di->getTranslation()
                ->_('news_comment_failed_save_subscription'));
            foreach ($subscription->getMessages() as $message) {
                $this->flashSession->error($message);
            }
            return;
        }

        if ($oldSubscribed === $subscription->subscribed) {
            return;
        }

        if ($subscribe) {
            $this->flashSession->success($this->di->getTranslation()
                ->_('news_comment_you_are_successfully_subscribed'));
        } else {
            $this->flashSession->success($this->di->getTranslation()
                ->_('news_comment_you_are_successfully_un_subscribed'));
        }
    }
  1. Snapshots to version 3.1 were bugged and not working as should be causing other bugs(for example in dynamic update and some other things), from 3.1 to fix other issues after save snapshots are updated, if you don't want this use 3.0(or install 3.2.x using zephir), in phalcon 3.2 there will be added option to disable snapshot update or there will be new methods to check if field was updated(hasUpdated/getUpdatedFields).
  2. Phalcon doesn't allow to change primary keys by design, this is why you have user_id all the time in getChangedFields because in model it's changed but not saved to database meaning not updated in snapshot.


638
Accepted
answer
edited May '17

Thanks Wojciech Ślawski you set me on the way.

Phalcon 3.2 has new function hasUpdated() which correspond to the behavior I was expecting in my first post. Only difference from my first implementation is the "UpdateOrCreate" pattern to have the snapshot defined.

  • Any idea on 3.2.x branch stability and expected release?

Thanks a lot!

    protected function updateSubscription(bool $subscribe) {
        $newsid = $this->dispatcher->getParam('news_id');
        $userid = $this->session->user_id;

        $subscription =
            GkNewsCommentsAccess::findFirst(['conditions' => 'news_id = ?1 and user_id=?2',
                'bind' => [1 => $newsid, 2 => $userid]]);
        if (!$subscription) {
            $subscription = new GkNewsCommentsAccess();
            $subscription->news_id = $newsid;
            $subscription->user_id = $userid;
        }
        $subscription->subscribed = ($subscribe?'1':'0');

        if (!$subscription->save()) {
            $this->flashSession->warning($this->di->getTranslation()
                ->_('news_comment_failed_save_subscription'));
            foreach ($subscription->getMessages() as $message) {
                $this->flashSession->error($message);
            }
            return;
        }

        if ((!$subscription->hasSnapshotData() && !$subscribe) ||
            ($subscription->hasSnapshotData() && !$subscription->hasUpdated('subscribed'))
        ) {
            return;
        }

        if ($subscribe) {
            $this->flashSession->success($this->di->getTranslation()
                ->_('news_comment_you_are_successfully_subscribed'));
        } else {
            $this->flashSession->success($this->di->getTranslation()
                ->_('news_comment_you_are_successfully_un_subscribed'));
        }
    }

I guess 3.2.0 will be relased in near future this or next month.