-
-
Notifications
You must be signed in to change notification settings - Fork 213
Add setting to delete company #1893
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR adds the ability to delete a company from the system settings with a confirmation modal and proper safety checks.
- Adds a "Danger Zone" section to the system settings with company deletion functionality
- Implements proper CSRF protection and confirmation modal requiring company name input
- Sets up proper cascading deletes to handle related entities when a company is removed
Reviewed Changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src/SettingsBundle/Twig/Components/Settings.php | Adds icon mapping for different settings sections |
| src/SettingsBundle/Resources/views/Components/Settings.html.twig | Adds danger zone UI with delete company modal and confirmation |
| src/CoreBundle/Traits/Entity/CompanyAware.php | Updates relationship to include cascade remove |
| src/CoreBundle/Resources/config/routing.php | Adds POST route for company deletion |
| src/CoreBundle/Repository/CompanyRepository.php | Implements company deletion method |
| src/CoreBundle/Entity/Company.php | Adds relationship mappings for orphan removal |
| src/CoreBundle/Action/DeleteCompany.php | Implements company deletion controller with CSRF protection |
| assets/controllers/delete-company-controller.ts | Adds frontend validation for company name confirmation |
src/SettingsBundle/Resources/views/Components/Settings.html.twig
Outdated
Show resolved
Hide resolved
src/SettingsBundle/Resources/views/Components/Settings.html.twig
Outdated
Show resolved
Hide resolved
|
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. WalkthroughThis change set introduces company deletion functionality, including backend support for securely deleting a company and all related data, as well as frontend UI and UX for initiating and confirming this action. It adds a new controller, repository method, entity relationships, routing, Twig template logic, and updates to settings navigation icons. Test snapshots are also updated to reflect these UI changes. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant Browser
participant StimulusController
participant Backend (DeleteCompany action)
participant CompanyRepository
participant Database
User->>Browser: Click "Delete Company"
Browser->>StimulusController: Show modal
User->>Browser: Type company name, confirm deletion
StimulusController->>Browser: Enable confirm button if input matches
User->>Browser: Submit deletion form
Browser->>Backend (DeleteCompany action): POST /delete-company (with CSRF token)
Backend (DeleteCompany action)->>CompanyRepository: deleteCompany(companyId)
CompanyRepository->>Database: Remove company and related entities
Backend (DeleteCompany action)->>Browser: Redirect to company selection with flash message
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~18 minutes Note 🔌 MCP (Model Context Protocol) integration is now available in Early Access!Pro users can now connect to remote MCP servers under the Integrations page to get reviews and chat conversations that understand additional development context. 📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (2)
✨ Finishing Touches🧪 Generate unit tests
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 9
🧹 Nitpick comments (7)
src/SettingsBundle/Twig/Components/Settings.php (1)
41-52: Make settingIconMap readonly and manually verify your Font Awesome version
- Apply this diff to prevent mutation and keep PHPStan happy:
- /** @var array<string, string> */ - public array $settingIconMap = [ + /** @var array<string, string> */ + public readonly array $settingIconMap = [ 'company' => 'building', 'invoice' => 'file-invoice', 'quote' => 'file-text-o', 'email' => 'envelope', 'payment' => 'credit-card', 'tax' => 'balance-scale', 'system' => 'cog', ];
- We found multiple usages of
file-text-oin your Twig templates—this is a Font Awesome 4 icon name. If your project uses FA 5+ (or newer), you’ll need to swap in the updated icon class (e.g.,file-altforfile-text-o,scale-balancedorbalance-scaledepending on your FA version).- I wasn’t able to locate the FA package/version in composer.json, package.json, or lockfiles. Please confirm which Font Awesome version you’re shipping (check composer.lock, package-lock.json, webpack config, etc.) and update any legacy icon names accordingly.
src/CoreBundle/Repository/CompanyRepository.php (1)
57-71: Optional: avoid SELECT by using getReference when existence check isn’t requiredCurrent approach loads the entity, then removes. If you don’t need to detect "not found" explicitly, using a reference avoids an extra query.
- $company = $this->find($companyId); - - if (! $company instanceof Company) { - return; - } - - $this->getEntityManager()->remove($company); + $em = $this->getEntityManager(); + $companyRef = $em->getReference(Company::class, $companyId); + $em->remove($companyRef); $this->getEntityManager()->flush();Pros: fewer queries. Cons: you lose the explicit "not found" branch (DELETE will no-op if row doesn’t exist).
src/CoreBundle/Action/DeleteCompany.php (2)
47-47: Use a translatable flash keyKeep flash messages consistent with the rest of the app using translation keys.
- $this->addFlash('success', 'Company deleted successfully.'); + $this->addFlash('success', 'company.deleted.success');
49-50: Use 303 See Other for POST-redirect303 is the recommended status for redirect-after-POST.
- return $this->redirectToRoute('_select_company'); + return $this->redirectToRoute('_select_company', [], Response::HTTP_SEE_OTHER);assets/controllers/delete-company-controller.ts (1)
16-18: Nit: adddisconnect()to clear referencesNot required, but cleaning up helps avoid stale references.
connect() { this.modal = $(this.modalTarget); } + + disconnect() { + this.modal = null; + }src/CoreBundle/Entity/Company.php (2)
95-96: Naming consistency: pluralizecreditcollectionFor a OneToMany to
Credit, consider$creditsfor clarity and consistency.
134-138: Optional: initialize new collections to avoid typed property access issuesIf any of these collections are ever accessed, uninitialized typed properties will throw. Initialize them in the constructor.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (8)
assets/controllers/delete-company-controller.ts(1 hunks)src/CoreBundle/Action/DeleteCompany.php(1 hunks)src/CoreBundle/Entity/Company.php(2 hunks)src/CoreBundle/Repository/CompanyRepository.php(1 hunks)src/CoreBundle/Resources/config/routing.php(2 hunks)src/CoreBundle/Traits/Entity/CompanyAware.php(1 hunks)src/SettingsBundle/Resources/views/Components/Settings.html.twig(2 hunks)src/SettingsBundle/Twig/Components/Settings.php(1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-06-01T18:20:04.058Z
Learnt from: pierredup
PR: SolidInvoice/SolidInvoice#1759
File: src/UserBundle/Resources/views/Layout/_partial/nav.html.twig:1-46
Timestamp: 2025-06-01T18:20:04.058Z
Learning: In SolidInvoice project, routes are defined in PHP routing configuration files like `src/UserBundle/Resources/config/routing.php`, not just in YAML files or PHP annotations.
Applied to files:
src/CoreBundle/Resources/config/routing.php
🧬 Code Graph Analysis (1)
src/CoreBundle/Entity/Company.php (6)
src/CoreBundle/Repository/CompanyRepository.php (1)
CompanyRepository(26-72)src/ClientBundle/Entity/Address.php (1)
ORM(37-277)src/ClientBundle/Entity/Credit.php (1)
ORM(29-92)src/ClientBundle/Entity/AdditionalContactDetail.php (1)
ORM(34-161)src/ClientBundle/Entity/ContactType.php (1)
ORM(30-161)src/UserBundle/Entity/ApiToken.php (1)
ORM(30-133)
🪛 PHPMD (2.15.0)
src/CoreBundle/Entity/Company.php
75-75: Avoid unused private fields such as '$apiTokenHistories'. (Unused Code Rules)
(UnusedPrivateField)
78-78: Avoid unused private fields such as '$taxes'. (Unused Code Rules)
(UnusedPrivateField)
81-81: Avoid unused private fields such as '$additionalContactDetails'. (Unused Code Rules)
(UnusedPrivateField)
84-84: Avoid unused private fields such as '$addresses'. (Unused Code Rules)
(UnusedPrivateField)
87-87: Avoid unused private fields such as '$clients'. (Unused Code Rules)
(UnusedPrivateField)
90-90: Avoid unused private fields such as '$contacts'. (Unused Code Rules)
(UnusedPrivateField)
93-93: Avoid unused private fields such as '$contactTypes'. (Unused Code Rules)
(UnusedPrivateField)
96-96: Avoid unused private fields such as '$credit'. (Unused Code Rules)
(UnusedPrivateField)
99-99: Avoid unused private fields such as '$userInvitations'. (Unused Code Rules)
(UnusedPrivateField)
102-102: Avoid unused private fields such as '$apiTokens'. (Unused Code Rules)
(UnusedPrivateField)
105-105: Avoid unused private fields such as '$settings'. (Unused Code Rules)
(UnusedPrivateField)
108-108: Avoid unused private fields such as '$quotes'. (Unused Code Rules)
(UnusedPrivateField)
111-111: Avoid unused private fields such as '$quoteLines'. (Unused Code Rules)
(UnusedPrivateField)
114-114: Avoid unused private fields such as '$paymentMethods'. (Unused Code Rules)
(UnusedPrivateField)
117-117: Avoid unused private fields such as '$payments'. (Unused Code Rules)
(UnusedPrivateField)
120-120: Avoid unused private fields such as '$userNotifications'. (Unused Code Rules)
(UnusedPrivateField)
123-123: Avoid unused private fields such as '$transportSettings'. (Unused Code Rules)
(UnusedPrivateField)
126-126: Avoid unused private fields such as '$invoices'. (Unused Code Rules)
(UnusedPrivateField)
129-129: Avoid unused private fields such as '$recurringInvoices'. (Unused Code Rules)
(UnusedPrivateField)
132-132: Avoid unused private fields such as '$invoiceLines'. (Unused Code Rules)
(UnusedPrivateField)
🔇 Additional comments (2)
src/CoreBundle/Action/DeleteCompany.php (1)
34-41: Confirmation field not found – no server‐side validation neededThe deletion form in
src/SettingsBundle/Resources/views/Components/Settings.html.twigonly includes the CSRF token and_actionhidden inputs—it does not post aconfirm_namefield. As a result, there’s no name to validate on the server:
- Template lines 121–124 only define:
action="{{ path('_delete_company') }}"<input name="_csrf_token"><input name="_action" value="delete_company">- No
<input name="confirm_name">exists, so the suggested check inDeleteCompany.phpcannot run.If you decide to require users to type the company name to confirm deletion in the UI, add an
<input name="confirm_name">(e.g. inSettings.html.twig) and then mirror that check inDeleteCompany.phpby comparing it against the actual company name and throwing on mismatch. Otherwise, no changes are needed here.assets/controllers/delete-company-controller.ts (1)
16-18: jQuery-based modals are valid with Bootstrap 4.6.2
package.json specifies"bootstrap": "^4.6.2"and"jquery": "^3.7.1", so$(el).modal('show')/hide()is the correct API. No refactor is needed unless you upgrade to Bootstrap 5, in which case you’d switch to thebootstrap.Modalclass.Likely an incorrect or invalid review comment.
src/SettingsBundle/Resources/views/Components/Settings.html.twig
Outdated
Show resolved
Hide resolved
src/SettingsBundle/Resources/views/Components/Settings.html.twig
Outdated
Show resolved
Hide resolved
src/SettingsBundle/Resources/views/Components/Settings.html.twig
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🧹 Nitpick comments (5)
src/SettingsBundle/Tests/Twig/Components/__snapshots__/SettingsTest__testRenderComponent__1.html (5)
15-15: Verify Font Awesome version and class prefixes for new icons
fa-file-invoiceis not available in FA4 and in FA5+ typically usesfas fa-file-invoice. Ensure the project’s icon set matches these classes; otherwise the icon won’t render. Align all icons to the same FA version/prefix.Also applies to: 21-21, 27-27
567-567: Non-standard classcard-danger– use Bootstrap-supported variants
card-dangerisn’t a standard class in Bootstrap 4/5. Preferborder-danger(and optionallytext-danger/bg-*) for consistent styling across themes.- <div class="card mb-3 card-danger"> + <div class="card mb-3 border-danger">
586-586: Modal accessibility improvementsAdd
aria-modal="true"to the modal container and ensure initial focus is handled when opening (Stimulus can callfocus()on the input target).- <div class="modal fade" id="deleteCompanyModal" tabindex="-1" role="dialog" aria-labelledby="deleteCompanyModalLabel" aria-hidden="true" data-delete-company-target="modal"> + <div class="modal fade" id="deleteCompanyModal" tabindex="-1" role="dialog" aria-labelledby="deleteCompanyModalLabel" aria-modal="true" aria-hidden="true" data-delete-company-target="modal">Also consider
aria-describedbyreferencing the warning text for additional context.Also applies to: 590-592, 611-618
615-617: Confirm action must POST with CSRF and provide UX feedbackThe confirm button is handled via Stimulus. Ensure it submits a POST to the delete route with a valid CSRF token and handles failures (disable button while submitting, show spinner, display error).
If not already present, consider a hidden form as a progressive enhancement:
<form id="delete-company-form" method="post" action="{{ path('_delete_company') }}" class="d-none"> <input type="hidden" name="_token" value="{{ csrf_token('delete_company') }}"> </form>Stimulus can
document.getElementById('delete-company-form').submit()once validated.
570-579: Internationalization of new UI stringsNew strings (“Danger Zone”, warnings, labels, buttons) should be translatable. Ensure the Twig template wraps them with the translator (e.g.,
{{ '...'|trans }}) and add catalog entries.Also applies to: 591-596, 601-609, 612-617
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (7)
src/CoreBundle/Action/DeleteCompany.php(1 hunks)src/CoreBundle/Entity/Company.php(2 hunks)src/SettingsBundle/Resources/views/Components/Settings.html.twig(2 hunks)src/SettingsBundle/Tests/Twig/Components/__snapshots__/SettingsTest__testChangeSection__1.html(2 hunks)src/SettingsBundle/Tests/Twig/Components/__snapshots__/SettingsTest__testChangeSection__2.html(2 hunks)src/SettingsBundle/Tests/Twig/Components/__snapshots__/SettingsTest__testRenderComponent__1.html(2 hunks)src/SettingsBundle/Tests/Twig/Components/__snapshots__/SettingsTest__testSaveOnDifferentSection__2.html(2 hunks)
✅ Files skipped from review due to trivial changes (3)
- src/SettingsBundle/Tests/Twig/Components/snapshots/SettingsTest__testChangeSection__2.html
- src/SettingsBundle/Tests/Twig/Components/snapshots/SettingsTest__testSaveOnDifferentSection__2.html
- src/SettingsBundle/Tests/Twig/Components/snapshots/SettingsTest__testChangeSection__1.html
🚧 Files skipped from review as they are similar to previous changes (3)
- src/SettingsBundle/Resources/views/Components/Settings.html.twig
- src/CoreBundle/Action/DeleteCompany.php
- src/CoreBundle/Entity/Company.php
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (20)
- GitHub Check: DB (MariaDB pdo_mysql 11.0)
- GitHub Check: DB (MariaDB pdo_mysql 10.5)
- GitHub Check: DB (MariaDB pdo_mysql 10.6)
- GitHub Check: DB (PostgreSQL pdo_pgsql 17)
- GitHub Check: DB (MariaDB pdo_mysql 11)
- GitHub Check: DB (MySQL pdo_mysql 8.4)
- GitHub Check: DB (MariaDB pdo_mysql 11.4)
- GitHub Check: DB (MySQL pdo_mysql 8.3)
- GitHub Check: DB (MySQL pdo_mysql 9)
- GitHub Check: DB (MariaDB pdo_mysql 10.4)
- GitHub Check: DB (MariaDB pdo_mysql 10.11)
- GitHub Check: DB (PostgreSQL pdo_pgsql 16)
- GitHub Check: DB (MySQL pdo_mysql 5.7)
- GitHub Check: DB (MySQL pdo_mysql 8.0)
- GitHub Check: Lint
- GitHub Check: Unit ( PHP 8.3 )
- GitHub Check: Unit ( PHP 8.3 )
- GitHub Check: PHPStan
- GitHub Check: Analyze (javascript)
- GitHub Check: Unit ( PHP 8.4 )
...SettingsBundle/Tests/Twig/Components/__snapshots__/SettingsTest__testRenderComponent__1.html
Outdated
Show resolved
Hide resolved
...SettingsBundle/Tests/Twig/Components/__snapshots__/SettingsTest__testRenderComponent__1.html
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
♻️ Duplicate comments (2)
src/SettingsBundle/Tests/Twig/Components/__snapshots__/SettingsTest__testRenderComponent__1.html (2)
599-601: Bootstrap 4 dismissal/close markup — LGTMYou reverted to
.closeanddata-dismiss="modal"consistent with BS4. Good fix.Also applies to: 620-622
587-587: Hardcoded company name — make dynamic and properly escapedThe confirmation attribute and label use a hardcoded name “SolidInvoice”. Use the actual company name from context, escaped for attribute/text.
Conceptual Twig changes:
- <div class="form-group" data-controller="delete-company" data-delete-company-company-name-value="SolidInvoice"> + <div class="form-group" + data-controller="delete-company" + data-delete-company-company-name-value="{{ company.name|e('html_attr') }}"> @@ - <p class="fw-bold text-danger">SolidInvoice</p> + <p class="font-weight-bold text-danger">{{ company.name|e }}</p>Note: Update the template; snapshots will follow.
Also applies to: 611-611
🧹 Nitpick comments (2)
src/SettingsBundle/Tests/Twig/Components/__snapshots__/SettingsTest__testRenderComponent__1.html (2)
616-616: Small UX hardening: disable browser assistance on confirmation fieldPrevent autocomplete/capitalization/spellcheck from interfering with exact match validation.
- <input type="text" class="form-control" id="companyNameConfirmation" name="company_name" form="deleteCompanyForm" data-delete-company-target="companyNameInput" data-action="input->delete-company#validateInput" placeholder="Enter company name to confirm"> + <input type="text" class="form-control" id="companyNameConfirmation" name="company_name" form="deleteCompanyForm" data-delete-company-target="companyNameInput" data-action="input->delete-company#validateInput" placeholder="Enter company name to confirm" autocomplete="off" autocapitalize="off" spellcheck="false">
581-586: Consider marking user-facing strings for translationMake Danger Zone copy, button labels, and warnings translatable to align with the rest of the app.
Example:
- Replace literals with
{{ 'settings.danger_zone.title'|trans }},{{ 'settings.delete_company.button'|trans }}, etc.- I can propose keys and update the template + translations if helpful.
Also applies to: 603-610, 620-629
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
composer.lockis excluded by!**/*.lock
📒 Files selected for processing (4)
src/SettingsBundle/Tests/Twig/Components/__snapshots__/SettingsTest__testChangeSection__1.html(2 hunks)src/SettingsBundle/Tests/Twig/Components/__snapshots__/SettingsTest__testChangeSection__2.html(2 hunks)src/SettingsBundle/Tests/Twig/Components/__snapshots__/SettingsTest__testRenderComponent__1.html(2 hunks)src/SettingsBundle/Tests/Twig/Components/__snapshots__/SettingsTest__testSaveOnDifferentSection__2.html(2 hunks)
✅ Files skipped from review due to trivial changes (1)
- src/SettingsBundle/Tests/Twig/Components/snapshots/SettingsTest__testChangeSection__2.html
🚧 Files skipped from review as they are similar to previous changes (2)
- src/SettingsBundle/Tests/Twig/Components/snapshots/SettingsTest__testSaveOnDifferentSection__2.html
- src/SettingsBundle/Tests/Twig/Components/snapshots/SettingsTest__testChangeSection__1.html
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (16)
- GitHub Check: PHPStan
- GitHub Check: Analyze (javascript)
- GitHub Check: Lint
- GitHub Check: DB (PostgreSQL pdo_pgsql 16)
- GitHub Check: Unit ( PHP 8.4 )
- GitHub Check: DB (MariaDB pdo_mysql 11)
- GitHub Check: DB (MySQL pdo_mysql 9)
- GitHub Check: DB (MySQL pdo_mysql 8.3)
- GitHub Check: Unit ( PHP 8.3 )
- GitHub Check: DB (MySQL pdo_mysql 5.7)
- GitHub Check: DB (MariaDB pdo_mysql 11.4)
- GitHub Check: DB (MariaDB pdo_mysql 10.11)
- GitHub Check: DB (MariaDB pdo_mysql 10.4)
- GitHub Check: DB (MySQL pdo_mysql 8.4)
- GitHub Check: DB (MariaDB pdo_mysql 10.5)
- GitHub Check: DB (MariaDB pdo_mysql 11.0)
🔇 Additional comments (2)
src/SettingsBundle/Tests/Twig/Components/__snapshots__/SettingsTest__testRenderComponent__1.html (2)
624-626: Avoid hardcoded URL and empty CSRF — use Symfony helpersUse route generation and CSRF helpers to ensure correctness and security.
Conceptual Twig changes:
- <form id="deleteCompanyForm" action="/delete-company" method="post"> - <input type="hidden" name="_csrf_token" value=""> + <form id="deleteCompanyForm" action="{{ path('_delete_company') }}" method="post"> + <input type="hidden" name="_csrf_token" value="{{ csrf_token('delete_company') }}">I can update the Twig and adjust snapshots accordingly if you want.
Likely an incorrect or invalid review comment.
15-15: Font Awesome setup supports both new and legacy classes—no icon change needed
package.json declares@fortawesome/fontawesome-free@^6.4.0and your SCSS imports~@fortawesome/fontawesome-free/scss/shims, enabling full support for FA6 icons (likefa-file-invoice) alongside legacy FA4 class names (such asfa-file-text-o). No replacement is necessary here.Likely an incorrect or invalid review comment.
No description provided.