diff --git a/src/Campaigns/Actions/ConvertQueryDataToCampaign.php b/src/Campaigns/Actions/ConvertQueryDataToCampaign.php index 4c13e2fd78..a064898b87 100644 --- a/src/Campaigns/Actions/ConvertQueryDataToCampaign.php +++ b/src/Campaigns/Actions/ConvertQueryDataToCampaign.php @@ -20,6 +20,7 @@ public function __invoke(object $queryObject): Campaign { return new Campaign([ 'id' => (int)$queryObject->id, + 'defaultFormId' => (int)$queryObject->defaultFormId, 'type' => new CampaignType($queryObject->type), 'enableCampaignPage' => (bool)$queryObject->enableCampaignPage, 'title' => $queryObject->title, diff --git a/src/Campaigns/Actions/LoadCampaignDetailsAssets.php b/src/Campaigns/Actions/LoadCampaignDetailsAssets.php index 2f0e0301c7..7a815c5918 100644 --- a/src/Campaigns/Actions/LoadCampaignDetailsAssets.php +++ b/src/Campaigns/Actions/LoadCampaignDetailsAssets.php @@ -4,7 +4,6 @@ use Give\Campaigns\Models\Campaign; use Give\Framework\Support\Facades\Scripts\ScriptAsset; -use Give\Helpers\Form\Utils; /** * @unreleased @@ -34,13 +33,12 @@ public function __invoke() ); $defaultForm = $campaign->defaultForm(); - $defaultFormTitle = Utils::isV3Form($defaultForm->id) ? $defaultForm->settings->formTitle : $defaultForm->title; wp_localize_script($handleName, 'GiveCampaignDetails', [ 'adminUrl' => admin_url(), 'currency' => give_get_currency(), 'isRecurringEnabled' => defined('GIVE_RECURRING_VERSION') ? GIVE_RECURRING_VERSION : null, - 'defaultForm' => $defaultFormTitle, + 'defaultForm' => $defaultForm->title, ] ); diff --git a/src/Campaigns/Controllers/CampaignRequestController.php b/src/Campaigns/Controllers/CampaignRequestController.php index 3b7a7ce371..357b2f3fa6 100644 --- a/src/Campaigns/Controllers/CampaignRequestController.php +++ b/src/Campaigns/Controllers/CampaignRequestController.php @@ -130,8 +130,7 @@ public function updateCampaign(WP_REST_Request $request) $campaign->goalType = new CampaignGoalType($value); break; case 'defaultFormId': - give(CampaignRepository::class)->updateDefaultCampaignForm($campaign, - $request->get_param('defaultFormId')); + give(CampaignRepository::class)->updateDefaultCampaignForm($campaign, $request->get_param('defaultFormId')); break; default: if ($campaign->hasProperty($key)) { @@ -147,6 +146,21 @@ public function updateCampaign(WP_REST_Request $request) return new WP_REST_Response($campaign->toArray()); } + /** + * @unreleased + * + * @throws Exception + */ + public function mergeCampaigns(WP_REST_Request $request): WP_REST_Response + { + $destinationCampaign = Campaign::find($request->get_param('id')); + $campaignsToMerge = Campaign::query()->whereIn('id', $request->get_param('campaignsToMergeIds'))->getAll(); + + $campaignsMerged = $destinationCampaign->merge(...$campaignsToMerge); + + return new WP_REST_Response($campaignsMerged); + } + /** * @unreleased diff --git a/src/Campaigns/Factories/CampaignFactory.php b/src/Campaigns/Factories/CampaignFactory.php index 5f467c0485..1cc64f9510 100644 --- a/src/Campaigns/Factories/CampaignFactory.php +++ b/src/Campaigns/Factories/CampaignFactory.php @@ -23,6 +23,7 @@ public function definition(): array return [ 'type' => CampaignType::CORE(), 'enableCampaignPage' => true, + 'defaultFormId' => 1, 'title' => __('GiveWP Campaign', 'give'), 'shortDescription' => __('Campaign short description', 'give'), 'longDescription' => __('Campaign long description', 'give'), diff --git a/src/Campaigns/Migrations/MigrateFormsToCampaignForms.php b/src/Campaigns/Migrations/MigrateFormsToCampaignForms.php index ce4e42f149..07ce2f3b1b 100644 --- a/src/Campaigns/Migrations/MigrateFormsToCampaignForms.php +++ b/src/Campaigns/Migrations/MigrateFormsToCampaignForms.php @@ -116,6 +116,7 @@ public function createCampaignForForm($formData): void DB::table('give_campaigns') ->insert([ + 'form_id' => $formId, 'campaign_type' => 'core', 'campaign_title' => $formTitle, 'status' => $this->mapFormToCampaignStatus($formStatus), @@ -134,7 +135,7 @@ public function createCampaignForForm($formData): void $campaignId = DB::last_insert_id(); - $this->addCampaignFormRelationship($formId, $campaignId, true); + $this->addCampaignFormRelationship($formId, $campaignId); } /** @@ -142,19 +143,18 @@ public function createCampaignForForm($formData): void */ protected function addUpgradedFormToCampaign($data): void { - $this->addCampaignFormRelationship($data->migratedFormId, $data->campaignId, false); + $this->addCampaignFormRelationship($data->migratedFormId, $data->campaignId); } /** * @unreleased */ - protected function addCampaignFormRelationship($formId, $campaignId, $isDefault) + protected function addCampaignFormRelationship($formId, $campaignId) { DB::table('give_campaign_forms') ->insert([ 'form_id' => $formId, - 'campaign_id' => $campaignId, - 'is_default' => $isDefault, + 'campaign_id' => $campaignId ]); } diff --git a/src/Campaigns/Migrations/RevenueTable/AddCampaignID.php b/src/Campaigns/Migrations/RevenueTable/AddCampaignID.php index 92101e7c42..a53d7c5586 100644 --- a/src/Campaigns/Migrations/RevenueTable/AddCampaignID.php +++ b/src/Campaigns/Migrations/RevenueTable/AddCampaignID.php @@ -2,7 +2,7 @@ namespace Give\Campaigns\Migrations\RevenueTable; -use Give\Framework\Database\Exceptions\DatabaseQueryException; +use Give\Framework\Database\DB; use Give\Framework\Migrations\Contracts\Migration; use Give\Framework\Migrations\Exceptions\DatabaseMigrationException; @@ -41,19 +41,11 @@ public static function timestamp(): string */ public function run() { - global $wpdb; + $table = DB::prefix('give_revenue'); + $columnAdded = maybe_add_column($table, 'campaign_id', "ALTER TABLE $table ADD COLUMN campaign_id INT UNSIGNED NULL"); - $table = $wpdb->give_revenue; - - $sql = " - ALTER TABLE $table - ADD COLUMN campaign_id INT UNSIGNED NOT NULL DEFAULT '0' - "; - - try { - $wpdb->query($sql); - } catch (DatabaseQueryException $exception) { - throw new DatabaseMigrationException("An error occurred while updating the $table table", 0, $exception); + if ( ! $columnAdded) { + throw new DatabaseMigrationException("An error occurred while updating the $table table"); } } } diff --git a/src/Campaigns/Migrations/Tables/CreateCampaignFormsTable.php b/src/Campaigns/Migrations/Tables/CreateCampaignFormsTable.php index 92e58b6c57..49c32034c2 100644 --- a/src/Campaigns/Migrations/Tables/CreateCampaignFormsTable.php +++ b/src/Campaigns/Migrations/Tables/CreateCampaignFormsTable.php @@ -51,7 +51,6 @@ public function run(): void $sql = "CREATE TABLE $table ( campaign_id INT UNSIGNED NOT NULL, form_id INT UNSIGNED NOT NULL, - is_default BOOLEAN NOT NULL DEFAULT 0, KEY form_id (form_id), KEY campaign_id (campaign_id), PRIMARY KEY (campaign_id, form_id) diff --git a/src/Campaigns/Models/Campaign.php b/src/Campaigns/Models/Campaign.php index c269c19843..23d086d901 100644 --- a/src/Campaigns/Models/Campaign.php +++ b/src/Campaigns/Models/Campaign.php @@ -12,8 +12,8 @@ use Give\Campaigns\ValueObjects\CampaignGoalType; use Give\Campaigns\ValueObjects\CampaignStatus; use Give\Campaigns\ValueObjects\CampaignType; -use Give\DonationForms\Models\DonationForm; -use Give\DonationForms\V2\Models\DonationForm as LegacyDonationForm; +use Give\DonationForms\V2\Models\DonationForm; +use Give\DonationForms\V2\Repositories\DonationFormsRepository; use Give\Framework\Exceptions\Primitives\InvalidArgumentException; use Give\Framework\Models\Contracts\ModelCrud; use Give\Framework\Models\Contracts\ModelHasFactory; @@ -25,6 +25,7 @@ * @unreleased * * @property int $id + * @property int $defaultFormId * @property CampaignType $type * @property bool $enableCampaignPage * @property string $title @@ -49,6 +50,7 @@ class Campaign extends Model implements ModelCrud, ModelHasFactory */ protected $properties = [ 'id' => 'int', + 'defaultFormId' => 'int', 'type' => CampaignType::class, 'enableCampaignPage' => ['bool', true], 'title' => 'string', @@ -68,22 +70,10 @@ class Campaign extends Model implements ModelCrud, ModelHasFactory /** * @unreleased - * - * @return DonationForm | LegacyDonationForm */ - public function defaultForm() + public function defaultForm(): ?DonationForm { - $defaultForm = $this->forms() - ->where('campaign_forms.is_default', true) - ->get(); - - if (is_null($defaultForm)) { - $defaultForm = $this->legacyForms() - ->where('campaign_forms.is_default', true) - ->get(); - } - - return $defaultForm; + return give(DonationFormsRepository::class)->getById($this->defaultFormId); } /** @@ -93,21 +83,11 @@ public function forms(): ModelQueryBuilder { return DonationForm::query() ->join(function (JoinQueryBuilder $builder) { - $builder->leftJoin('give_campaign_forms', 'campaign_forms') - ->on('campaign_forms.form_id', 'forms.id'); - })->where('campaign_forms.campaign_id', $this->id); - } - - /** - * @unreleased - */ - public function legacyForms(): ModelQueryBuilder - { - return LegacyDonationForm::query() - ->join(function (JoinQueryBuilder $builder) { - $builder->leftJoin('give_campaign_forms', 'campaign_forms') + $builder + ->leftJoin('give_campaign_forms', 'campaign_forms') ->on('campaign_forms.form_id', 'id'); - })->where('campaign_forms.campaign_id', $this->id); + }) + ->where('campaign_forms.campaign_id', $this->id); } /** diff --git a/src/Campaigns/Repositories/CampaignRepository.php b/src/Campaigns/Repositories/CampaignRepository.php index d0be320e8b..7b387e5089 100644 --- a/src/Campaigns/Repositories/CampaignRepository.php +++ b/src/Campaigns/Repositories/CampaignRepository.php @@ -44,13 +44,13 @@ public function getById(int $id) /** * @unreleased * - * Get Campaign by Form ID + * Get Campaign by Form ID using a lookup table */ public function getByFormId(int $formId) { return $this->prepareQuery() - ->leftJoin('give_campaign_forms', 'campaigns.id', 'forms.campaign_id', 'forms') - ->where('forms.form_id', $formId) + ->leftJoin('give_campaign_forms', 'campaigns.id', 'campaignForms.campaign_id', 'campaignForms') + ->where('campaignForms.form_id', $formId) ->get(); } @@ -170,24 +170,21 @@ public function addCampaignForm(Campaign $campaign, int $donationFormId, bool $i DB::query('START TRANSACTION'); try { - // Make sure we'll have only one default form if ($isDefault) { - DB::table('give_campaign_forms') - ->where('campaign_id', $campaign->id) + DB::table('give_campaigns') + ->where('id', $campaign->id) ->update([ - 'is_default' => false, + 'form_id' => $donationFormId, ]); + + $campaign->defaultFormId = $donationFormId; } - $table = DB::prefix('give_campaign_forms'); - DB::query( - DB::prepare("INSERT INTO {$table} (form_id, campaign_id, is_default ) VALUES (%d, %d, %d)", - [ - $donationFormId, - $campaign->id, - $isDefault, - ]) - ); + DB::table('give_campaign_forms') + ->insert([ + 'form_id' => $donationFormId, + 'campaign_id' => $campaign->id, + ]); } catch (Exception $exception) { DB::query('ROLLBACK'); @@ -213,13 +210,13 @@ public function updateDefaultCampaignForm(Campaign $campaign, int $donationFormI DB::query('START TRANSACTION'); try { - DB::query( - DB::prepare('UPDATE ' . DB::prefix('give_campaign_forms') . ' SET is_default = IF(form_id = %d, 1, 0) WHERE campaign_id = %d', - [ - $donationFormId, - $campaign->id, - ]) - ); + DB::table('give_campaigns') + ->where('id', $campaign->id) + ->update([ + 'form_id' => $donationFormId + ]); + + $campaign->defaultFormId = $donationFormId; } catch (Exception $exception) { DB::query('ROLLBACK'); @@ -295,7 +292,7 @@ public function mergeCampaigns(Campaign $destinationCampaign, Campaign ...$campa // Migrate forms from campaigns to merge to the destination campaign DB::query( - DB::prepare("UPDATE " . DB::prefix('give_campaign_forms') . " SET is_default = 0, campaign_id = %d WHERE campaign_id IN ($campaignsToMergeIdsString)", + DB::prepare("UPDATE " . DB::prefix('give_campaign_forms') . " SET campaign_id = %d WHERE campaign_id IN ($campaignsToMergeIdsString)", [ $destinationCampaign->id, ]) @@ -345,6 +342,7 @@ public function prepareQuery(): ModelQueryBuilder return $builder->from('give_campaigns', 'campaigns') ->select( 'id', + ['campaigns.form_id', 'defaultFormId'], // Prefix the `form_id` column to avoid conflicts with the `give_campaign_forms` table. ['campaign_type', 'type'], ['enable_campaign_page', 'enableCampaignPage'], ['campaign_title', 'title'], diff --git a/src/Campaigns/Routes/MergeCampaigns.php b/src/Campaigns/Routes/MergeCampaigns.php deleted file mode 100644 index 1999fa3638..0000000000 --- a/src/Campaigns/Routes/MergeCampaigns.php +++ /dev/null @@ -1,65 +0,0 @@ - WP_REST_Server::EDITABLE, - 'callback' => [$this, 'handleRequest'], - 'permission_callback' => function () { - return current_user_can('manage_options'); - }, - ], - 'args' => [ - 'id' => [ - 'type' => 'integer', - 'required' => true, - ], - 'campaignsToMergeIds' => [ - 'type' => 'array', - 'required' => true, - 'items' => [ - 'type' => 'integer', - ], - ], - ], - ] - ); - } - - /** - * @unreleased - * - * @throws Exception - */ - public function handleRequest(WP_REST_Request $request): WP_REST_Response - { - $destinationCampaign = Campaign::find($request->get_param('id')); - $campaignsToMerge = Campaign::query()->whereIn('id', $request->get_param('campaignsToMergeIds'))->getAll(); - - $campaignsMerged = $destinationCampaign->merge(...$campaignsToMerge); - - return new WP_REST_Response($campaignsMerged); - } -} diff --git a/src/Campaigns/Routes/RegisterCampaignRoutes.php b/src/Campaigns/Routes/RegisterCampaignRoutes.php index d6b5e0ad25..9d7d9b71ec 100644 --- a/src/Campaigns/Routes/RegisterCampaignRoutes.php +++ b/src/Campaigns/Routes/RegisterCampaignRoutes.php @@ -35,6 +35,7 @@ public function __invoke() $this->registerGetCampaign(); $this->registerUpdateCampaign(); $this->registerGetCampaigns(); + $this->registerMergeCampaigns(); $this->registerCreateCampaign(); } @@ -130,6 +131,44 @@ public function registerUpdateCampaign() } + /** + * Update Campaign route + * + * @unreleased + */ + public function registerMergeCampaigns() + { + register_rest_route( + CampaignRoute::NAMESPACE, + CampaignRoute::CAMPAIGN . '/merge', + [ + [ + 'methods' => WP_REST_Server::EDITABLE, + 'callback' => function (WP_REST_Request $request) { + return $this->campaignRequestController->mergeCampaigns($request); + }, + 'permission_callback' => function () { + return current_user_can('manage_options'); + }, + ], + 'args' => [ + 'id' => [ + 'type' => 'integer', + 'required' => true, + ], + 'campaignsToMergeIds' => [ + 'type' => 'array', + 'required' => true, + 'items' => [ + 'type' => 'integer', + ], + ], + ], + ] + ); + } + + /** * Create Campaign route * diff --git a/src/Campaigns/ServiceProvider.php b/src/Campaigns/ServiceProvider.php index e8ec820d2c..012be96503 100644 --- a/src/Campaigns/ServiceProvider.php +++ b/src/Campaigns/ServiceProvider.php @@ -57,7 +57,6 @@ private function registerRoutes() Hooks::addAction('rest_api_init', Routes\DeleteCampaignListTable::class, 'registerRoute'); Hooks::addAction('rest_api_init', Routes\GetCampaignStatistics::class, 'registerRoute'); Hooks::addAction('rest_api_init', Routes\GetCampaignRevenue::class, 'registerRoute'); - Hooks::addAction('rest_api_init', Routes\MergeCampaigns::class, 'registerRoute'); } /** diff --git a/tests/Unit/Campaigns/Migrations/MigrateFormsToCampaignFormsTest.php b/tests/Unit/Campaigns/Migrations/MigrateFormsToCampaignFormsTest.php index b763b7653b..c74e5e9857 100644 --- a/tests/Unit/Campaigns/Migrations/MigrateFormsToCampaignFormsTest.php +++ b/tests/Unit/Campaigns/Migrations/MigrateFormsToCampaignFormsTest.php @@ -80,9 +80,9 @@ public function testMigratedFormsAreDefault() $migration = new MigrateFormsToCampaignForms(); $migration->run(); - $relationship = DB::table('give_campaign_forms')->where('form_id', $form->id)->get(); + $campaign = Campaign::findByFormId($form->id); - $this->assertEquals(1, $relationship->is_default); + $this->assertEquals($form->id, $campaign->defaultFormId); } /** @@ -99,8 +99,8 @@ public function testUpgradedFormsAreNotDefault() $migration = new MigrateFormsToCampaignForms(); $migration->run(); - $relationship = DB::table('give_campaign_forms')->where('form_id', $form1->id)->get(); + $campaign = Campaign::findByFormId($form2->id); - $this->assertEquals(0, $relationship->is_default); + $this->assertNotEquals($form1->id, $campaign->defaultFormId); } } diff --git a/tests/Unit/Campaigns/Models/CampaignModelTest.php b/tests/Unit/Campaigns/Models/CampaignModelTest.php index afd868895f..239612b666 100644 --- a/tests/Unit/Campaigns/Models/CampaignModelTest.php +++ b/tests/Unit/Campaigns/Models/CampaignModelTest.php @@ -56,6 +56,6 @@ public function testCampaignHasDefaultForm() $newDefaultForm = DonationForm::factory()->create(); give(CampaignRepository::class)->addCampaignForm($campaign, $newDefaultForm->id, true); - $this->assertEquals($newDefaultForm->id, $campaign->defaultForm()->id); + $this->assertEquals($newDefaultForm->id, $campaign->defaultFormId); } } diff --git a/tests/Unit/Campaigns/Repositories/CampaignRepositoryTest.php b/tests/Unit/Campaigns/Repositories/CampaignRepositoryTest.php index ea8c39207a..19f9bcb649 100644 --- a/tests/Unit/Campaigns/Repositories/CampaignRepositoryTest.php +++ b/tests/Unit/Campaigns/Repositories/CampaignRepositoryTest.php @@ -428,10 +428,6 @@ public function testMergeCampaignsShouldKeepDefaultFormFromDestinationCampaign() //Re-fetch $destinationCampaign = Campaign::find($destinationCampaign->id); - $countDefaultForm = $destinationCampaign->forms() - ->where('campaign_forms.is_default', true)->count(); - - $this->assertEquals(1, $countDefaultForm); $this->assertEquals($defaultFormBeforeMerge->id, $destinationCampaign->defaultForm()->id); } }