Skip to content

feat: add-on types crud#558

Open
romanetar wants to merge 1 commit into
mainfrom
feature/add-on-types-crud
Open

feat: add-on types crud#558
romanetar wants to merge 1 commit into
mainfrom
feature/add-on-types-crud

Conversation

@romanetar

@romanetar romanetar commented Jun 16, 2026

Copy link
Copy Markdown
Collaborator

ref https://app.clickup.com/t/86b9rdth6

Summary by CodeRabbit

Release Notes

  • New Features

    • Added full CRUD for sponsorship add-on types at /api/v1/summits/all/add-on-types (list, create, retrieve by id, update, delete).
  • Refactor

    • Sponsorship add-ons now use a dedicated add-on type entity via numeric identifiers (type_id), with add-on type name handling via the new lookup.
    • Updated add-on type listing/filtering and response serialization to return normalized add-on type details.
  • Bug Fixes

    • Deleting an add-on type is now blocked when it is in use by existing add-ons.
  • Tests

    • Expanded API coverage for add-on type endpoints and related behaviors.

@coderabbitai

coderabbitai Bot commented Jun 16, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Introduces SummitSponsorshipAddOnType as a new managed Doctrine entity, replacing the legacy string type column on SummitSponsorshipAddOn with a nullable ManyToOne relation. Adds full CRUD REST endpoints at /api/v1/summits/all/add-on-types, supporting repositories, a transactional service with uniqueness and in-use guards, serializers, database migrations, API endpoint seeding, and a complete test suite.

Changes

SummitSponsorshipAddOnType CRUD Feature

Layer / File(s) Summary
Entity models: SummitSponsorshipAddOnType and SummitSponsorshipAddOn refactoring
app/Models/Foundation/Summit/SummitSponsorshipAddOnType.php, app/Models/Foundation/Summit/Factories/SummitSponsorshipAddOnTypeFactory.php, app/Models/Foundation/Summit/SummitSponsorshipAddOn.php, app/Models/Foundation/Summit/Factories/SummitSponsorshipAddOnFactory.php
Introduces the SummitSponsorshipAddOnType Doctrine entity with name field and factory; replaces SummitSponsorshipAddOn's string type column and ValidTypes constants with a nullable ManyToOne relation to SummitSponsorshipAddOnType via AddOnTypeID, updating ORM mappings, accessor/mutator signatures, and removing getMetadata.
Repository contracts and implementations
app/Models/Foundation/Summit/Repositories/ISummitSponsorshipAddOnTypeRepository.php, app/Models/Foundation/Summit/Repositories/ISummitSponsorshipAddOnRepository.php, app/Repositories/Summit/DoctrineSummitSponsorshipAddOnTypeRepository.php, app/Repositories/Summit/DoctrineSummitSponsorshipAddOnRepository.php, app/Repositories/RepositoriesProvider.php
Adds ISummitSponsorshipAddOnTypeRepository with getByName and extends ISummitSponsorshipAddOnRepository with countByAddOnType; implements both via new and updated Doctrine repositories (left-join on type alias, updated filter/order mappings); wires both into RepositoriesProvider.
Service contracts and transactional business logic
app/Services/Model/ISummitSponsorshipAddOnTypeService.php, app/Services/Model/Imp/SummitSponsorshipAddOnTypeService.php, app/Services/Model/Imp/SummitSponsorshipService.php, app/Services/ModelServicesProvider.php
Adds ISummitSponsorshipAddOnTypeService and its transactional implementation enforcing name uniqueness and in-use deletion guard; updates SummitSponsorshipService to inject ISummitSponsorshipAddOnTypeRepository and resolve add-on type from type_id/type in addNewAddOn/updateAddOn; registers bindings.
Serializers
app/ModelSerializers/Summit/SummitSponsorshipAddOnTypeSerializer.php, app/ModelSerializers/Summit/SummitSponsorshipAddOnSerializer.php, app/ModelSerializers/SerializerRegistry.php
Adds SummitSponsorshipAddOnTypeSerializer mapping Name to name; updates SummitSponsorshipAddOnSerializer to expose type_id:json_int and add a type expand mapping; registers the new serializer.
Controller, validation factories, and API integration
app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitSponsorshipAddOnTypesApiController.php, app/Http/Controllers/Apis/Protected/Summit/Factories/SummitSponsorshipAddOnTypeValidationRulesFactory.php, app/Http/Controllers/Apis/Protected/Summit/Factories/SummitSponsorshipAddOnsValidationRulesFactory.php, app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitSponsorshipsApiController.php, routes/api_v1.php
Adds OAuth2SummitSponsorshipAddOnTypesApiController with GetAll/add/get/update/delete endpoints and OpenAPI annotations; adds SummitSponsorshipAddOnTypeValidationRulesFactory; loosens SummitSponsorshipAddOnsValidationRulesFactory to accept type_id/type via required_without; updates getAllAddOns filter to support type_id; registers routes.
Database migrations and API endpoint seeding
database/migrations/model/Version20260615000000.php, database/migrations/model/Version20260615000001.php, database/migrations/config/Version20260615000000.php, database/seeders/ApiEndpointsSeeder.php
Creates SummitSponsorshipAddOnType table and AddOnTypeID FK column; seeds four default type rows, backfills from legacy Type string, adds FK constraint with ON DELETE SET NULL, and drops the legacy column; seeds five CRUD endpoint rows with scopes and authz groups.
Test fixtures and full test suite coverage
tests/InsertSummitTestData.php, tests/oauth2/OAuth2SummitSponsorshipAddOnTypesApiControllerTest.php, tests/Unit/Entities/SummitSponsorshipTest.php, tests/oauth2/OAuth2SummitSponsorshipApiControllerTest.php
Updates InsertSummitTestData to persist booth/meeting-room type fixtures for add-on records; adds full OAuth2SummitSponsorshipAddOnTypesApiControllerTest covering CRUD success and error paths; updates existing tests to use new persisted types and filter operators.

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant OAuth2SummitSponsorshipAddOnTypesApiController
  participant SummitSponsorshipAddOnTypeService
  participant ISummitSponsorshipAddOnTypeRepository
  participant ISummitSponsorshipAddOnRepository

  rect rgba(70, 130, 180, 0.5)
    note over Client,ISummitSponsorshipAddOnRepository: POST /api/v1/summits/all/add-on-types (add)
    Client->>OAuth2SummitSponsorshipAddOnTypesApiController: POST {name}
    OAuth2SummitSponsorshipAddOnTypesApiController->>SummitSponsorshipAddOnTypeService: add(payload)
    SummitSponsorshipAddOnTypeService->>ISummitSponsorshipAddOnTypeRepository: getByName(name)
    ISummitSponsorshipAddOnTypeRepository-->>SummitSponsorshipAddOnTypeService: null
    SummitSponsorshipAddOnTypeService->>ISummitSponsorshipAddOnTypeRepository: add(type)
    SummitSponsorshipAddOnTypeService-->>OAuth2SummitSponsorshipAddOnTypesApiController: SummitSponsorshipAddOnType
    OAuth2SummitSponsorshipAddOnTypesApiController-->>Client: 201 Created {id, name}
  end

  rect rgba(180, 70, 70, 0.5)
    note over Client,ISummitSponsorshipAddOnRepository: DELETE /api/v1/summits/all/add-on-types/{id}
    Client->>OAuth2SummitSponsorshipAddOnTypesApiController: DELETE {id}
    OAuth2SummitSponsorshipAddOnTypesApiController->>SummitSponsorshipAddOnTypeService: delete(type_id)
    SummitSponsorshipAddOnTypeService->>ISummitSponsorshipAddOnTypeRepository: getById(type_id)
    ISummitSponsorshipAddOnTypeRepository-->>SummitSponsorshipAddOnTypeService: SummitSponsorshipAddOnType
    SummitSponsorshipAddOnTypeService->>ISummitSponsorshipAddOnRepository: countByAddOnType(type_id)
    ISummitSponsorshipAddOnRepository-->>SummitSponsorshipAddOnTypeService: 0
    SummitSponsorshipAddOnTypeService->>ISummitSponsorshipAddOnTypeRepository: delete(type)
    SummitSponsorshipAddOnTypeService-->>OAuth2SummitSponsorshipAddOnTypesApiController: void
    OAuth2SummitSponsorshipAddOnTypesApiController-->>Client: 204 No Content
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • OpenStackweb/summit-api#492: Modifies SummitSponsorshipService's add-on create/update transaction flow — directly overlaps with the same service methods (addNewAddOn, updateAddOn) that this PR extends to resolve SummitSponsorshipAddOnType from payload.

Suggested reviewers

  • smarcet

Poem

🐇 A type was once just a string so plain,
Now it's an entity with its own domain!
Add, update, delete — the endpoints are here,
With migrations that make the old column disappear.
This bunny approves: the schema feels right! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 39.76% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the primary change: introduction of CRUD operations for sponsorship add-on types. It accurately reflects the main objective of the changeset.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/add-on-types-crud

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions

Copy link
Copy Markdown

📘 OpenAPI / Swagger preview

➡️ https://OpenStackweb.github.io/summit-api/openapi/pr-558/

This page is automatically updated on each push to this PR.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🧹 Nitpick comments (1)
database/migrations/model/Version20260615000001.php (1)

55-61: 💤 Low value

Consider making the seed INSERT idempotent.

The INSERT statement will fail if re-executed (e.g., after a partial migration failure) due to the unique constraint on Name. While the constraint provides data integrity, using INSERT IGNORE or an ON DUPLICATE KEY UPDATE clause would make re-runs safer.

♻️ Optional: Make INSERT idempotent
-        $this->addSql(<<<SQL
-            INSERT INTO `SummitSponsorshipAddOnType` (`Created`, `LastEdited`, `Name`) VALUES
-                (NOW(), NOW(), 'Booth'),
-                (NOW(), NOW(), 'Meeting_Room'),
-                (NOW(), NOW(), 'Schedule_Spot'),
-                (NOW(), NOW(), 'Signage_Spot')
-        SQL);
+        $this->addSql(<<<SQL
+            INSERT IGNORE INTO `SummitSponsorshipAddOnType` (`Created`, `LastEdited`, `Name`) VALUES
+                (NOW(), NOW(), 'Booth'),
+                (NOW(), NOW(), 'Meeting_Room'),
+                (NOW(), NOW(), 'Schedule_Spot'),
+                (NOW(), NOW(), 'Signage_Spot')
+        SQL);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@database/migrations/model/Version20260615000001.php` around lines 55 - 61,
The INSERT statement for SummitSponsorshipAddOnType in the addSql call will fail
if the migration is re-executed due to the unique constraint on the Name column.
Make the INSERT idempotent by adding either INSERT IGNORE or an ON DUPLICATE KEY
UPDATE clause to the SQL statement so that re-running the migration after a
partial failure does not cause the statement to fail, allowing the migration to
proceed safely.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@app/Http/Controllers/Apis/Protected/Summit/Factories/SummitSponsorshipAddOnsValidationRulesFactory.php`:
- Around line 27-29: The validation rules for type_id and type fields in
SummitSponsorshipAddOnsValidationRulesFactory allow both fields to be submitted
simultaneously, creating ambiguous type resolution. To enforce mutual
exclusivity, add a `prohibits` validation rule (or equivalent mutual exclusion
constraint) at lines 27-29 so that type_id prohibits the presence of type, and
at lines 36-37 so that type prohibits the presence of type_id. This ensures only
one field can be provided per request, eliminating conflicting values and
non-deterministic behavior.

In
`@app/Http/Controllers/Apis/Protected/Summit/Factories/SummitSponsorshipAddOnTypeValidationRulesFactory.php`:
- Around line 30-34: The validation rule for the 'name' field in the
buildForUpdate method of SummitSponsorshipAddOnTypeValidationRulesFactory
currently permits empty strings because it only validates that the field is a
string when present. Add the 'filled' validation rule to the 'name' field
validation chain to ensure that when the name is provided, it must not be empty,
preventing blank lookup names from being persisted during updates.

In `@app/ModelSerializers/Summit/SummitSponsorshipAddOnTypeSerializer.php`:
- Around line 27-32: The serialize method in
SummitSponsorshipAddOnTypeSerializer is mutating the canonical name field by
replacing underscores with spaces on line 31, which prevents round-tripping of
the original stored value and breaks idempotent update/filter operations.
Instead of modifying the name value directly, create a separate display field
(such as name_display or similar) to hold the transformed version with spaces,
leaving the canonical name field unchanged so it reflects the actual stored
value in the database.

In `@app/Repositories/Summit/DoctrineSummitSponsorshipAddOnRepository.php`:
- Around line 85-88: The getMetadata() method in
DoctrineSummitSponsorshipAddOnRepository currently returns an empty array but
should return populated metadata following the pattern used in similar
repositories. Examine how DoctrineSummitRegistrationPromoCodeRepository and
DoctrineSummitLocationRepository implement their getMetadata() methods—they call
Model::getMetadata() on their related entity types to populate the array. Apply
the same approach to the getMetadata() method in
DoctrineSummitSponsorshipAddOnRepository by calling getMetadata() on
SummitSponsorshipAddOn and/or SummitSponsorshipAddOnType entity classes and
returning the resulting metadata array instead of an empty array.

In `@app/Services/Model/ISummitSponsorshipAddOnTypeService.php`:
- Around line 41-45: The PHPDoc comment for the delete method in the
ISummitSponsorshipAddOnTypeService interface only documents that it throws
EntityNotFoundException, but the implementation also throws ValidationException
when the type is in use. Add a `@throws` ValidationException line to the PHPDoc
comment block of the delete method to fully document all exceptions that callers
need to handle.

In `@app/Services/ModelServicesProvider.php`:
- Around line 351-354: Since ModelServicesProvider is a deferred provider with
`$defer = true`, you must declare all service bindings registered in the
`register()` method within the `provides()` method as well. Add
`ISummitSponsorshipAddOnTypeService::class` to the `provides()` method array in
ModelServicesProvider so that Laravel can properly resolve this binding at
runtime without failures.

In `@tests/oauth2/OAuth2SummitSponsorshipAddOnTypesApiControllerTest.php`:
- Around line 41-57: The tearDown method only removes self::$default_type but
does not clean up add-on types created by testAdd(), causing test data leaks.
Add a class-level collection variable (such as self::$created_types) to track
all SummitSponsorshipAddOnType instances created during test execution. In
testAdd() and any other test methods that create add-on types, append the newly
created type to this tracking collection after persistence. Then in tearDown(),
iterate through all tracked add-on types in the collection and remove each one
from the entity manager before clearing the collection, ensuring complete
cleanup of all test-created data alongside the existing self::$default_type
cleanup.

---

Nitpick comments:
In `@database/migrations/model/Version20260615000001.php`:
- Around line 55-61: The INSERT statement for SummitSponsorshipAddOnType in the
addSql call will fail if the migration is re-executed due to the unique
constraint on the Name column. Make the INSERT idempotent by adding either
INSERT IGNORE or an ON DUPLICATE KEY UPDATE clause to the SQL statement so that
re-running the migration after a partial failure does not cause the statement to
fail, allowing the migration to proceed safely.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 024ec028-2fd4-4c04-a1b6-c185cf3a1ae0

📥 Commits

Reviewing files that changed from the base of the PR and between 4fdd3db and f34a772.

📒 Files selected for processing (28)
  • app/Http/Controllers/Apis/Protected/Summit/Factories/SummitSponsorshipAddOnTypeValidationRulesFactory.php
  • app/Http/Controllers/Apis/Protected/Summit/Factories/SummitSponsorshipAddOnsValidationRulesFactory.php
  • app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitSponsorshipAddOnTypesApiController.php
  • app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitSponsorshipsApiController.php
  • app/ModelSerializers/SerializerRegistry.php
  • app/ModelSerializers/Summit/SummitSponsorshipAddOnSerializer.php
  • app/ModelSerializers/Summit/SummitSponsorshipAddOnTypeSerializer.php
  • app/Models/Foundation/Summit/Factories/SummitSponsorshipAddOnFactory.php
  • app/Models/Foundation/Summit/Factories/SummitSponsorshipAddOnTypeFactory.php
  • app/Models/Foundation/Summit/Repositories/ISummitSponsorshipAddOnRepository.php
  • app/Models/Foundation/Summit/Repositories/ISummitSponsorshipAddOnTypeRepository.php
  • app/Models/Foundation/Summit/SummitSponsorshipAddOn.php
  • app/Models/Foundation/Summit/SummitSponsorshipAddOnType.php
  • app/Repositories/RepositoriesProvider.php
  • app/Repositories/Summit/DoctrineSummitSponsorshipAddOnRepository.php
  • app/Repositories/Summit/DoctrineSummitSponsorshipAddOnTypeRepository.php
  • app/Services/Model/ISummitSponsorshipAddOnTypeService.php
  • app/Services/Model/Imp/SummitSponsorshipAddOnTypeService.php
  • app/Services/Model/Imp/SummitSponsorshipService.php
  • app/Services/ModelServicesProvider.php
  • database/migrations/config/Version20260615000000.php
  • database/migrations/model/Version20260615000000.php
  • database/migrations/model/Version20260615000001.php
  • database/seeders/ApiEndpointsSeeder.php
  • routes/api_v1.php
  • tests/InsertSummitTestData.php
  • tests/oauth2/OAuth2SummitSponsorshipAddOnTypesApiControllerTest.php
  • tests/oauth2/OAuth2SummitSponsorshipApiControllerTest.php
💤 Files with no reviewable changes (1)
  • app/Models/Foundation/Summit/Factories/SummitSponsorshipAddOnFactory.php

Comment on lines +30 to +34
public static function buildForUpdate(array $payload = []): array
{
return [
'name' => 'sometimes|string|max:255',
];

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Reject empty name values on update.

Line 33 allows name: "" (empty string) during updates, which can persist blank lookup names.

Suggested fix
-            'name' => 'sometimes|string|max:255',
+            'name' => 'sometimes|required|string|max:255',
🧰 Tools
🪛 PHPMD (2.15.0)

[warning] 30-30: Avoid unused parameters such as '$payload'. (undefined)

(UnusedFormalParameter)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@app/Http/Controllers/Apis/Protected/Summit/Factories/SummitSponsorshipAddOnTypeValidationRulesFactory.php`
around lines 30 - 34, The validation rule for the 'name' field in the
buildForUpdate method of SummitSponsorshipAddOnTypeValidationRulesFactory
currently permits empty strings because it only validates that the field is a
string when present. Add the 'filled' validation rule to the 'name' field
validation chain to ensure that when the name is provided, it must not be empty,
preventing blank lookup names from being persisted during updates.

Comment thread app/ModelSerializers/Summit/SummitSponsorshipAddOnTypeSerializer.php Outdated
Comment on lines 85 to +88
public function getMetadata(Summit $summit): array
{
return SummitSponsorshipAddOn::getMetadata();
return [];
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Find getMetadata callsites and inspect expectations.
rg -n -C4 '\bgetMetadata\s*\(' app tests

# Narrow to sponsorship add-on repository references.
rg -n -C4 'ISummitSponsorshipAddOnRepository|DoctrineSummitSponsorshipAddOnRepository' app tests

Repository: OpenStackweb/summit-api

Length of output: 50379


🏁 Script executed:

# Search for method calls to getMetadata on sponsorship add-on repository or interface
rg -n 'ISummitSponsorshipAddOnRepository|sponsorshipAddOn.*getMetadata|getMetadata.*sponsorship' app tests --type php

# Search for services/controllers that use ISummitSponsorshipAddOnRepository
rg -n -A5 -B5 'ISummitSponsorshipAddOnRepository' app/Services app/Http --type php

# Look for API endpoints that expose sponsorship add-on metadata
rg -n -i 'sponsorship.*metadata|metadata.*sponsorship' app/Http --type php

Repository: OpenStackweb/summit-api

Length of output: 8715


🏁 Script executed:

# Get context around line 742 in the controller to see how getMetadata is used
sed -n '730,760p' app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitSponsorshipsApiController.php | cat -n

Repository: OpenStackweb/summit-api

Length of output: 898


🏁 Script executed:

# Check if SummitSponsorshipAddOn model has a getMetadata method
rg -n 'class SummitSponsorshipAddOn' app/Models --type php

# Find the model and check for metadata pattern
find app/Models -name '*SponsorshipAddOn*' -type f

# Search for tests of this endpoint
rg -n 'getMetadata.*sponsorship|getSponsorshipAddOn.*etadata' tests --type php

Repository: OpenStackweb/summit-api

Length of output: 985


🏁 Script executed:

# Check the SummitSponsorshipAddOn model for getMetadata method
rg -n 'getMetadata|public static' app/Models/Foundation/Summit/SummitSponsorshipAddOn.php -A3

# Check for tests of the sponsorship endpoint
rg -n 'testGetMetadata|getMetadata.*sponsorship' tests --type php

# Look at the full SummitSponsorshipAddOn model to understand its structure
wc -l app/Models/Foundation/Summit/SummitSponsorshipAddOn.php

Repository: OpenStackweb/summit-api

Length of output: 331


🏁 Script executed:

# Read the SummitSponsorshipAddOn model to understand its structure
cat -n app/Models/Foundation/Summit/SummitSponsorshipAddOn.php

# Also check if there are any tests for the sponsorship add-on getMetadata endpoint
rg -n 'SponsorshipAddOn.*etadata|sponsorshipAddOn.*getMetadata' tests --type php -A5

Repository: OpenStackweb/summit-api

Length of output: 3492


🏁 Script executed:

# Search for tests that call the sponsorship add-on metadata endpoint
rg -n 'getSponsorshipAddOns.*Metadata|sponsorship.*add.*on.*metadata' tests --type php -i -A5

# Check the complete test file for the controller to see if there are any metadata tests
rg -n 'OAuth2SummitSponsorshipsApiTest|testGetMetadata' tests --type php -l

# Check if such a test file exists
find tests -name '*SponsorshipAddOn*' -o -name '*Sponsorship*Api*Test*' | head -10

Repository: OpenStackweb/summit-api

Length of output: 427


🏁 Script executed:

# Check the OAuth2SummitSponsorshipApiControllerTest for getMetadata tests
rg -n 'getMetadata|testGet' tests/oauth2/OAuth2SummitSponsorshipApiControllerTest.php -A10 | head -50

Repository: OpenStackweb/summit-api

Length of output: 1847


🏁 Script executed:

# Get the full testGetAddsMetadata test
sed -n '305,330p' tests/oauth2/OAuth2SummitSponsorshipApiControllerTest.php | cat -n

Repository: OpenStackweb/summit-api

Length of output: 755


Add sponsorship add-on metadata to match pattern of other repository implementations.

The getMetadata() method currently returns an empty array, but the API endpoint is documented as returning "Add-ons metadata" and the test only verifies it's not null, not that it contains expected metadata keys. Similar repositories (DoctrineSummitRegistrationPromoCodeRepository, DoctrineSummitLocationRepository) return populated metadata arrays by calling Model::getMetadata() on related entity types. Add metadata for SummitSponsorshipAddOn and/or SummitSponsorshipAddOnType following the established pattern to provide consumers with the schema of available add-on attributes.

🧰 Tools
🪛 PHPMD (2.15.0)

[warning] 85-85: Avoid unused parameters such as '$summit'. (undefined)

(UnusedFormalParameter)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/Repositories/Summit/DoctrineSummitSponsorshipAddOnRepository.php` around
lines 85 - 88, The getMetadata() method in
DoctrineSummitSponsorshipAddOnRepository currently returns an empty array but
should return populated metadata following the pattern used in similar
repositories. Examine how DoctrineSummitRegistrationPromoCodeRepository and
DoctrineSummitLocationRepository implement their getMetadata() methods—they call
Model::getMetadata() on their related entity types to populate the array. Apply
the same approach to the getMetadata() method in
DoctrineSummitSponsorshipAddOnRepository by calling getMetadata() on
SummitSponsorshipAddOn and/or SummitSponsorshipAddOnType entity classes and
returning the resulting metadata array instead of an empty array.

Comment thread app/Services/Model/ISummitSponsorshipAddOnTypeService.php
Comment thread app/Services/ModelServicesProvider.php
Comment on lines +41 to +57
protected function tearDown(): void
{
if (!is_null(self::$default_type)) {
$em = self::$em->isOpen()
? self::$em
: Registry::resetManager(SilverstripeBaseModel::EntityManager);

$type = $em->find(SummitSponsorshipAddOnType::class, self::$default_type->getId());
if (!is_null($type)) {
$em->remove($type);
$em->flush();
}
self::$default_type = null;
}
self::clearSummitTestData();
parent::tearDown();
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

TearDown does not clean add-on types created by testAdd().

testAdd() persists a new add-on type, but tearDown() only removes self::$default_type. This can leak rows across tests and erode isolation in shared test DB runs.

Suggested fix
 final class OAuth2SummitSponsorshipAddOnTypesApiControllerTest extends ProtectedApiTestCase
 {
     use InsertSummitTestData;
 
     private static ?SummitSponsorshipAddOnType $default_type = null;
+    private array $created_type_ids = [];
@@
     protected function tearDown(): void
     {
@@
             self::$default_type = null;
         }
+
+        $em = self::$em->isOpen()
+            ? self::$em
+            : Registry::resetManager(SilverstripeBaseModel::EntityManager);
+        foreach ($this->created_type_ids as $id) {
+            $created = $em->find(SummitSponsorshipAddOnType::class, $id);
+            if (!is_null($created)) {
+                $em->remove($created);
+            }
+        }
+        if (!empty($this->created_type_ids)) {
+            $em->flush();
+        }
+        $this->created_type_ids = [];
         self::clearSummitTestData();
         parent::tearDown();
     }
@@
     public function testAdd(): void
     {
@@
         $type = json_decode($content);
         $this->assertNotNull($type);
+        $this->created_type_ids[] = (int)$type->id;
         $name = str_replace('_', ' ', $data['name']);
         $this->assertEquals($name, $type->name);
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/oauth2/OAuth2SummitSponsorshipAddOnTypesApiControllerTest.php` around
lines 41 - 57, The tearDown method only removes self::$default_type but does not
clean up add-on types created by testAdd(), causing test data leaks. Add a
class-level collection variable (such as self::$created_types) to track all
SummitSponsorshipAddOnType instances created during test execution. In testAdd()
and any other test methods that create add-on types, append the newly created
type to this tracking collection after persistence. Then in tearDown(), iterate
through all tracked add-on types in the collection and remove each one from the
entity manager before clearing the collection, ensuring complete cleanup of all
test-created data alongside the existing self::$default_type cleanup.

@romanetar romanetar force-pushed the feature/add-on-types-crud branch from f34a772 to de1edb8 Compare June 16, 2026 16:58
@github-actions

Copy link
Copy Markdown

📘 OpenAPI / Swagger preview

➡️ https://OpenStackweb.github.io/summit-api/openapi/pr-558/

This page is automatically updated on each push to this PR.

@romanetar romanetar force-pushed the feature/add-on-types-crud branch from de1edb8 to 32ec9ba Compare June 16, 2026 17:03
@github-actions

Copy link
Copy Markdown

📘 OpenAPI / Swagger preview

➡️ https://OpenStackweb.github.io/summit-api/openapi/pr-558/

This page is automatically updated on each push to this PR.

Signed-off-by: romanetar <roman_ag@hotmail.com>
@romanetar romanetar force-pushed the feature/add-on-types-crud branch from 32ec9ba to 4dd14e8 Compare June 16, 2026 18:30
@github-actions

Copy link
Copy Markdown

📘 OpenAPI / Swagger preview

➡️ https://OpenStackweb.github.io/summit-api/openapi/pr-558/

This page is automatically updated on each push to this PR.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
app/Http/Controllers/Apis/Protected/Summit/Factories/SummitSponsorshipAddOnTypeValidationRulesFactory.php (1)

30-34: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Reject blank name values on update.

Line 33 uses sometimes|string|max:255, so name: "" is accepted when present. That leaves this layer allowing empty lookup names.

Suggested fix
-            'name' => 'sometimes|string|max:255',
+            'name' => 'sometimes|filled|string|max:255',
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@app/Http/Controllers/Apis/Protected/Summit/Factories/SummitSponsorshipAddOnTypeValidationRulesFactory.php`
around lines 30 - 34, The validation rule for the name field in the
buildForUpdate method of SummitSponsorshipAddOnTypeValidationRulesFactory is
missing a check to reject empty string values. The current rule
sometimes|string|max:255 allows blank names to pass validation. Add the filled
validation rule to ensure that when the name field is present in the payload, it
cannot be an empty string. Update the rule to include filled alongside the
existing validators.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Duplicate comments:
In
`@app/Http/Controllers/Apis/Protected/Summit/Factories/SummitSponsorshipAddOnTypeValidationRulesFactory.php`:
- Around line 30-34: The validation rule for the name field in the
buildForUpdate method of SummitSponsorshipAddOnTypeValidationRulesFactory is
missing a check to reject empty string values. The current rule
sometimes|string|max:255 allows blank names to pass validation. Add the filled
validation rule to ensure that when the name field is present in the payload, it
cannot be an empty string. Update the rule to include filled alongside the
existing validators.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3178fecb-bdd5-47b1-89ec-085ef20189df

📥 Commits

Reviewing files that changed from the base of the PR and between f34a772 and 4dd14e8.

📒 Files selected for processing (29)
  • app/Http/Controllers/Apis/Protected/Summit/Factories/SummitSponsorshipAddOnTypeValidationRulesFactory.php
  • app/Http/Controllers/Apis/Protected/Summit/Factories/SummitSponsorshipAddOnsValidationRulesFactory.php
  • app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitSponsorshipAddOnTypesApiController.php
  • app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitSponsorshipsApiController.php
  • app/ModelSerializers/SerializerRegistry.php
  • app/ModelSerializers/Summit/SummitSponsorshipAddOnSerializer.php
  • app/ModelSerializers/Summit/SummitSponsorshipAddOnTypeSerializer.php
  • app/Models/Foundation/Summit/Factories/SummitSponsorshipAddOnFactory.php
  • app/Models/Foundation/Summit/Factories/SummitSponsorshipAddOnTypeFactory.php
  • app/Models/Foundation/Summit/Repositories/ISummitSponsorshipAddOnRepository.php
  • app/Models/Foundation/Summit/Repositories/ISummitSponsorshipAddOnTypeRepository.php
  • app/Models/Foundation/Summit/SummitSponsorshipAddOn.php
  • app/Models/Foundation/Summit/SummitSponsorshipAddOnType.php
  • app/Repositories/RepositoriesProvider.php
  • app/Repositories/Summit/DoctrineSummitSponsorshipAddOnRepository.php
  • app/Repositories/Summit/DoctrineSummitSponsorshipAddOnTypeRepository.php
  • app/Services/Model/ISummitSponsorshipAddOnTypeService.php
  • app/Services/Model/Imp/SummitSponsorshipAddOnTypeService.php
  • app/Services/Model/Imp/SummitSponsorshipService.php
  • app/Services/ModelServicesProvider.php
  • database/migrations/config/Version20260615000000.php
  • database/migrations/model/Version20260615000000.php
  • database/migrations/model/Version20260615000001.php
  • database/seeders/ApiEndpointsSeeder.php
  • routes/api_v1.php
  • tests/InsertSummitTestData.php
  • tests/Unit/Entities/SummitSponsorshipTest.php
  • tests/oauth2/OAuth2SummitSponsorshipAddOnTypesApiControllerTest.php
  • tests/oauth2/OAuth2SummitSponsorshipApiControllerTest.php
💤 Files with no reviewable changes (1)
  • app/Models/Foundation/Summit/Factories/SummitSponsorshipAddOnFactory.php
🚧 Files skipped from review as they are similar to previous changes (21)
  • app/ModelSerializers/Summit/SummitSponsorshipAddOnTypeSerializer.php
  • app/Repositories/Summit/DoctrineSummitSponsorshipAddOnTypeRepository.php
  • app/Models/Foundation/Summit/Factories/SummitSponsorshipAddOnTypeFactory.php
  • app/Models/Foundation/Summit/SummitSponsorshipAddOnType.php
  • app/ModelSerializers/SerializerRegistry.php
  • app/Models/Foundation/Summit/Repositories/ISummitSponsorshipAddOnTypeRepository.php
  • app/Services/Model/ISummitSponsorshipAddOnTypeService.php
  • tests/oauth2/OAuth2SummitSponsorshipApiControllerTest.php
  • app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitSponsorshipsApiController.php
  • app/Models/Foundation/Summit/Repositories/ISummitSponsorshipAddOnRepository.php
  • database/migrations/model/Version20260615000000.php
  • app/Repositories/Summit/DoctrineSummitSponsorshipAddOnRepository.php
  • tests/InsertSummitTestData.php
  • app/ModelSerializers/Summit/SummitSponsorshipAddOnSerializer.php
  • database/seeders/ApiEndpointsSeeder.php
  • app/Models/Foundation/Summit/SummitSponsorshipAddOn.php
  • app/Services/Model/Imp/SummitSponsorshipService.php
  • app/Services/Model/Imp/SummitSponsorshipAddOnTypeService.php
  • routes/api_v1.php
  • database/migrations/model/Version20260615000001.php
  • app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitSponsorshipAddOnTypesApiController.php

@romanetar romanetar requested a review from smarcet June 16, 2026 18:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant