Thread

Possible issue with VariableColumnModel

March 30, 2017 4:52pm

Subscribe [2]
  • #1 / Mar 30, 2017 4:52pm

    litzinger's avatar

    litzinger

    564 posts

    I have a strange issue with a customer using Publisher. I haven’t been able to replicate it, and they setup a new environment and can’t replicate it, and no one else has reported this bug, so its unique to their install it seems. Given I make the following query:

    $entry = ee('Model')->get(EntryTranslation::NAME)
                ->filter('entry_id', $entryId)
                ->filter('lang_id', $language)
                ->filter('status', $status)
                ->first();

    Its returning the title column value of entry_id 456 even though $entryId is clearly 459 when making the query. I’ve checked all the tables and the data is legit, but it seems like somewhere along the way when VariableColumnModel->fillProperty is called it is getting the wrong title value.

    I’m using Gateways, so I don’t know how/if that is coming into play. Unfortunately the only place this is happening is on their environment and I can’t step debug it. Since you guys know the inner workings of the Model layer better than I do, is it possible for it to be getting confused? Its pretty clear that given the query above I can echo out $entry->title and it is incorrect. I’m at a loss here.

    class EntryTranslation extends VariableColumnModel
    {
        const NAME = 'publisher:EntryTranslation';
    
        protected static $_primary_key = 'id';
        protected static $_gateway_names = ['EntryTranslationTitleGateway', 'EntryTranslationDataGateway'];
    
        protected $site_id;
        protected $channel_id;
        protected $author_id;
        protected $entry_id;
        protected $lang_id;
        protected $status;
        protected $title;
        protected $url_title;
        protected $page_url;
        protected $hide_in_nav = 'n';
        protected $template_id = 0;
        protected $parent_id = 0;
        protected $entry_date;
        protected $edit_date;
        protected $edit_by;
    class EntryTranslationTitleGateway extends Gateway
    {
        protected static $_table_name = 'publisher_titles';
        protected static $_primary_key = 'id';
    
        protected $site_id;
        protected $channel_id;
        protected $author_id;
        protected $entry_id;
        protected $lang_id;
        protected $status;
        protected $title;
        protected $url_title;
        protected $page_url;
        protected $hide_in_nav = 'n';
        protected $template_id = 0;
        protected $parent_id = 0;
        protected $entry_date;
        protected $edit_date;
        protected $edit_by;
    }
    class EntryTranslationDataGateway extends VariableColumnGateway
    {
        protected static $_table_name = 'publisher_data';
        protected static $_primary_key = 'id';
    
        protected $site_id;
        protected $channel_id;
        protected $entry_id;
        protected $lang_id;
        protected $status;
    }
  • #2 / Mar 31, 2017 5:12pm

    Kevin Cupp's avatar

    Kevin Cupp

    669 posts

    Sorry to say I don’t know off hand. Would be great to have something reproducible. Wonder if their data is in some kind of inconsistent state. We use VariableColumnModel all over the place for some important stuff, so you’d think we’d have run into it by now.

  • #3 / Apr 04, 2017 9:46am

    litzinger's avatar

    litzinger

    564 posts

    Yeah, I figured that would be the answer, but thought I’d throw it out here to see if it rang any bells. The customer decided to un-install, then re-install and then enter the translations/drafts, which seems to work fine. If it comes up again I’ll dig deeper into it, but for now just chalking it up to bad data, which I haven’t seen from anyone else or myself. ¯_(ツ)_/¯

  • #4 / Apr 18, 2017 11:23am

    litzinger's avatar

    litzinger

    564 posts

    Looks like I have another similar report. Fun.

  • #5 / Apr 19, 2017 9:29am

    litzinger's avatar

    litzinger

    564 posts

    Ok, I found a work around. Still unsure what is causing the issue, but I’m beginning to feel like its nested deep in EE’s model layer or something b/c it only occurs when I make this query. Its returning a totally different entry unrelated to the entry it should be querying. Its picking the same wrong entry every time, so its not randomly selecting an entry each page load. The $entryId, $language, and $status variables are all 100% correct when passed to that model for querying.

    $entry = ee('Model')->get(EntryTranslation::NAME)
                ->filter('entry_id', $entryId)
                ->filter('lang_id', $language)
                ->filter('status', $status)
                ->first();

    The work around is this:

    $qry = ee()->db->where([
                'entry_id' => $entryId,
                'lang_id' => $language,
                'status' => $status
            ])->get('publisher_titles');
            
            $entry = null;
    
            if ($qry->num_rows() == 1) {
                $entry = ee('Model')->get(EntryTranslation::NAME)
                    ->filter('id', $qry->row('id'))
                    ->first();
            }

    I’ve disabled caching, step debugged every method call in the process and its correct in Publisher’s codebase until it hits that query above, then it all goes haywire. If the issue involves more than just EE’s core models, e.g Publisher is triggering something else where, I can’t find it.

  • #6 / Apr 19, 2017 11:30am

    Kevin Cupp's avatar

    Kevin Cupp

    669 posts

    Very odd. I can’t reproduce with our ChannelEntry model by also querying by random foreign keys. Were you able to see what the generated query looked like in the query profiler? Curious if the query is getting modified before it’s run and how it’s modified.

  • #7 / Apr 21, 2017 9:17am

    litzinger's avatar

    litzinger

    564 posts

    Duh, good call. So that reveals a little something. I had to post it in a gist: https://gist.github.com/litzinger/257ce3309e39afbe4b85d90fffda9faf

    One of the query conditionals contains this, but its not searching _publisher_titles where entry_id = 1630 too, so that may be the issue. Its not joining correctly?

    AND ( publisher_m_EntryTranslation_publisher_data.entry_id = 1630

  • #8 / Apr 21, 2017 9:26am

    litzinger's avatar

    litzinger

    564 posts

    Ugh, think I found the issue. So my EntryTranslation model has $_primary_key = ‘id’; not ‘entry_id’, so its finding the id 36 in both tables (publisher_titles and publisher_data), but the entry_id does not match, thus returning the wrong data. So its finding the right rows, except the rows are not in sync.

    Have any ideas on how to resolve this? I can’t use entry_id as a primary key b/c I have multiple translations and drafts in the table, so I need a unique primary key, thus the id column. Does EE’s model understand composite primary keys, e.g. lang_id, status, entry_id?

    edit: I have a sicking feeling in my stomach that this is not a small fix/refactor for me if composite primary keys aren’t possible with the Model.

  • #9 / Apr 21, 2017 12:01pm

    Kevin Cupp's avatar

    Kevin Cupp

    669 posts

    So the id column isn’t unique, is that correct? If it’s not auto-incrementing, how have you been filling it in? I see it’s not even listed as an available property. Or has it been letting you anyway?

    There’s no support for composite primary keys at the moment, sorry.

  • #10 / Apr 21, 2017 12:10pm

    litzinger's avatar

    litzinger

    564 posts

    Its unique and has been auto-incrementing, I just think there is a way that they aren’t always in sync. So id 1 in the data table may not have the corresponding entry data for id 1 in the titles column.

    Its been saving data correctly, so I think I can continue to keep using my EntryTranslation model with the title and data gateways to save data, and I think I have a work around b/c I have an entry service with a find() method on it, which is what I’m using pretty much everywhere to search for an entry and returns an EntryTranslation model. This is what I literally just finished adding when I got the email notification of your last comment smile

    Basically I went back to my Publisher 1 codebase to my main find()/get() method and ported it so it creates an EntryTranslation model, thus the many, many other typehints in my codebase that are expecting an EntryTranslation model actually get what they’re wanting (thats the part that gave me the sick feeling earlier).

    private function get(
            $entryId,
            $langId = null,
            $status = null
        ){
            $where = [
                't.entry_id' => $entryId,
                'd.entry_id' => $entryId,
                't.status' => $status,
                'd.status' => $status,
                't.lang_id' => $langId,
                'd.lang_id' => $langId
            ];
    
            $selectFields = [];
    
            /** @var ChannelField $channelField */
            $channelField = ee(ChannelField::NAME);
            $customFields = $channelField->getCustomFieldNames();
    
            foreach ($customFields as $k => $name) {
                $selectFields[] = 'd.' . $k . ' AS `' . $name . '`';
            }
    
            $selectFieldsStr = implode(', ', $selectFields);
    
            /** @var \CI_DB_result $query */
            $query = ee()->db->select('t.*, ' . $selectFieldsStr)
                ->from('exp_publisher_titles AS t')
                ->join('exp_publisher_data AS d', 't.entry_id = d.entry_id')
                ->where($where)
                ->get();
    
            /** @var EntryTranslation $entry */
            $entry = ee('Model')->make(EntryTranslation::NAME);
    
            if ($query->num_rows() == 1) {
                $entry->fill((array) $query->first_row());
                return $entry;
            }
    
            return null;
        }
  • #11 / Apr 21, 2017 1:26pm

    Kevin Cupp's avatar

    Kevin Cupp

    669 posts

    Strange. It sounds like your model is set up like our ChannelEntry model but we haven’t had any out-of-sync issues between those two tables. Well, glad you’ve got a workaround, sorry it was a pain.

  • #12 / Apr 21, 2017 1:31pm

    litzinger's avatar

    litzinger

    564 posts

    Yeah I explicitly followed the ChannelEntry model when I was doing this b/c thats what Publisher does… basically create a copy of the entries in different tables. You haven’t had the issue b/c the primary key is entry_id and there is always a 1 to 1 relationship b/w the title and data tables.

    But yeah, hoping this fix, though not ideal, is all I need b/c I really don’t want to re-write other classes smile

    Thanks for asking the right questions… it pushed me in the right direction to figure out what the real issue was.

ExpressionEngine News

#eecms, #events, #releases