diff --git a/lib/Config/Initializer.php b/lib/Config/Initializer.php index 77c71b5d9d..e5f5d45e45 100644 --- a/lib/Config/Initializer.php +++ b/lib/Config/Initializer.php @@ -8,7 +8,7 @@ if(!defined('ABSPATH')) exit; class Initializer { function __construct($params = array( - 'file' => '', + 'file' => '', 'version' => '1.0.0' )) { Env::init($params['file'], $params['version']); @@ -40,6 +40,8 @@ class Initializer { $segments = Env::$db_prefix . 'segments'; $subscriber_segment = Env::$db_prefix . 'subscriber_segment'; $newsletter_segment = Env::$db_prefix . 'newsletter_segment'; + $custom_fields = Env::$db_prefix . 'custom_fields'; + $subscriber_custom_field = Env::$db_prefix . 'subscriber_custom_field'; define('MP_SUBSCRIBERS_TABLE', $subscribers); define('MP_SETTINGS_TABLE', $settings); @@ -48,6 +50,8 @@ class Initializer { define('MP_SUBSCRIBER_SEGMENT_TABLE', $subscriber_segment); define('MP_NEWSLETTER_TEMPLATES_TABLE', $newsletter_templates); define('MP_NEWSLETTER_SEGMENT_TABLE', $newsletter_segment); + define('MP_CUSTOM_FIELDS_TABLE', $custom_fields); + define('MP_SUBSCRIBER_CUSTOM_FIELD_TABLE', $subscriber_custom_field); } function setupActivator() { @@ -82,4 +86,4 @@ class Initializer { $widget = new Widget(); $widget->init(); } -} +} \ No newline at end of file diff --git a/lib/Config/Migrator.php b/lib/Config/Migrator.php index c35e8a374d..f0d038531c 100644 --- a/lib/Config/Migrator.php +++ b/lib/Config/Migrator.php @@ -16,7 +16,9 @@ class Migrator { 'newsletter_templates', 'segments', 'subscriber_segment', - 'newsletter_segment' + 'newsletter_segment', + 'custom_fields', + 'subscriber_custom_field' ); } @@ -133,6 +135,31 @@ class Migrator { return $this->sqlify(__FUNCTION__, $attributes); } + function custom_fields() { + $attributes = array( + 'id mediumint(9) NOT NULL AUTO_INCREMENT,', + 'name varchar(90) NOT NULL,', + 'created_at TIMESTAMP NOT NULL DEFAULT 0,', + 'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,', + 'PRIMARY KEY (id),', + 'UNIQUE KEY name (name)' + ); + return $this->sqlify(__FUNCTION__, $attributes); + } + + function subscriber_custom_field() { + $attributes = array( + 'id mediumint(9) NOT NULL AUTO_INCREMENT,', + 'subscriber_id mediumint(9) NOT NULL,', + 'custom_field_id mediumint(9) NOT NULL,', + 'value varchar(255) NOT NULL,', + 'created_at TIMESTAMP NOT NULL DEFAULT 0,', + 'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,', + 'PRIMARY KEY (id)' + ); + return $this->sqlify(__FUNCTION__, $attributes); + } + private function sqlify($model, $attributes) { $table = $this->prefix . $model; diff --git a/lib/Models/CustomField.php b/lib/Models/CustomField.php new file mode 100644 index 0000000000..ca98d821d1 --- /dev/null +++ b/lib/Models/CustomField.php @@ -0,0 +1,25 @@ +addValidations('name', array( + 'required' => __('You need to specify a name.') + )); + } + + function subscribers() { + return $this->has_many_through( + __NAMESPACE__ . '\Subscriber', + __NAMESPACE__ . '\SubscriberCustomField', + 'custom_field_id', + 'subscriber_id' + ); + } +} \ No newline at end of file diff --git a/lib/Models/Subscriber.php b/lib/Models/Subscriber.php index 7275f472b8..7e96cc6bcb 100644 --- a/lib/Models/Subscriber.php +++ b/lib/Models/Subscriber.php @@ -132,6 +132,15 @@ class Subscriber extends Model { ); } + function customFields() { + return $this->has_many_through( + __NAMESPACE__.'\CustomField', + __NAMESPACE__.'\SubscriberCustomField', + 'subscriber_id', + 'custom_field_id' + )->select_expr(MP_SUBSCRIBER_CUSTOM_FIELD_TABLE.'.value'); + } + static function createOrUpdate($data = array()) { $subscriber = false; diff --git a/lib/Models/SubscriberCustomField.php b/lib/Models/SubscriberCustomField.php new file mode 100644 index 0000000000..e12dddc2bd --- /dev/null +++ b/lib/Models/SubscriberCustomField.php @@ -0,0 +1,12 @@ +writeln('Cleaning up database...'); $models = array( - 'Subscriber', - 'Setting', + 'CustomField', 'Newsletter', + 'NewsletterSegment', + 'NewsletterTemplate', 'Segment', + 'Setting', + 'Subscriber', + 'SubscriberCustomField', 'SubscriberSegment' ); $destroy = function ($model) { diff --git a/tests/unit/Models/CustomFieldCest.php b/tests/unit/Models/CustomFieldCest.php new file mode 100644 index 0000000000..9fb6dc8b63 --- /dev/null +++ b/tests/unit/Models/CustomFieldCest.php @@ -0,0 +1,114 @@ +before_time = time(); + $this->data = array( + 'name' => 'city', + ); + $this->customField = CustomField::create(); + $this->customField->hydrate($this->data); + $this->saved = $this->customField->save(); + $this->subscribersData = array( + array( + 'first_name' => 'John', + 'last_name' => 'Mailer', + 'email' => 'john@mailpoet.com' + ), + array( + 'first_name' => 'Mike', + 'last_name' => 'Smith', + 'email' => 'mike@maipoet.com' + ) + ); + } + + function itCanBeCreated() { + expect($this->saved)->equals(true); + } + + function itHasToBeValid() { + expect($this->saved)->equals(true); + $empty_model = CustomField::create(); + expect($empty_model->save())->notEquals(true); + $validations = $empty_model->getValidationErrors(); + expect(count($validations))->equals(1); + } + + function itHasACreatedAtOnCreation() { + $customField = CustomField::where('name', $this->data['name']) + ->findOne(); + $time_difference = strtotime($customField->created_at) >= $this->before_time; + expect($time_difference)->equals(true); + } + + function itHasAnUpdatedAtOnCreation() { + $customField = CustomField::where('name', $this->data['name']) + ->findOne(); + $time_difference = strtotime($customField->updated_at) >= $this->before_time; + expect($time_difference)->equals(true); + } + + function itKeepsTheCreatedAtOnUpdate() { + $customField = CustomField::where('name', $this->data['name']) + ->findOne(); + $old_created_at = $customField->created_at; + $customField->name = 'new name'; + $customField->save(); + expect($old_created_at)->equals($customField->created_at); + } + + function itUpdatesTheUpdatedAtOnUpdate() { + $customField = CustomField::where('name', $this->data['name']) + ->findOne(); + $update_time = time(); + $customField->name = 'new name'; + $customField->save(); + $time_difference = strtotime($customField->updated_at) >= $update_time; + expect($time_difference)->equals(true); + } + + function itCanHaveManySubscribers() { + foreach ($this->subscribersData as $data) { + $subscriber = Subscriber::create(); + $subscriber->hydrate($data); + $subscriber->save(); + $association = SubscriberCustomField::create(); + $association->subscriber_id = $subscriber->id; + $association->custom_field_id = $this->customField->id; + $association->save(); + } + $customField = CustomField::findOne($this->customField->id); + $subscribers = $customField->subscribers() + ->findArray(); + expect(count($subscribers))->equals(2); + } + + function itCanStoreCustomFieldValue() { + $subscriber = Subscriber::create(); + $subscriber->hydrate($this->subscribersData[0]); + $subscriber->save(); + $association = SubscriberCustomField::create(); + $association->subscriber_id = $subscriber->id; + $association->custom_field_id = $this->customField->id; + $association->value = 'test'; + $association->save(); + $customField = CustomField::findOne($this->customField->id); + $subscriber = $customField->subscribers() + ->findOne(); + expect($subscriber->value)->equals($association->value); + } + + function _after() { + ORM::forTable(CustomField::$_table) + ->deleteMany(); + ORM::forTable(Subscriber::$_table) + ->deleteMany(); + ORM::forTable(SubscriberCustomField::$_table) + ->deleteMany(); + } +} \ No newline at end of file diff --git a/tests/unit/Models/SubscriberCest.php b/tests/unit/Models/SubscriberCest.php index 603044f48a..f65e6a067a 100644 --- a/tests/unit/Models/SubscriberCest.php +++ b/tests/unit/Models/SubscriberCest.php @@ -1,6 +1,8 @@ 'Mailer', 'email' => 'john@mailpoet.com' ); - $this->subscriber = Subscriber::create(); $this->subscriber->hydrate($this->data); $this->saved = $this->subscriber->save(); @@ -21,7 +22,7 @@ class SubscriberCest { expect($this->saved)->equals(true); } - function itHasAFirstName() { + function itHasFirstName() { $subscriber = Subscriber::where('email', $this->data['email']) ->findOne(); @@ -29,7 +30,7 @@ class SubscriberCest { ->equals($this->data['first_name']); } - function itHasALastName() { + function itHasLastName() { $subscriber = Subscriber::where('email', $this->data['email']) ->findOne(); @@ -37,7 +38,7 @@ class SubscriberCest { ->equals($this->data['last_name']); } - function itHasAnEmail() { + function itHasEmail() { $subscriber = Subscriber::where('email', $this->data['email']) ->findOne(); @@ -52,59 +53,60 @@ class SubscriberCest { expect($saved)->notEquals(true); } - function itHasAStatus() { + function itHasStatus() { $subscriber = Subscriber::where('email', $this->data['email']) - ->findOne(); - + ->findOne(); expect($subscriber->status)->equals('unconfirmed'); } function itCanChangeStatus() { - $subscriber = Subscriber::where('email', $this->data['email'])->findOne(); + $subscriber = Subscriber::where('email', $this->data['email']) + ->findOne(); $subscriber->status = 'subscribed'; expect($subscriber->save())->equals(true); - $subscriber_updated = Subscriber::where( 'email', $this->data['email'] - )->findOne(); + ) + ->findOne(); expect($subscriber_updated->status)->equals('subscribed'); } - function itHasASearchFilter() { - $subscriber = Subscriber::filter('search', 'john')->findOne(); + function itHasSearchFilter() { + $subscriber = Subscriber::filter('search', 'john') + ->findOne(); expect($subscriber->first_name)->equals($this->data['first_name']); - - $subscriber = Subscriber::filter('search', 'mailer')->findOne(); + $subscriber = Subscriber::filter('search', 'mailer') + ->findOne(); expect($subscriber->last_name)->equals($this->data['last_name']); - - $subscriber = Subscriber::filter('search', 'mailpoet')->findOne(); + $subscriber = Subscriber::filter('search', 'mailpoet') + ->findOne(); expect($subscriber->email)->equals($this->data['email']); } - function itHasAGroupFilter() { - $subscribers = Subscriber::filter('groupBy', 'unconfirmed')->findMany(); - foreach($subscribers as $subscriber) { + function itHasGroupFilter() { + $subscribers = Subscriber::filter('groupBy', 'unconfirmed') + ->findMany(); + foreach ($subscribers as $subscriber) { expect($subscriber->status)->equals('unconfirmed'); } - - $subscribers = Subscriber::filter('groupBy', 'subscribed')->findMany(); - foreach($subscribers as $subscriber) { + $subscribers = Subscriber::filter('groupBy', 'subscribed') + ->findMany(); + foreach ($subscribers as $subscriber) { expect($subscriber->status)->equals('subscribed'); } - - $subscribers = Subscriber::filter('groupBy', 'unsubscribed')->findMany(); - foreach($subscribers as $subscriber) { + $subscribers = Subscriber::filter('groupBy', 'unsubscribed') + ->findMany(); + foreach ($subscribers as $subscriber) { expect($subscriber->status)->equals('unsubscribed'); } } - function itCanHaveASegment() { + function itCanHaveSegment() { $segmentData = array( 'name' => 'some name' ); - $segment = Segment::create(); $segment->hydrate($segmentData); $segment->save(); @@ -112,32 +114,46 @@ class SubscriberCest { $association->subscriber_id = $this->subscriber->id; $association->segment_id = $segment->id; $association->save(); - $subscriber = Subscriber::findOne($this->subscriber->id); - $subscriberSegment = $subscriber->segments()->findOne(); + $subscriberSegment = $subscriber->segments() + ->findOne(); expect($subscriberSegment->id)->equals($segment->id); } + + function itCanHaveCustomField() { + $customFieldData = array( + 'name' => 'city' + ); + $customField = CustomField::create(); + $customField->hydrate($customFieldData); + $customField->save(); + $association = SubscriberCustomField::create(); + $association->subscriber_id = $this->subscriber->id; + $association->custom_field_id = $customField->id; + $association->save(); + $subscriber = Subscriber::findOne($this->subscriber->id); + $subscriberCustomField = $subscriber->customFields() + ->findOne(); + expect($subscriberCustomField->id)->equals($customField->id); + } function itCanCreateOrUpdate() { $data = array( - 'email' => 'john.doe@mailpoet.com', + 'email' => 'john.doe@mailpoet.com', 'first_name' => 'John', 'last_name' => 'Doe' ); - $result = Subscriber::createOrUpdate($data); expect($result)->equals(true); - $record = Subscriber::where('email', $data['email']) ->findOne(); expect($record->first_name)->equals($data['first_name']); expect($record->last_name)->equals($data['last_name']); - $record->last_name = 'Mailer'; $result = Subscriber::createOrUpdate($record->asArray()); expect($result)->equals(true); - - $record = Subscriber::where('email', $data['email'])->findOne(); + $record = Subscriber::where('email', $data['email']) + ->findOne(); expect($record->last_name)->equals('Mailer'); } @@ -148,5 +164,9 @@ class SubscriberCest { ->deleteMany(); ORM::forTable(SubscriberSegment::$_table) ->deleteMany(); + ORM::forTable(CustomField::$_table) + ->deleteMany(); + ORM::forTable(SubscriberCustomField::$_table) + ->deleteMany(); } -} +} \ No newline at end of file