Skip to content
Merged

Dev #357

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
50 changes: 50 additions & 0 deletions .coderabbit.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json
language: "en-US"
tone_instructions: "chill"
reviews:
profile: "chill"
high_level_summary: true
collapse_walkthrough: true
suggested_labels: false
high_level_summary_in_walkthrough: false
poem: false
path_instructions:
- path: "src/Domain/**"
instructions: |
You are reviewing PHP domain-layer code. Enforce strict domain purity:
- ❌ Do not allow infrastructure persistence side effects here.
- Flag ANY usage of Doctrine persistence APIs, especially:
- $entityManager->flush(...), $this->entityManager->flush(...)
- $em->persist(...), $em->remove(...)
- direct transaction control ($em->beginTransaction(), commit(), rollback())
- If found, request moving these calls to application-layer Command handlers or background Jobs.
- Also flag repositories in Domain that invoke flush/transactional logic; Domain repositories should be abstractions without side effects.
- Encourage domain events/outbox or return-values to signal write-intent, leaving orchestration to Commands/Jobs.

- path: "src/**/Command/**"
instructions: |
Application layer (Commands/Handlers) is the right place to coordinate persistence.
- ✅ It is acceptable to call $entityManager->flush() here.
- Check that flush is used atomically (once per unit of work) after all domain operations.
- Ensure no domain entity or domain service is calling flush; only the handler orchestrates it.
- Prefer $em->transactional(...) or explicit try/catch with rollback on failure.

- path: "src/**/MessageHandler/**"
instructions: |
Background jobs/workers may perform persistence.
- ✅ Allow $entityManager->flush() here when the job is the orchestration boundary.
- Verify idempotency and that flush frequency is appropriate (batching where practical).
- Ensure no domain-layer code invoked by the job performs flush/transaction control.

auto_review:
enabled: true
base_branches:
- ".*"
drafts: false
# ignore_title_keywords:
# - ''

#knowledge_base:
# code_guidelines:
# filePatterns:
# - ".github/AGENT.md"
103 changes: 103 additions & 0 deletions .github/AGENT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
# AGENT.md — Code Review Knowledge Base for phpList/core

## 🧭 Repository Overview

This repository is the **core package** of **phpList 4**, a modular and extensible email campaign management system.

- **Purpose:** Provides the reusable foundation and framework for phpList applications and modules.
- **Consumers:** `phpList/web-frontend`, `phpList/rest-api`, and `phpList/base-distribution`.
- **Core responsibilities:**
- Application bootstrapping and service configuration
- Database ORM (Doctrine) integration
- Command-line utilities (Symfony Console)
- Async email sending via Symfony Messenger
- Logging, configuration, routing, dependency injection
- Schema definition and updates

> **Note:** This repository does *not* contain UI or REST endpoints. Those are part of other phpList packages.

---

## ⚙️ Tech Stack

| Category | Technology |
|-----------|-------------|
| Language | PHP ≥ 8.1 |
| Framework | Symfony 6.x components |
| ORM | Doctrine ORM 3.x |
| Async / Queue | Symfony Messenger |
| Tests | PHPUnit |
| Static analysis | PHPStan |
| Docs | PHPDocumentor |
| License | AGPL-3.0 |

---

## 📁 Project Structure
- .github/ CI/CD and PR templates
- bin/ Symfony console entrypoints
- config/ Application & environment configs
- docs/ Developer documentation and generated API docs
- public/ Public entrypoint for local web server
- resources/Database/ Canonical SQL schema
- src/ Core PHP source code
- tests/ PHPUnit test suites
- composer.json Package metadata and dependencies
- phpunit.xml.dist Test configuration
- phpstan.neon Static analysis configuration

---

## 💡 Code Design Principles

1. **Modularity:**
The core remains framework-like — decoupled from frontend or API layers.

2. **Dependency Injection:**
Use Symfony’s service container; avoid static/global dependencies.

3. **Strict Typing:**
Always use `declare(strict_types=1);` and explicit type declarations.

4. **Doctrine Entities:**
- Keep entities simple (no business logic).
- Mirror schema changes in `resources/Database/Schema.sql`.
- Maintain backward compatibility with phpList 3.

5. **Symfony Best Practices:**
Follow Symfony structure and naming conventions. Use annotations or attributes for routing.

6. **Error Handling & Logging:**
- Prefer structured logging via Graylog.
- Catch and handle exceptions at service or command boundaries.

7. **Async Email:**
- Uses Symfony Messenger.
- Handlers must be idempotent and retry-safe.
- Avoid blocking or synchronous email sending.

---

## 🧪 Testing Guidelines

- **Framework:** PHPUnit
- **Database:** SQLite or mocks for unit tests; MySQL for integration tests.
- **Coverage target:** ≥85% for core logic.
- **Naming:** Mirror source structure (e.g., `Mailer.php` → `MailerTest.php`).


## 🧱 Code Style

- Follow PSR-12 and Symfony coding conventions.
- Match the current codebase’s formatting and spacing.
- Use meaningful, consistent naming.
- Apply a single responsibility per class.


## 🔄 Pull Request Review Guidelines
### 🔐 Security Review Notes

- Do not log sensitive data (passwords, tokens, SMTP credentials).
- Sanitize all user and external inputs.
- Always use parameterized Doctrine queries.
- Async jobs must be retry-safe and idempotent.
36 changes: 1 addition & 35 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -1,37 +1,3 @@
### Summary

Provide a general description of the code changes in your pull request …
were there any bugs you had fixed? If so, mention them. If these bugs have open
GitHub issues, be sure to tag them here as well, to keep the conversation
linked together.


### Unit test

Are your changes covered with unit tests, and do they not break anything?

You can run the existing unit tests using this command:

vendor/bin/phpunit tests/


### Code style

Have you checked that you code is well-documented and follows the PSR-2 coding
style?

You can check for this using this command:

vendor/bin/phpcs --standard=PSR2 src/ tests/


### Other Information

If there's anything else that's important and relevant to your pull
request, mention that information here. This could include benchmarks,
or other information.

If you are updating any of the CHANGELOG files or are asked to update the
CHANGELOG files by reviewers, please add the CHANGELOG entry at the top of the file.
"@coderabbitai summary"

Thanks for contributing to phpList!
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -75,4 +75,4 @@ jobs:
- name: Running PHPMD
run: vendor/bin/phpmd src/ text config/PHPMD/rules.xml;
- name: Running PHP_CodeSniffer
run: vendor/bin/phpcs --standard=config/PhpCodeSniffer/ bin/ src/ tests/ public/;
run: vendor/bin/phpcs --standard=config/PhpCodeSniffer/ --ignore=*/Migrations/* bin/ src/ tests/ public/;
69 changes: 69 additions & 0 deletions .github/workflows/i18n-validate.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
name: I18n Validate

on:
pull_request:
paths:
- 'resources/translations/**/*.xlf'
- 'composer.lock'
- 'composer.json'

jobs:
validate-xliff:
runs-on: ubuntu-22.04

strategy:
fail-fast: false
matrix:
php: ['8.1']

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
extensions: imap, zip
tools: composer:v2
coverage: none

- name: Cache Composer packages
uses: actions/cache@v4
with:
path: |
~/.composer/cache/files
key: ${{ runner.os }}-composer-${{ matrix.php }}-${{ hashFiles('**/composer.lock') }}
restore-keys: |
${{ runner.os }}-composer-${{ matrix.php }}-

- name: Install dependencies (no dev autoloader scripts)
run: |
set -euo pipefail
composer install --no-interaction --no-progress --prefer-dist

- name: Lint XLIFF with Symfony
run: |
set -euo pipefail
# Adjust the directory to match your repo layout
php bin/console lint:xliff resources/translations

- name: Validate XLIFF XML with xmllint
run: |
set -euo pipefail
sudo apt-get update
sudo apt-get install -y --no-install-recommends libxml2-utils
# Adjust root dir; prune vendor; accept spaces/newlines safely
find resources/translations -type f -name '*.xlf' -not -path '*/vendor/*' -print0 \
| xargs -0 -n1 xmllint --noout

- name: Symfony translation sanity (extract dry-run)
run: |
set -euo pipefail
# Show what would be created/updated without writing files
php bin/console translation:extract en \
--format=xlf \
--domain=messages \
--dump-messages \
--no-interaction
# Note: omit --force to keep this a dry-run
23 changes: 23 additions & 0 deletions .weblate
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# .weblate
---
projects:
- slug: phplist-core
name: phpList core
components:
- slug: messages
name: Messages
files:
# {language} is Weblate’s placeholder (e.g., fr, de, es)
- src: resources/translations/messages.en.xlf
template: true
# Where localized files live (mirrors Symfony layout)
target: resources/translations/messages.{language}.xlf
file_format: xliff
language_code_style: bcp
# Ensure placeholders like %name% are preserved
parse_file_headers: true
check_flags:
- xml-invalid
- placeholders
- urls
- accelerated
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -214,3 +214,11 @@ For detailed configuration instructions, see the [Mailer Transports documentatio
## Copyright

phpList is copyright (C) 2000-2025 [phpList Ltd](https://www.phplist.com/).


### Translations
command to extract translation strings

```bash
php bin/console translation:extract --force en --format=xlf
```
19 changes: 17 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@
"role": "Maintainer"
}
],
"repositories": [
{
"type": "vcs",
"url": "https://github.com/TatevikGr/rss-bundle.git"
}
],
"support": {
"issues": "https://github.com/phpList/core/issues",
"forum": "https://discuss.phplist.org/",
Expand Down Expand Up @@ -68,7 +74,10 @@
"symfony/sendgrid-mailer": "^6.4",
"symfony/twig-bundle": "^6.4",
"symfony/messenger": "^6.4",
"symfony/lock": "^6.4"
"symfony/lock": "^6.4",
"webklex/php-imap": "^6.2",
"ext-imap": "*",
"tatevikgr/rss-feed": "dev-main"
},
"require-dev": {
"phpunit/phpunit": "^9.5",
Expand Down Expand Up @@ -140,7 +149,8 @@
"Doctrine\\Bundle\\DoctrineBundle\\DoctrineBundle",
"Doctrine\\Bundle\\MigrationsBundle\\DoctrineMigrationsBundle",
"PhpList\\Core\\EmptyStartPageBundle\\EmptyStartPageBundle",
"FOS\\RestBundle\\FOSRestBundle"
"FOS\\RestBundle\\FOSRestBundle",
"TatevikGr\\RssFeedBundle\\RssFeedBundle"
],
"routes": {
"homepage": {
Expand All @@ -149,5 +159,10 @@
}
}
}
},
"config": {
"allow-plugins": {
"php-http/discovery": true
}
}
}
11 changes: 8 additions & 3 deletions config/PHPMD/rules.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
PHPMD rules for phpList
</description>

<exclude-pattern>*/Migrations/*</exclude-pattern>

<!-- rules from the "clean code" rule set -->
<rule ref="rulesets/cleancode.xml/BooleanArgumentFlag"/>
<rule ref="rulesets/cleancode.xml/StaticAccess">
Expand Down Expand Up @@ -45,13 +47,17 @@
<rule ref="rulesets/design.xml/GotoStatement"/>
<rule ref="rulesets/design.xml/NumberOfChildren"/>
<rule ref="rulesets/design.xml/DepthOfInheritance"/>
<rule ref="rulesets/design.xml/CouplingBetweenObjects"/>
<rule ref="rulesets/design.xml/CouplingBetweenObjects">
<properties>
<property name="maximum" value="15"/>
</properties>
</rule>
<rule ref="rulesets/design.xml/DevelopmentCodeFragment"/>

<!-- rules from the "naming" rule set -->
<rule ref="rulesets/naming.xml/ShortVariable">
<properties>
<property name="exceptions" value="id,ip,cc"/>
<property name="exceptions" value="id,ip,cc,io"/>
</properties>
</rule>
<rule ref="rulesets/naming.xml/LongVariable">
Expand All @@ -67,5 +73,4 @@
<rule ref="rulesets/unusedcode.xml/UnusedPrivateField"/>
<rule ref="rulesets/unusedcode.xml/UnusedLocalVariable"/>
<rule ref="rulesets/unusedcode.xml/UnusedPrivateMethod"/>
<rule ref="rulesets/unusedcode.xml/UnusedFormalParameter"/>
</ruleset>
Loading
Loading