public function onAfterWrite()
 {
     parent::onAfterWrite();
     // This is to ensure this only fires once on each write
     if ($this->getFirstWrite()) {
         // Get Array of updated fields
         $UpdatedDataFields = $this->owner->getChangedFields(true, 2);
         // Get HasManyList of this Members MCSubscriptions
         $subs = $this->owner->getComponents("MCSubscriptions");
         // If the Member Has One or More Subscriptions
         if (is_object($subs) && $subs->exists()) {
             // Foreach of This Members Subscription Objects
             foreach ($subs as $sub) {
                 SS_Log::log("Subscription ID = " . $sub->ID, SS_Log::NOTICE);
                 // Get DataList of MC List Field Mappings (Excluding LastVisited) Which Are On The Member Class && In A MCList Which Concerns This Member (i.e. One They Are Subscribed To)
                 // (as if LastVisited is the ONLY updated field it just represents a site login, not an actual manual MC data field update)
                 $dl = new DataList("MCListField");
                 $mappings = $dl->where("\"OnClass\" = 'Member' AND \"MCListID\" = '" . $sub->MCListID . "' AND \"SyncDirection\" IN ('Export','Both') AND \"FieldName\" != 'LastVisited'");
                 // Foreach Mapping Record
                 foreach ($mappings as $mapping) {
                     SS_Log::log("Mapping Field Name = " . $mapping->FieldName, SS_Log::NOTICE);
                     // If The Member FieldName is One of the Updated Fields
                     if (isset($UpdatedDataFields[$mapping->FieldName])) {
                         // Mark the Subscription as Being Updated
                         SS_Log::log("\$UpdatedDataFields['" . $mapping->FieldName . "'] Is Set, doing \$sub->write();", SS_Log::NOTICE);
                         $sub->setSyncMailChimp($this->getSyncMailChimp());
                         // Set MCSubscriber Sync to MailChimp Based on This (Member) Sync State
                         $sub->setForceAdditionalWrite(true);
                         $sub->write();
                         break;
                     }
                 }
             }
         } else {
             if (isset($UpdatedDataFields["ID"])) {
                 // Creation Write
                 // Add New or Link Existing Subscription Records
                 $subs = MCSubscription::get()->where("\"Email\" = '" . $this->owner->Email . "'");
                 if (is_object($subs) && $subs->exists()) {
                     // Link Each Subscriber Object to this Member
                     foreach ($subs as $sub) {
                         $sub->setForceAdditionalWrite(true);
                         $this->owner->getComponents("MCSubscriptions")->add($sub);
                     }
                 } else {
                     // Get the Default MailChimp List To Relate The New Subscription To
                     $MCList = MCList::get()->sort("\"SortOrder\" ASC")->first();
                     if (is_object($MCList) && $MCList->exists()) {
                         // Create New Subscriber Object and Link to New Member
                         $sub = new MCSubscription();
                         $sub->setField("FirstName", $this->owner->FirstName);
                         $sub->setField("Surname", $this->owner->Surname);
                         $sub->setField("Email", $this->owner->Email);
                         $sub->setField("MemberID", $this->owner->ID);
                         $sub->setField("MCListID", $MCList->ID);
                         $sub->write();
                         // Link the New Subscriber Object to this Member
                         $this->owner->getComponents("MCSubscriptions")->add($sub);
                     } else {
                         SS_Log::log("No MCList object available to add new MCSubscriptions to when saving Member #" . $this->owner->ID, SS_Log::NOTICE);
                     }
                 }
             }
         }
     }
 }
 public function UpdateMemberData($list = null, $checkpoint = null, $listFields = array())
 {
     if (!is_object($list) || !is_object($checkpoint)) {
         SS_Log::log("UpdateMemberData() Requires MCList Object and Sync Checkpoint Parameters!", SS_Log::ERR);
         return false;
     }
     $api = new MCAPI($this->apikey);
     $retval = $api->listMembers($list->ListID, 'updated', $checkpoint->LastSuccessfulSync, 0, 5000);
     if ($api->errorCode) {
         SS_Log::log("API Call Failed: listMembers('" . $list->ListID . "', 'updated', '" . $checkpoint->LastSuccessfulSync . "', 0, 5000); Error Code = " . $api->errorCode . " | Error Message = " . $api->errorMessage, SS_Log::ERR);
         return false;
     } else {
         SS_Log::log("API Call Success: listMembers('" . $list->ListID . "', 'updated', '" . $checkpoint->LastSuccessfulSync . "', 0, 5000); Returned Members = " . $retval['total'], SS_Log::NOTICE);
         if ($retval['total'] > 0) {
             foreach ($retval['data'] as $member) {
                 $where = "\"MCListID\" = '" . $list->ID . "' AND ";
                 // Try and Lookup Member Data By E-mail To Get MailChimp ID for More Accurate Updates
                 // (i.e. E-mail Updated on MailChimp Would Otherwise Create New Sub Rather Than Update Existing)
                 $mcMember = $api->listMemberInfo($list->ListID, $member['email']);
                 if ($api->errorCode) {
                     // (Should Always Return Data As Members Yet To Confirm Subscribption Shouldn't Be Returned in listMembers() But Just Incase Fall Back On E-mail)
                     SS_Log::log(" - API Call Failed: listMemberInfo('" . $list->ListID . "', '" . $member['email'] . "'); Error Code = " . $api->errorCode . " | Error Message = " . $api->errorMessage, SS_Log::ERR);
                     $where .= "LOWER(\"Email\") = '" . strtolower($member['email']) . "'";
                 } else {
                     SS_Log::log(" - API Call Success: listMemberInfo('" . $list->ListID . "', '" . $member['email'] . "');", SS_Log::NOTICE);
                     $where .= "\"MCMemberID\" = '" . $mcMember['data'][0]['web_id'] . "'";
                 }
                 SS_Log::log(" - MEMBER " . $member['email'] . " (MCID: " . $mcMember['data'][0]['web_id'] . ")", SS_Log::NOTICE);
                 SS_Log::log(" - MailChimp Updated: " . $member['timestamp'], SS_Log::NOTICE);
                 $dl = new DataList("MCSubscription");
                 $sub = $dl->where($where)->first();
                 if (empty($sub)) {
                     // Newly Added Subscription
                     $sub = new MCSubscription();
                     $sub->setField("MCListID", $list->ID);
                     // See if There is a Related Member Email
                     $dl = new DataList("Member");
                     $relatedMember = $dl->where("LOWER(\"Email\") = '" . strtolower($member['email']) . "'")->first();
                     if (!empty($relatedMember->ID)) {
                         $sub->setField("MemberID", $relatedMember->ID);
                     }
                 } else {
                     $relatedMember = $sub->getComponent("Member");
                 }
                 // We Will Need To Set Subscribed To True For Newly Added Members (Including Members Who Took A While To Confirm (DoubleOpt In) And Got Marked As Unsubscribed)
                 // Setting Subscribed True Even If Its Already True Wont Do Any Harm Anyway
                 $sub->setField("Subscribed", 1);
                 SS_Log::log(" - Site MC Data Updated: " . gmdate('Y-m-d H:i:s', strtotime($sub->LastEdited)), SS_Log::NOTICE);
                 /*
                 // The Below If Should Never Return True If Exporting Data From The Website - Mail Chimp On Write(), Unless The API Call Were To Fail On Export
                 // $sub->LastEdited Also Takes Into Account The Last Time MCList Fields On Member Were Updated (See MCMemberExtension onBeforeWrite())
                 // Take $sub->LastEdited As A Marker For Last Time ANY Data Relating To This MCList Was Manually Updated
                 if(strtotime($sub->LastEdited) > strtotime($member['timestamp'])) {
                     // MailChimp Data Has Been SuperSeded By More Recent Website Managed MailChimp Data Update (Skip Update)
                     SS_Log::log(" - Site MC Data Updated: ".$sub->LastEdited, SS_Log::WARN);
                     SS_Log::log(" - Data Superseded By Site MC Data", SS_Log::WARN);
                     continue;
                 }
                 */
                 // Push MCSubscription and (If Exists) Member Objects In To $class Array
                 $Class['MCSubscription'] = $sub;
                 SS_Log::log(" - Subscriber ID = " . $sub->ID, SS_Log::NOTICE);
                 if (!empty($relatedMember->ID)) {
                     // getComponent() Returns an Empty Component if None Are Found (So Check For Existance of ID)
                     $Class['Member'] = $relatedMember;
                     SS_Log::log(" - Related Member ID = " . $Class['Member']->ID, SS_Log::NOTICE);
                 } else {
                     SS_Log::log(" - No Related Member", SS_Log::NOTICE);
                 }
                 // $mcMember Array Created Above When Doing listMemberInfo() Call
                 if (isset($mcMember['data']) && !empty($mcMember['data'])) {
                     // Set The MailChimp Member (Web) && Email ID's for this Member
                     $Class["MCSubscription"]->setField("MCMemberID", $mcMember['data'][0]['web_id']);
                     $Class["MCSubscription"]->setField("MCEmailID", $mcMember['data'][0]['id']);
                     foreach ($mcMember['data'][0]['merges'] as $mergeTag => $Value) {
                         // If Current Merge Tag is in List Field Mapping (i.e. is to be synced)
                         if (isset($listFields[$mergeTag])) {
                             $ClassName = $listFields[$mergeTag]['OnClass'];
                             $FieldName = $listFields[$mergeTag]['FieldName'];
                             // If We Are Updating a 'Subscription' Object Which Has No Related Member $Class['Member'] Will Not Contain a Member Object (So Just Dump The Data)
                             if (isset($Class[$ClassName]) && !empty($FieldName) && !empty($Value)) {
                                 SS_Log::log(" -- \$Class['" . $ClassName . "']->setField('" . $FieldName . "', '" . $Value . "');", SS_Log::NOTICE);
                                 $Class[$ClassName]->setField($FieldName, $Value);
                             }
                         }
                     }
                     // write() The Updated Object(s)
                     $Class["MCSubscription"]->setSyncMailChimp(false);
                     $Class["MCSubscription"]->write();
                     if (!empty($Class["Member"])) {
                         $Class["Member"]->setSyncMailChimp(false);
                         $Class["Member"]->write();
                     }
                 }
                 // END listMemberInfo() -> if($api->errorCode) {} else {
             }
             // END foreach($retval['data] as $member) {
         }
         // END if($retval['total] > 0) {
     }
     // END listMembers() -> if($api->errorCode) {} else {
     // Assume Success If We Havn't Already Returned False By This Point
     return true;
 }