-
Notifications
You must be signed in to change notification settings - Fork 0
Code refactoring and additional tests. #14
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
Merged
Merged
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
79523bd
updated versionlog.
ljonesfl 6f8bc55
refactoring
ljonesfl 03e6e02
Update tests/Cms/Services/User/UpdaterTest.php
ljonesfl 04a5069
Update src/Cms/Services/User/Updater.php
ljonesfl c084cfc
Update tests/Cms/Services/User/CreatorTest.php
ljonesfl 84db963
Initial plan
Copilot 3f97074
Add validation to prevent empty username/email updates in UserController
Copilot 3c1939b
Merge pull request #15 from Neuron-PHP/copilot/sub-pr-14
ljonesfl File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,266 @@ | ||
| # Event System | ||
|
|
||
| The CMS uses an event-driven architecture to decouple business logic from side effects like sending emails and clearing caches. | ||
|
|
||
| ## Available Events | ||
|
|
||
| ### User Events | ||
| - **UserCreatedEvent** - Fired when a new user is created | ||
| - **UserUpdatedEvent** - Fired when a user is updated | ||
| - **UserDeletedEvent** - Fired when a user is deleted | ||
|
|
||
| ### Post Events | ||
| - **PostCreatedEvent** - Fired when a new post is created | ||
| - **PostPublishedEvent** - Fired when a post is published | ||
| - **PostDeletedEvent** - Fired when a post is deleted | ||
|
|
||
| ### Category Events | ||
| - **CategoryCreatedEvent** - Fired when a new category is created | ||
| - **CategoryUpdatedEvent** - Fired when a category is updated | ||
| - **CategoryDeletedEvent** - Fired when a category is deleted | ||
|
|
||
| ## Built-in Listeners | ||
|
|
||
| ### SendWelcomeEmailListener | ||
|
|
||
| Sends a professional HTML welcome email to newly registered users using the **editable template** at `resources/views/emails/welcome.php`. | ||
|
|
||
| **Configuration:** | ||
| ```yaml | ||
| # resources/config/email.yaml | ||
| email: | ||
| test_mode: false # Set true to log instead of send | ||
| driver: smtp # or 'mail', 'sendmail' | ||
| from_address: noreply@yourdomain.com | ||
| from_name: Your Site Name | ||
| # SMTP settings (if driver is 'smtp') | ||
| host: smtp.gmail.com | ||
| port: 587 | ||
| username: your-email@gmail.com | ||
| password: your-app-password | ||
| encryption: tls | ||
| ``` | ||
|
|
||
| **Template Location:** | ||
| `resources/views/emails/welcome.php` - Fully editable PHP template | ||
|
|
||
| **Template Variables:** | ||
| - `$Username` - New user's username | ||
| - `$SiteName` - Site name from settings | ||
| - `$SiteUrl` - Site URL from settings | ||
|
|
||
| **Features:** | ||
| - **Editable template** - Customize design, colors, text without code changes | ||
| - **PHPMailer integration** - Professional email delivery with SMTP support | ||
| - **Test mode** - Logs emails during development instead of sending | ||
| - **Responsive design** - Works on desktop and mobile email clients | ||
| - **Inline CSS** - Styles work across all email clients | ||
| - **XSS protection** - All variables properly escaped | ||
|
|
||
| **Customization:** | ||
| Simply edit `resources/views/emails/welcome.php` to: | ||
| - Change gradient colors | ||
| - Add your logo | ||
| - Modify greeting message | ||
| - Update call-to-action button | ||
| - Customize footer | ||
| - Add social media links | ||
|
|
||
| See [EMAIL_TEMPLATES.md](EMAIL_TEMPLATES.md) for complete customization guide. | ||
|
|
||
| ### ClearCacheListener | ||
|
|
||
| Automatically clears view cache when content changes to ensure users see fresh content. | ||
|
|
||
| **Triggers:** | ||
| - Post published | ||
| - Post deleted | ||
| - Category updated | ||
|
|
||
| **How it Works:** | ||
| 1. Listener receives content change event | ||
| 2. Retrieves ViewCache instance from Registry | ||
| 3. Calls `ViewCache::clear()` to invalidate all cached views | ||
| 4. Logs success/failure for debugging | ||
|
|
||
| **Requirements:** | ||
| - ViewCache must be registered in Registry as 'ViewCache' | ||
| - Cache storage must be configured (File or Redis) | ||
|
|
||
| ### LogUserActivityListener | ||
|
|
||
| Logs all user activity for audit trail purposes. | ||
|
|
||
| **Logged Activities:** | ||
| - User created: "User created: username (ID: 1)" | ||
| - User updated: "User updated: username (ID: 1)" | ||
| - User deleted: "User deleted: ID 1" | ||
|
|
||
| **Log Level:** INFO | ||
|
|
||
| ## Event Configuration | ||
|
|
||
| Events and their listeners are configured in `resources/config/event-listeners.yaml`: | ||
|
|
||
| ```yaml | ||
| events: | ||
| user.created: | ||
| class: 'Neuron\Cms\Events\UserCreatedEvent' | ||
| listeners: | ||
| - 'Neuron\Cms\Listeners\SendWelcomeEmailListener' | ||
| - 'Neuron\Cms\Listeners\LogUserActivityListener' | ||
|
|
||
| user.updated: | ||
| class: 'Neuron\Cms\Events\UserUpdatedEvent' | ||
| listeners: | ||
| - 'Neuron\Cms\Listeners\LogUserActivityListener' | ||
|
|
||
| user.deleted: | ||
| class: 'Neuron\Cms\Events\UserDeletedEvent' | ||
| listeners: | ||
| - 'Neuron\Cms\Listeners\LogUserActivityListener' | ||
|
|
||
| post.published: | ||
| class: 'Neuron\Cms\Events\PostPublishedEvent' | ||
| listeners: | ||
| - 'Neuron\Cms\Listeners\ClearCacheListener' | ||
|
|
||
| post.deleted: | ||
| class: 'Neuron\Cms\Events\PostDeletedEvent' | ||
| listeners: | ||
| - 'Neuron\Cms\Listeners\ClearCacheListener' | ||
|
|
||
| category.updated: | ||
| class: 'Neuron\Cms\Events\CategoryUpdatedEvent' | ||
| listeners: | ||
| - 'Neuron\Cms\Listeners\ClearCacheListener' | ||
| ``` | ||
|
|
||
| ## Creating Custom Listeners | ||
|
|
||
| ### Step 1: Create Listener Class | ||
|
|
||
| ```php | ||
| <?php | ||
| namespace Neuron\Cms\Listeners; | ||
|
|
||
| use Neuron\Events\IListener; | ||
| use Neuron\Cms\Events\UserCreatedEvent; | ||
| use Neuron\Log\Log; | ||
|
|
||
| class MyCustomListener implements IListener | ||
| { | ||
| public function event( $event ): void | ||
| { | ||
| if( !$event instanceof UserCreatedEvent ) | ||
| { | ||
| return; | ||
| } | ||
|
|
||
| $user = $event->user; | ||
|
|
||
| // Your custom logic here | ||
| Log::info( "Custom action for user: {$user->getUsername()}" ); | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ### Step 2: Register in Configuration | ||
|
|
||
| Add your listener to `resources/config/event-listeners.yaml`: | ||
|
|
||
| ```yaml | ||
| events: | ||
| user.created: | ||
| class: 'Neuron\Cms\Events\UserCreatedEvent' | ||
| listeners: | ||
| - 'Neuron\Cms\Listeners\SendWelcomeEmailListener' | ||
| - 'Neuron\Cms\Listeners\LogUserActivityListener' | ||
| - 'Neuron\Cms\Listeners\MyCustomListener' # Your listener | ||
| ``` | ||
|
|
||
| ## How Events are Emitted | ||
|
|
||
| Events are emitted from service classes, not controllers. This keeps controllers thin and business logic encapsulated. | ||
|
|
||
| **Example from User\Creator service:** | ||
|
|
||
| ```php | ||
| public function create( /* ... */ ): User | ||
| { | ||
| // Create user | ||
| $user = new User(); | ||
| // ... set user properties | ||
| $user = $this->_userRepository->create( $user ); | ||
|
|
||
| // Emit event | ||
| $emitter = Registry::getInstance()->get( 'EventEmitter' ); | ||
| if( $emitter ) | ||
| { | ||
| $emitter->emit( new UserCreatedEvent( $user ) ); | ||
| } | ||
|
|
||
| return $user; | ||
| } | ||
| ``` | ||
|
|
||
| ## Benefits of Event-Driven Architecture | ||
|
|
||
| 1. **Decoupling** - Services don't need to know about emails, caching, logging, etc. | ||
| 2. **Extensibility** - Add new listeners without modifying existing code | ||
| 3. **Testability** - Easy to test services without side effects | ||
| 4. **Flexibility** - Enable/disable features by adding/removing listeners | ||
| 5. **Single Responsibility** - Each component does one thing well | ||
|
|
||
| ## Debugging Events | ||
|
|
||
| Enable debug logging to see event flow: | ||
|
|
||
| ```php | ||
| Log::setLevel( Log::DEBUG ); | ||
| ``` | ||
|
|
||
| You'll see logs like: | ||
| ``` | ||
| [INFO] User created: testuser (ID: 5) | ||
| [DEBUG] Settings not available - welcome email skipped for: test@example.com | ||
| [INFO] Cache cleared successfully: Post published: My New Post | ||
| ``` | ||
|
|
||
| ## Testing Listeners | ||
|
|
||
| Listeners can be tested in isolation: | ||
|
|
||
| ```php | ||
| public function testSendWelcomeEmailListener(): void | ||
| { | ||
| $user = new User(); | ||
| $user->setEmail( 'test@example.com' ); | ||
|
|
||
| $event = new UserCreatedEvent( $user ); | ||
| $listener = new SendWelcomeEmailListener(); | ||
|
|
||
| // Should not throw exception | ||
| $listener->event( $event ); | ||
|
|
||
| $this->assertTrue( true ); | ||
| } | ||
| ``` | ||
|
|
||
| ## Performance Considerations | ||
|
|
||
| - Listeners run synchronously during the request | ||
| - Keep listener logic fast (< 100ms) | ||
| - For slow operations (external APIs), use a job queue instead | ||
| - Cache clearing is fast (< 10ms typically) | ||
| - Email sending uses PHP's mail() which is non-blocking | ||
|
|
||
| ## Future Enhancements | ||
|
|
||
| Potential improvements to the event system: | ||
|
|
||
| 1. **Async Listeners** - Queue slow listeners for background processing | ||
| 2. **Event Priorities** - Control listener execution order | ||
| 3. **Conditional Listeners** - Only fire based on conditions | ||
| 4. **Event Middleware** - Transform events before listeners receive them | ||
| 5. **Dead Letter Queue** - Capture failed listener executions |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,68 @@ | ||
| # Email Configuration Example | ||
| # | ||
| # Copy this file to email.yaml and configure for your environment | ||
| # | ||
| # This configuration is used by the SendWelcomeEmailListener and other | ||
| # email-sending features of the CMS powered by PHPMailer. | ||
|
|
||
| email: | ||
| # Test mode - logs emails instead of sending (useful for development) | ||
| # When enabled, emails are logged to the log file instead of being sent | ||
| test_mode: false | ||
|
|
||
| # Email driver: mail, sendmail, or smtp | ||
| # - mail: Uses PHP's mail() function (default, requires server mail setup) | ||
| # - sendmail: Uses sendmail binary (Linux/Mac) | ||
| # - smtp: Uses SMTP server (recommended for production) | ||
| driver: mail | ||
|
|
||
| # From address and name for system emails | ||
| from_address: noreply@yourdomain.com | ||
| from_name: Your Site Name | ||
|
|
||
| # SMTP Configuration (only required if driver is 'smtp') | ||
| # Examples for popular email services: | ||
| # | ||
| # Gmail: | ||
| # host: smtp.gmail.com | ||
| # port: 587 | ||
| # encryption: tls | ||
| # username: your-email@gmail.com | ||
| # password: your-app-password (not your regular password!) | ||
| # | ||
| # SendGrid: | ||
| # host: smtp.sendgrid.net | ||
| # port: 587 | ||
| # encryption: tls | ||
| # username: apikey | ||
| # password: your-sendgrid-api-key | ||
| # | ||
| # Mailgun: | ||
| # host: smtp.mailgun.org | ||
| # port: 587 | ||
| # encryption: tls | ||
| # username: postmaster@yourdomain.com | ||
| # password: your-mailgun-smtp-password | ||
|
|
||
| # host: smtp.gmail.com | ||
| # port: 587 | ||
| # username: your-email@gmail.com | ||
| # password: your-app-password | ||
| # encryption: tls # or 'ssl' for port 465 | ||
|
|
||
| # Email Template Customization | ||
| # | ||
| # Templates are located in: resources/views/emails/ | ||
| # | ||
| # Available templates: | ||
| # - welcome.php - Welcome email sent to new users | ||
| # | ||
| # To customize, edit the template files directly. They use standard PHP | ||
| # templating with variables like $Username, $SiteName, $SiteUrl. | ||
| # | ||
| # Example customization in welcome.php: | ||
| # - Change colors in the <style> section | ||
| # - Modify greeting text | ||
| # - Update call-to-action button text | ||
| # - Add your logo (use absolute URL for images) | ||
| # - Customize footer text | ||
ljonesfl marked this conversation as resolved.
Show resolved
Hide resolved
|
||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.