diff --git a/QvitterPlugin.php b/QvitterPlugin.php index 742a1ff..771de31 100644 --- a/QvitterPlugin.php +++ b/QvitterPlugin.php @@ -150,6 +150,12 @@ class QvitterPlugin extends Plugin { return true; } + public function onBeforePluginCheckSchema() + { + QvitterNotification::beforeSchemaUpdate(); + return true; + } + // route/reroute urls public function onRouterInitialized($m) { diff --git a/classes/QvitterNotification.php b/classes/QvitterNotification.php index 869827c..3c77cdd 100644 --- a/classes/QvitterNotification.php +++ b/classes/QvitterNotification.php @@ -19,8 +19,8 @@ class QvitterNotification extends Managed_DataObject return array( 'fields' => array( 'id' => array('type' => 'serial', 'not null' => true), - 'to_profile_id' => array('type' => 'int', 'description' => 'the profile being notified'), - 'from_profile_id' => array('type' => 'int', 'description' => 'the profile that is notifying'), + 'to_profile_id' => array('type' => 'int', 'not null'=>true, 'description' => 'the profile being notified'), + 'from_profile_id' => array('type' => 'int', 'not null'=>true, 'description' => 'the profile that is notifying'), 'ntype' => array('type' => 'varchar', 'length' => 7, 'description' => 'reply, like, mention or follow'), 'notice_id' => array('type' => 'int', 'description' => 'id for the reply or mention or notice being faved'), 'is_seen' => array('type' => 'int', 'size' => 'tiny', 'default' => 0, 'description' => 'if the notification has been seen'), @@ -30,7 +30,8 @@ class QvitterNotification extends Managed_DataObject 'foreign keys' => array( 'qvitternotification_to_profile_id_fkey' => array('profile', array('to_profile_id' => 'id')), 'qvitternotification_from_profile_id_fkey' => array('profile', array('from_profile_id' => 'id')), - 'qvitternotification_notice_id_fkey' => array('notice', array('notice_id' => 'id')), + // removing this because there can be rows without related notice_id + //'qvitternotification_notice_id_fkey' => array('notice', array('notice_id' => 'id')), ), 'indexes' => array( 'qvitternotification_created_idx' => array('created'), @@ -54,5 +55,43 @@ class QvitterNotification extends Managed_DataObject return $result; } + static public function beforeSchemaUpdate() + { + printfnq("\nEnsuring no NULL values for foreign keys in QvitterNotification..."); + // Because constraints to profile and notice table assume not null, we must + // remove any values in these columns that are NULL (or 0), because they + // are invalid anyway. + $qn = new QvitterNotification(); + foreach (['to_profile_id', 'from_profile_id'] as $field) { + $qn->whereAdd(sprintf('%s is NULL', $field), 'OR'); + $qn->whereAdd(sprintf('%s = 0', $field), 'OR'); + } + if ($qn->find()) { + printfnq(" removing {$qn->N} rows..."); + while ($qn->fetch()) { + $qn->delete(); + } + } + printfnq("DONE.\n"); + printfnq("Ensuring no dead profile or notice IDs are stored in QvitterNotification..."); + // We could probably build a single statement for this but I just want it done... + // or maybe be smart and take it directly from our defined 'foreign keys'... but oh well! + $constraints = ['to_profile_id' => 'profile:id', + 'from_profile_id' => 'profile:id']; + foreach ($constraints as $field=>$foreign) { + $qn = new QvitterNotification(); + $qn->selectAdd(); + $qn->selectAdd('qvitternotification.id'); // to avoid confusion with profile.id, also we only need the primary key + $qn->joinAdd([$field, $foreign], 'LEFT'); + $qn->whereAdd(str_replace(':', '.', $foreign).' IS NULL'); + if ($qn->find()) { + printfnq("\n{$field}: {$qn->N} rows..."); + while ($qn->fetch()) { + $qn->delete(); + } + } + } + printfnq("DONE.\n"); + } }