We use cookies to improve your experience. No personal information is gathered and we don't serve ads. Cookies Policy.

ExpressionEngine Logo ExpressionEngine
Features Pricing Support Find A Developer
Partners Upgrades
Blog Add-Ons Learn
Docs Forums University
Log In or Sign Up
Log In Sign Up
ExpressionEngine Logo
Features Pro new Support Find A Developer
Partners Upgrades
Blog Add-Ons Learn
Docs Forums University Blog
  • Home
  • Forums

Possible issue with VariableColumnModel

Developer Preview

Brian Litzinger's avatar
Brian Litzinger
693 posts
8 years ago
Brian Litzinger's avatar Brian Litzinger

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;
}
       
Kevin Cupp's avatar
Kevin Cupp
791 posts
8 years ago
Kevin Cupp's avatar Kevin Cupp

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.

       
Brian Litzinger's avatar
Brian Litzinger
693 posts
8 years ago
Brian Litzinger's avatar Brian Litzinger

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. ¯_(ツ)_/¯

       
Brian Litzinger's avatar
Brian Litzinger
693 posts
8 years ago
Brian Litzinger's avatar Brian Litzinger

Looks like I have another similar report. Fun.

       
Brian Litzinger's avatar
Brian Litzinger
693 posts
8 years ago
Brian Litzinger's avatar Brian Litzinger

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.

       
Kevin Cupp's avatar
Kevin Cupp
791 posts
8 years ago
Kevin Cupp's avatar Kevin Cupp

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.

       
Brian Litzinger's avatar
Brian Litzinger
693 posts
8 years ago
Brian Litzinger's avatar Brian Litzinger

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

       
Brian Litzinger's avatar
Brian Litzinger
693 posts
8 years ago
Brian Litzinger's avatar Brian Litzinger

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.

       
Kevin Cupp's avatar
Kevin Cupp
791 posts
8 years ago
Kevin Cupp's avatar Kevin Cupp

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.

       
Brian Litzinger's avatar
Brian Litzinger
693 posts
8 years ago
Brian Litzinger's avatar Brian Litzinger

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 😊

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;
    }
       
Kevin Cupp's avatar
Kevin Cupp
791 posts
8 years ago
Kevin Cupp's avatar Kevin Cupp

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.

       
Brian Litzinger's avatar
Brian Litzinger
693 posts
8 years ago
Brian Litzinger's avatar Brian Litzinger

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 😊

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

       

Reply

Sign In To Reply

ExpressionEngine Home Features Pro Contact Version Support
Learn Docs University Forums
Resources Support Add-Ons Partners Blog
Privacy Terms Trademark Use License

Packet Tide owns and develops ExpressionEngine. © Packet Tide, All Rights Reserved.