From 2ca47e1042bc375f49f35f1fc0b45c74f0adcb5b Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Fri, 14 Nov 2025 08:31:35 -0600 Subject: [PATCH 1/2] refactors controllers to use the new method signature and updated request object. --- composer.json | 2 +- src/Cms/Controllers/Admin/Categories.php | 36 ++++----- src/Cms/Controllers/Admin/Dashboard.php | 7 +- src/Cms/Controllers/Admin/Posts.php | 48 ++++++------ src/Cms/Controllers/Admin/Profile.php | 19 ++--- src/Cms/Controllers/Admin/Tags.php | 36 ++++----- src/Cms/Controllers/Admin/Users.php | 46 ++++++----- src/Cms/Controllers/Auth/Login.php | 35 +++++---- src/Cms/Controllers/Auth/PasswordReset.php | 73 +++++++----------- src/Cms/Controllers/Blog.php | 85 +++++++++------------ src/Cms/Controllers/Content.php | 23 +++--- src/Cms/Controllers/Home.php | 11 +-- src/Cms/Controllers/Member/Dashboard.php | 8 +- src/Cms/Controllers/Member/Profile.php | 21 ++--- src/Cms/Controllers/Member/Registration.php | 54 ++++++------- tests/Cms/BlogControllerTest.php | 34 ++++----- tests/Cms/ContentControllerTest.php | 6 +- 17 files changed, 262 insertions(+), 282 deletions(-) diff --git a/composer.json b/composer.json index 38daa31..0433b96 100644 --- a/composer.json +++ b/composer.json @@ -12,7 +12,7 @@ "require": { "ext-curl": "*", "ext-json": "*", - "neuron-php/mvc": "0.8.*", + "neuron-php/mvc": "0.9.*", "neuron-php/cli": "0.8.*", "neuron-php/jobs": "0.2.*", "neuron-php/orm": "0.1.*", diff --git a/src/Cms/Controllers/Admin/Categories.php b/src/Cms/Controllers/Admin/Categories.php index 87a15ee..268c8e1 100644 --- a/src/Cms/Controllers/Admin/Categories.php +++ b/src/Cms/Controllers/Admin/Categories.php @@ -46,12 +46,11 @@ public function __construct( ?Application $app = null ) /** * List categories - * @param array $parameters - * @param Request|null $request + * @param Request $request * @return string * @throws \Exception */ - public function index( array $parameters, ?Request $request ): string + public function index( Request $request ): string { $user = Registry::getInstance()->get( 'Auth.User' ); @@ -79,12 +78,11 @@ public function index( array $parameters, ?Request $request ): string /** * Show create category form - * @param array $parameters - * @param Request|null $request + * @param Request $request * @return string * @throws \Exception */ - public function create( array $parameters, ?Request $request ): string + public function create( Request $request ): string { $user = Registry::getInstance()->get( 'Auth.User' ); @@ -109,12 +107,11 @@ public function create( array $parameters, ?Request $request ): string /** * Store new category - * @param array $parameters - * @param Request|null $request + * @param Request $request * @return never * @throws \Exception */ - public function store( array $parameters, ?Request $request ): never + public function store( Request $request ): never { try { @@ -133,12 +130,11 @@ public function store( array $parameters, ?Request $request ): never /** * Show edit category form - * @param array $parameters - * @param Request|null $request + * @param Request $request * @return string * @throws \Exception */ - public function edit( array $parameters, ?Request $request ): string + public function edit( Request $request ): string { $user = Registry::getInstance()->get( 'Auth.User' ); @@ -147,7 +143,7 @@ public function edit( array $parameters, ?Request $request ): string throw new \RuntimeException( 'Authenticated user not found' ); } - $categoryId = (int)$parameters['id']; + $categoryId = (int)$request->getRouteParameter( 'id' ); $category = $this->_categoryRepository->findById( $categoryId ); if( !$category ) @@ -172,14 +168,13 @@ public function edit( array $parameters, ?Request $request ): string /** * Update category - * @param array $parameters - * @param Request|null $request + * @param Request $request * @return never * @throws \Exception */ - public function update( array $parameters, ?Request $request ): never + public function update( Request $request ): never { - $categoryId = (int)$parameters['id']; + $categoryId = (int)$request->getRouteParameter( 'id' ); $category = $this->_categoryRepository->findById( $categoryId ); if( !$category ) @@ -204,14 +199,13 @@ public function update( array $parameters, ?Request $request ): never /** * Delete category - * @param array $parameters - * @param Request|null $request + * @param Request $request * @return never * @throws \Exception */ - public function destroy( array $parameters, ?Request $request ): never + public function destroy( Request $request ): never { - $categoryId = (int)$parameters['id']; + $categoryId = (int)$request->getRouteParameter( 'id' ); try { diff --git a/src/Cms/Controllers/Admin/Dashboard.php b/src/Cms/Controllers/Admin/Dashboard.php index 7b1ae08..5180181 100644 --- a/src/Cms/Controllers/Admin/Dashboard.php +++ b/src/Cms/Controllers/Admin/Dashboard.php @@ -5,7 +5,9 @@ use Neuron\Cms\Controllers\Content; use Neuron\Cms\Auth\CsrfTokenManager; use Neuron\Cms\Auth\SessionManager; +use Neuron\Core\Exceptions\NotFound; use Neuron\Mvc\Application; +use Neuron\Mvc\Requests\Request; use Neuron\Mvc\Responses\HttpResponseStatus; use Neuron\Patterns\Registry; @@ -29,10 +31,11 @@ public function __construct( ?Application $app = null ) /** * Show admin dashboard - * @param array $parameters + * @param Request $request * @return string + * @throws NotFound */ - public function index( array $parameters ): string + public function index( Request $request ): string { // Get authenticated user from Registry $user = Registry::getInstance()->get( 'Auth.User' ); diff --git a/src/Cms/Controllers/Admin/Posts.php b/src/Cms/Controllers/Admin/Posts.php index 3c7c7af..0d6f7a6 100644 --- a/src/Cms/Controllers/Admin/Posts.php +++ b/src/Cms/Controllers/Admin/Posts.php @@ -15,6 +15,7 @@ use Neuron\Cms\Auth\SessionManager; use Neuron\Data\Setting\SettingManager; use Neuron\Mvc\Application; +use Neuron\Mvc\Requests\Request; use Neuron\Mvc\Responses\HttpResponseStatus; use Neuron\Patterns\Registry; @@ -25,7 +26,6 @@ */ class Posts extends Content { - private DatabasePostRepository $_postRepository; private DatabaseCategoryRepository $_categoryRepository; private DatabaseTagRepository $_tagRepository; @@ -72,11 +72,11 @@ public function __construct( ?Application $app = null ) /** * List all posts - * @param array $parameters + * @param Request $request * @return string * @throws \Exception */ - public function index( array $parameters ): string + public function index( Request $request ): string { $user = Registry::getInstance()->get( 'Auth.User' ); @@ -119,11 +119,11 @@ public function index( array $parameters ): string /** * Show create post form - * @param array $parameters + * @param Request $request * @return string * @throws \Exception */ - public function create( array $parameters ): string + public function create( Request $request ): string { $user = Registry::getInstance()->get( 'Auth.User' ); @@ -153,11 +153,11 @@ public function create( array $parameters ): string /** * Store new post - * @param array $parameters + * @param Request $request * @return never * @throws \Exception */ - public function store( array $parameters ): never + public function store( Request $request ): never { $user = Registry::getInstance()->get( 'Auth.User' ); @@ -201,11 +201,11 @@ public function store( array $parameters ): never /** * Show edit post form - * @param array $parameters + * @param Request $request * @return string * @throws \Exception */ - public function edit( array $parameters ): string + public function edit( Request $request ): string { $user = Registry::getInstance()->get( 'Auth.User' ); @@ -214,7 +214,7 @@ public function edit( array $parameters ): string throw new \RuntimeException( 'Authenticated user not found' ); } - $postId = (int)$parameters['id']; + $postId = (int)$request->getRouteParameter( 'id' ); $post = $this->_postRepository->findById( $postId ); if( !$post ) @@ -250,11 +250,11 @@ public function edit( array $parameters ): string /** * Update post - * @param array $parameters + * @param Request $request * @return never * @throws \Exception */ - public function update( array $parameters ): never + public function update( Request $request ): never { $user = Registry::getInstance()->get( 'Auth.User' ); @@ -263,7 +263,7 @@ public function update( array $parameters ): never throw new \RuntimeException( 'Authenticated user not found' ); } - $postId = (int)$parameters['id']; + $postId = (int)$request->getRouteParameter( 'id' ); $post = $this->_postRepository->findById( $postId ); if( !$post ) @@ -280,14 +280,14 @@ public function update( array $parameters ): never try { // Get form data - $title = $_POST['title'] ?? ''; - $slug = $_POST['slug'] ?? ''; - $content = $_POST['content'] ?? ''; - $excerpt = $_POST['excerpt'] ?? ''; - $featuredImage = $_POST['featured_image'] ?? ''; - $status = $_POST['status'] ?? Post::STATUS_DRAFT; - $categoryIds = $_POST['categories'] ?? []; - $tagNames = $_POST['tags'] ?? ''; + $title = $request->post( 'title', '' ); + $slug = $request->post('slug', '' ); + $content = $request->post( 'content', '' ); + $excerpt = $request->post( 'excerpt' ,'' ); + $featuredImage = $request->post( 'featured_image', '' ); + $status = $request->post( 'status', Post::STATUS_DRAFT ); + $categoryIds = $request->post( 'categories', [] ); + $tagNames = $request->post( 'tags','' ); // Update post using service $this->_postUpdater->update( @@ -312,10 +312,10 @@ public function update( array $parameters ): never /** * Delete post - * @param array $parameters + * @param Request $request * @return never */ - public function destroy( array $parameters ): never + public function destroy( Request $request ): never { $user = Registry::getInstance()->get( 'Auth.User' ); @@ -324,7 +324,7 @@ public function destroy( array $parameters ): never throw new \RuntimeException( 'Authenticated user not found' ); } - $postId = (int)$parameters['id']; + $postId = (int)$request->getRouteParameter( 'id' ); $post = $this->_postRepository->findById( $postId ); if( !$post ) diff --git a/src/Cms/Controllers/Admin/Profile.php b/src/Cms/Controllers/Admin/Profile.php index dd98cde..6a23203 100644 --- a/src/Cms/Controllers/Admin/Profile.php +++ b/src/Cms/Controllers/Admin/Profile.php @@ -9,6 +9,7 @@ use Neuron\Cms\Auth\CsrfTokenManager; use Neuron\Data\Setting\SettingManager; use Neuron\Mvc\Application; +use Neuron\Mvc\Requests\Request; use Neuron\Mvc\Responses\HttpResponseStatus; use Neuron\Patterns\Registry; @@ -42,11 +43,11 @@ public function __construct( ?Application $app = null ) /** * Show profile edit form - * @param array $parameters + * @param Request $request * @return string * @throws \Exception */ - public function edit( array $parameters ): string + public function edit( Request $request ): string { $user = Registry::getInstance()->get( 'Auth.User' ); @@ -81,11 +82,11 @@ public function edit( array $parameters ): string /** * Update profile - * @param array $parameters + * @param Request $request * @return never * @throws \Exception */ - public function update( array $parameters ): never + public function update( Request $request ): never { $user = Registry::getInstance()->get( 'Auth.User' ); @@ -94,11 +95,11 @@ public function update( array $parameters ): never throw new \RuntimeException( 'Authenticated user not found' ); } - $email = $_POST['email'] ?? ''; - $timezone = $_POST['timezone'] ?? ''; - $currentPassword = $_POST['current_password'] ?? ''; - $newPassword = $_POST['new_password'] ?? ''; - $confirmPassword = $_POST['confirm_password'] ?? ''; + $email = $request->post( 'email', '' ); + $timezone = $request->post( 'timezone', '' ); + $currentPassword = $request->post( 'current_password', '' ); + $newPassword = $request->post( 'new_password', '' ); + $confirmPassword = $request->post( 'confirm_password', '' ); // Validate password change if requested if( !empty( $newPassword ) ) diff --git a/src/Cms/Controllers/Admin/Tags.php b/src/Cms/Controllers/Admin/Tags.php index 725f842..c893b37 100644 --- a/src/Cms/Controllers/Admin/Tags.php +++ b/src/Cms/Controllers/Admin/Tags.php @@ -17,7 +17,6 @@ */ class Tags extends Content { - private DatabaseTagRepository $_tagRepository; /** @@ -37,12 +36,11 @@ public function __construct( ?Application $app = null ) /** * List all tags - * @param array $parameters - * @param Request|null $request + * @param Request $request * @return string * @throws \Exception */ - public function index( array $parameters, ?Request $request ): string + public function index( Request $request ): string { $user = Registry::getInstance()->get( 'Auth.User' ); @@ -70,12 +68,11 @@ public function index( array $parameters, ?Request $request ): string /** * Show create tag form - * @param array $parameters - * @param Request|null $request + * @param Request $request * @return string * @throws \Exception */ - public function create( array $parameters, ?Request $request ): string + public function create( Request $request ): string { $user = Registry::getInstance()->get( 'Auth.User' ); @@ -100,12 +97,11 @@ public function create( array $parameters, ?Request $request ): string /** * Store new tag - * @param array $parameters - * @param Request|null $request + * @param Request $request * @return never * @throws \Exception */ - public function store( array $parameters, ?Request $request ): never + public function store( Request $request ): never { try { @@ -131,12 +127,12 @@ public function store( array $parameters, ?Request $request ): never /** * Show edit tag form - * @param array $parameters + * @param Request|null $request * @return string * @throws \Exception */ - public function edit( array $parameters, ?Request $request ): string + public function edit( Request $request ): string { $user = Registry::getInstance()->get( 'Auth.User' ); @@ -145,7 +141,7 @@ public function edit( array $parameters, ?Request $request ): string throw new \RuntimeException( 'Authenticated user not found' ); } - $tagId = (int)$parameters['id']; + $tagId = (int)$request->getRouteParameter( 'id' ); $tag = $this->_tagRepository->findById( $tagId ); if( !$tag ) @@ -170,14 +166,14 @@ public function edit( array $parameters, ?Request $request ): string /** * Update tag - * @param array $parameters + * * @param Request|null $request * @return never * @throws \Exception */ - public function update( array $parameters, ?Request $request ): never + public function update( Request $request ): never { - $tagId = (int)$parameters['id']; + $tagId = (int)$request->getRouteParameter( 'id' ); $tag = $this->_tagRepository->findById( $tagId ); if( !$tag ) @@ -208,14 +204,14 @@ public function update( array $parameters, ?Request $request ): never /** * Delete tag - * @param array $parameters - * @param Request|null $request + + * @param Request $request * @return never * @throws \Exception */ - public function destroy( array $parameters, ?Request $request ): never + public function destroy( Request $request ): never { - $tagId = (int)$parameters['id']; + $tagId = (int)$request->getRouteParameter( 'id' ); try { diff --git a/src/Cms/Controllers/Admin/Users.php b/src/Cms/Controllers/Admin/Users.php index 4d0d535..b4ea15a 100644 --- a/src/Cms/Controllers/Admin/Users.php +++ b/src/Cms/Controllers/Admin/Users.php @@ -12,6 +12,7 @@ use Neuron\Cms\Auth\CsrfTokenManager; use Neuron\Data\Setting\SettingManager; use Neuron\Mvc\Application; +use Neuron\Mvc\Requests\Request; use Neuron\Mvc\Responses\HttpResponseStatus; use Neuron\Patterns\Registry; @@ -48,11 +49,11 @@ public function __construct( ?Application $app = null ) /** * List all users - * @param array $parameters + * @param Request $request * @return string * @throws \Exception */ - public function index( array $parameters ): string + public function index( Request $request ): string { $user = Registry::getInstance()->get( 'Auth.User' ); @@ -81,11 +82,11 @@ public function index( array $parameters ): string /** * Show create user form - * @param array $parameters + * @param Request $request * @return string * @throws \Exception */ - public function create( array $parameters ): string + public function create( Request $request ): string { $user = Registry::getInstance()->get( 'Auth.User' ); @@ -110,16 +111,16 @@ public function create( array $parameters ): string /** * Store new user - * @param array $parameters + * @param Request $request * @return never * @throws \Exception */ - public function store( array $parameters ): never + public function store( Request $request ): never { - $username = $_POST['username'] ?? ''; - $email = $_POST['email'] ?? ''; - $password = $_POST['password'] ?? ''; - $role = $_POST['role'] ?? User::ROLE_SUBSCRIBER; + $username = $request->post( 'username','' ); + $email = $request->post( 'email', '' ); + $password = $request->post( 'password', '' ); + $role = $request->post( 'role', User::ROLE_SUBSCRIBER ); // Basic validation if( empty( $username ) || empty( $email ) || empty( $password ) ) @@ -140,13 +141,14 @@ public function store( array $parameters ): never /** * Show edit user form - * @param array $parameters + * + * @param Request $request * @return string|never * @throws \Exception */ - public function edit( array $parameters ) + public function edit( Request $request ) : string|never { - $id = (int)$parameters['id']; + $id = (int)$request->getRouteParameter( 'id' ); $currentUser = Registry::getInstance()->get( 'Auth.User' ); $user = $this->_repository->findById( $id ); @@ -177,13 +179,14 @@ public function edit( array $parameters ) /** * Update user - * @param array $parameters + * + * @param Request $request * @return never * @throws \Exception */ - public function update( array $parameters ): never + public function update( Request $request ): never { - $id = (int)$parameters['id']; + $id = (int)$request->getRouteParameter( 'id' ); $user = $this->_repository->findById( $id ); if( !$user ) @@ -191,8 +194,8 @@ public function update( array $parameters ): never $this->redirect( 'admin_users', [], ['error', 'User not found'] ); } - $usernameInput = $_POST['username'] ?? null; - $emailInput = $_POST['email'] ?? null; + $usernameInput = $request->post( 'username', null ); + $emailInput = $request->post( 'email', null ); $username = $usernameInput !== null ? trim( (string)$usernameInput ) : $user->getUsername(); $email = $emailInput !== null ? trim( (string)$emailInput ) : $user->getEmail(); @@ -218,13 +221,14 @@ public function update( array $parameters ): never /** * Delete user - * @param array $parameters + * + * @param Request $request * @return never * @throws \Exception */ - public function destroy( array $parameters ): never + public function destroy( Request $request ): never { - $id = (int)$parameters['id']; + $id = (int)$request->getRouteParameter( 'id' ); $currentUser = Registry::getInstance()->get( 'Auth.User' ); // Prevent self-deletion diff --git a/src/Cms/Controllers/Auth/Login.php b/src/Cms/Controllers/Auth/Login.php index 839ca66..85c1b9f 100644 --- a/src/Cms/Controllers/Auth/Login.php +++ b/src/Cms/Controllers/Auth/Login.php @@ -5,10 +5,11 @@ use Neuron\Cms\Controllers\Content; use Neuron\Cms\Auth\AuthManager; use Neuron\Cms\Auth\CsrfTokenManager; -use Neuron\Data\Filter\Post; +use Neuron\Core\Exceptions\NotFound; use Neuron\Mvc\Application; use Neuron\Mvc\Responses\HttpResponseStatus; use Neuron\Patterns\Registry; +use Neuron\Mvc\Requests\Request; /** * Login controller. @@ -44,23 +45,24 @@ public function __construct( ?Application $app = null ) /** * Show login form - * @param array $parameters + * + * @param Request $request * @return string + * @throws NotFound */ - public function showLoginForm( array $parameters ): string + public function showLoginForm( Request $request ): string { - // If already logged in, redirect to dashboard + // If already logged in, redirect to the dashboard if( $this->_authManager->check() ) { - header( 'Location: ' . $this->urlFor( 'admin_dashboard' ) ); - exit; + $this->redirect( 'admin_dashboard' ); } // Set CSRF token in Registry so csrf_field() helper works Registry::getInstance()->set( 'Auth.CsrfToken', $this->_csrfManager->getToken() ); $defaultRedirect = $this->urlFor( 'admin_dashboard' ) ?? '/admin/dashboard'; - $requestedRedirect = $this->filterGet( 'redirect', $defaultRedirect ); + $requestedRedirect = $request->get( 'redirect', $defaultRedirect ); $redirectUrl = $this->isValidRedirectUrl( $requestedRedirect ) ? $requestedRedirect : $defaultRedirect; @@ -83,13 +85,14 @@ public function showLoginForm( array $parameters ): string /** * Process login - * @param array $parameters + * + * @param Request $request * @return never */ - public function login( array $parameters ): never + public function login( Request $request ): never { // Validate CSRF token - $token = new Post()->filterScalar( 'csrf_token' ); + $token = $request->post( 'csrf_token' ); if( !$this->_csrfManager->validate( $token ) ) { @@ -97,9 +100,9 @@ public function login( array $parameters ): never } // Get credentials - $username = $_POST['username'] ?? ''; - $password = $_POST['password'] ?? ''; - $remember = isset( $_POST['remember'] ); + $username = $request->post( 'username', '' ); + $password = $request->post( 'password', '' ); + $remember = $request->post( 'remember' ) === 'on'; // Validate input if( empty( $username ) || empty( $password ) ) @@ -125,10 +128,10 @@ public function login( array $parameters ): never /** * Process logout - * @param array $parameters + * @param Request $request * @return never */ - public function logout( array $parameters ): never + public function logout( Request $request ): never { $this->_authManager->logout(); $this->redirect( 'login', [], ['success', 'You have been logged out successfully.'] ); @@ -164,7 +167,7 @@ private function isValidRedirectUrl( string $url ): bool // Check for malicious patterns // Prevent URLs with @ symbol (could be used for phishing: /path@evil.com) // Prevent URLs with backslashes (could bypass filters: /\evil.com) - if( strpos( $url, '@' ) !== false || strpos( $url, '\\' ) !== false ) + if( str_contains( $url, '@' ) || str_contains( $url, '\\' ) ) { return false; } diff --git a/src/Cms/Controllers/Auth/PasswordReset.php b/src/Cms/Controllers/Auth/PasswordReset.php index cc67170..d26d2ed 100644 --- a/src/Cms/Controllers/Auth/PasswordReset.php +++ b/src/Cms/Controllers/Auth/PasswordReset.php @@ -6,8 +6,10 @@ use Neuron\Cms\Auth\PasswordResetManager; use Neuron\Cms\Auth\SessionManager; use Neuron\Cms\Auth\CsrfTokenManager; +use Neuron\Core\Exceptions\NotFound; use Neuron\Log\Log; use Neuron\Mvc\Application; +use Neuron\Mvc\Requests\Request; use Neuron\Mvc\Responses\HttpResponseStatus; use Neuron\Mvc\Views\Html; use Neuron\Patterns\Registry; @@ -47,10 +49,11 @@ public function __construct( ?Application $app = null ) /** * Show forgot password form - * @param array $parameters + * + * @param Request $request * @return string */ - public function showForgotPasswordForm( array $parameters ): string + public function showForgotPasswordForm( Request $request ): string { // Set CSRF token in Registry so csrf_field() helper works Registry::getInstance()->set( 'Auth.CsrfToken', $this->_csrfManager->getToken() ); @@ -73,13 +76,14 @@ public function showForgotPasswordForm( array $parameters ): string /** * Process forgot password request + * * @param array $parameters * @return string */ - public function requestReset( array $parameters ): string + public function requestReset( Request $request ): string { // Validate CSRF token - $token = $_POST['csrf_token'] ?? ''; + $token = $request->post( 'csrf_token', '' ); if( !$this->_csrfManager->validate( $token ) ) { $this->_sessionManager->flash( 'error', 'Invalid CSRF token. Please try again.' ); @@ -88,22 +92,12 @@ public function requestReset( array $parameters ): string } // Get email - $email = $_POST['email'] ?? ''; + $email = $request->post( 'email', '' ); // Validate input - if( empty( $email ) ) + if( empty( $email ) || !filter_var( $email, FILTER_VALIDATE_EMAIL ) ) { - $this->_sessionManager->flash( 'error', 'Please enter your email address.' ); - header( 'Location: /forgot-password' ); - exit; - } - - // Validate email format - if( !filter_var( $email, FILTER_VALIDATE_EMAIL ) ) - { - $this->_sessionManager->flash( 'error', 'Please enter a valid email address.' ); - header( 'Location: /forgot-password' ); - exit; + $this->redirect( 'admin_posts', [], ['error', 'Please enter a valid email address.'] ); } try @@ -133,13 +127,15 @@ public function requestReset( array $parameters ): string /** * Show reset password form (with token) - * @param array $parameters + * + * @param Request $request * @return string + * @throws NotFound */ - public function showResetForm( array $parameters ): string + public function showResetForm( Request $request ): string { // Get token from query string - $token = $this->filterGet( 'token', '' ); + $token = $request->get( 'token', '' ); if( empty( $token ) ) { @@ -181,39 +177,33 @@ public function showResetForm( array $parameters ): string /** * Process password reset - * @param array $parameters + * @param Request $request * @return string */ - public function resetPassword( array $parameters ): string + public function resetPassword( Request $request ): string { // Validate CSRF token - $csrfToken = $_POST['csrf_token'] ?? ''; + $csrfToken = $request->post( 'csrf_token', '' ); if( !$this->_csrfManager->validate( $csrfToken ) ) { - $this->_sessionManager->flash( 'error', 'Invalid CSRF token. Please try again.' ); - header( 'Location: /forgot-password' ); - exit; + $this->redirect( 'admin_posts', [], ['error', 'Invalid CSRF token.'] ); } // Get form data - $token = $_POST['token'] ?? ''; - $password = $_POST['password'] ?? ''; - $passwordConfirmation = $_POST['password_confirmation'] ?? ''; + $token = $request->post( 'token', '' ); + $password = $request->post( 'password', '' ); + $passwordConfirmation = $request->post( 'password_confirmation', '' ); // Validate input if( empty( $token ) || empty( $password ) || empty( $passwordConfirmation ) ) { - $this->_sessionManager->flash( 'error', 'All fields are required.' ); - header( 'Location: /reset-password?token=' . urlencode( $token ) ); - exit; + $this->redirectToUrl( '/reset-password?token=' . urlencode( $token ), ['error', 'All fields are required.'] ); } // Validate passwords match if( $password !== $passwordConfirmation ) { - $this->_sessionManager->flash( 'error', 'Passwords do not match.' ); - header( 'Location: /reset-password?token=' . urlencode( $token ) ); - exit; + $this->redirectToUrl( '/reset-password?token=' . urlencode( $token ), ['error', 'Passwords do not match.'] ); } try @@ -223,22 +213,15 @@ public function resetPassword( array $parameters ): string if( !$success ) { - $this->_sessionManager->flash( 'error', 'This password reset link is invalid or has expired.' ); - header( 'Location: /forgot-password' ); - exit; + $this->redirect( 'forgot_password', [], ['error', 'This password reset link is invalid or has expired.'] ); } // Success - $this->_sessionManager->flash( 'success', 'Your password has been reset successfully. You can now log in.' ); - header( 'Location: /login' ); - exit; + $this->redirect( 'login', [], ['success', 'Your password has been reset successfully. You can now log in.'] ); } catch( Exception $e ) { - // Show validation or other errors - $this->_sessionManager->flash( 'error', $e->getMessage() ); - header( 'Location: /reset-password?token=' . urlencode( $token ) ); - exit; + $this->redirectToUrl( '/reset-password?token=' . urlencode( $token ), ['error', $e->getMessage() ] ); } } } diff --git a/src/Cms/Controllers/Blog.php b/src/Cms/Controllers/Blog.php index 8260da3..749b10e 100644 --- a/src/Cms/Controllers/Blog.php +++ b/src/Cms/Controllers/Blog.php @@ -1,26 +1,22 @@ _postRepository = new DatabasePostRepository( $settings ); $this->_categoryRepository = new DatabaseCategoryRepository( $settings ); $this->_tagRepository = new DatabaseTagRepository( $settings ); - - // Check for drafts parameter - $get = new Get(); - $this->_showDrafts = $get->filterScalar( 'drafts' ) ? true : false; } /** - * @param array $parameters - * @param Request|null $request + * Blog homepage - list of published posts + * + * @param Request $request * @return string - * @throws \Neuron\Core\Exceptions\NotFound + * @throws NotFound */ - public function index( array $parameters, ?Request $request ): string + public function index( Request $request ): string { - // Get published posts (or all if drafts mode) - if( $this->_showDrafts ) - { - $posts = $this->_postRepository->all(); - } - else - { - $posts = $this->_postRepository->getPublished(); - } + $posts = $this->_postRepository->getPublished(); $categories = $this->_categoryRepository->all(); $tags = $this->_tagRepository->all(); @@ -68,7 +53,7 @@ public function index( array $parameters, ?Request $request ): string HttpResponseStatus::OK, [ 'Posts' => $posts, - 'Categories' => $categories, + 'Categories' => $categories, 'Tags' => $tags, 'Title' => $this->getName() . ' | ' . $this->getTitle(), 'Name' => $this->getName(), @@ -79,17 +64,18 @@ public function index( array $parameters, ?Request $request ): string } /** - * @param array $parameters - * @param Request|null $request + * Blog article detail view + * + * @param Request $request * @return string - * @throws \Neuron\Core\Exceptions\NotFound + * @throws NotFound */ - public function show( array $parameters, ?Request $request ): string + public function show( Request $request ): string { - $slug = $parameters['slug'] ?? ''; + $slug = $request->getRouteParameter( 'slug', '' ); $post = $this->_postRepository->findBySlug( $slug ); - if( !$post || ( !$post->isPublished() && !$this->_showDrafts ) ) + if( !$post ) { $post = new Post(); $post->setTitle( 'Article Not Found' ); @@ -121,12 +107,13 @@ public function show( array $parameters, ?Request $request ): string } /** - * @param array $parameters - * @param Request|null $request + * Blog posts by author + * + * @param Request $request * @return string - * @throws \Neuron\Core\Exceptions\NotFound + * @throws NotFound */ - public function author( array $parameters, ?Request $request ): string + public function author( Request $request ): string { $authorName = $parameters['author'] ?? ''; @@ -152,14 +139,15 @@ public function author( array $parameters, ?Request $request ): string /** - * @param array $parameters + * Blog posts by tag + * * @param Request|null $request * @return string - * @throws \Neuron\Core\Exceptions\NotFound + * @throws NotFound */ - public function tag( array $parameters, ?Request $request ): string + public function tag( Request $request ): string { - $tagSlug = $parameters['tag'] ?? ''; + $tagSlug = $request->getRouteParameter( 'tag', '' ); $tag = $this->_tagRepository->findBySlug( $tagSlug ); if( !$tag ) @@ -169,7 +157,7 @@ public function tag( array $parameters, ?Request $request ): string } else { - $status = $this->_showDrafts ? null : Post::STATUS_PUBLISHED; + $status = Post::STATUS_PUBLISHED; $posts = $this->_postRepository->getByTag( $tag->getId(), $status ); $tagName = $tag->getName(); } @@ -191,14 +179,15 @@ public function tag( array $parameters, ?Request $request ): string } /** - * @param array $parameters - * @param Request|null $request + * Blog posts by category + * + * @param Request $request * @return string - * @throws \Neuron\Core\Exceptions\NotFound + * @throws NotFound */ - public function category( array $parameters, ?Request $request ): string + public function category( Request $request ): string { - $categorySlug = $parameters['category'] ?? ''; + $categorySlug = $request->getRouteParameter( 'category', '' ); $category = $this->_categoryRepository->findBySlug( $categorySlug ); if( !$category ) @@ -208,7 +197,7 @@ public function category( array $parameters, ?Request $request ): string } else { - $status = $this->_showDrafts ? null : Post::STATUS_PUBLISHED; + $status = Post::STATUS_PUBLISHED; $posts = $this->_postRepository->getByCategory( $category->getId(), $status ); $categoryName = $category->getName(); } @@ -232,11 +221,11 @@ public function category( array $parameters, ?Request $request ): string /** * Generate RSS feed * - * @param array $parameters - * @param Request|null $request + * @param Request $request * @return string */ - public function feed( array $parameters, ?Request $request ): string + #[NoReturn] + public function feed( Request $request ): string { $posts = $this->_postRepository->getPublished( 20 ); diff --git a/src/Cms/Controllers/Content.php b/src/Cms/Controllers/Content.php index c857394..1a04ade 100644 --- a/src/Cms/Controllers/Content.php +++ b/src/Cms/Controllers/Content.php @@ -47,10 +47,13 @@ * ``` */ +use League\CommonMark\Exception\CommonMarkException; use Neuron\Cms\Auth\SessionManager; +use Neuron\Core\Exceptions\NotFound; use Neuron\Data\Object\Version; use Neuron\Mvc\Application; use Neuron\Mvc\Controllers\Base; +use Neuron\Mvc\Requests\Request; use Neuron\Mvc\Responses\HttpResponseStatus; use Neuron\Patterns\Registry; @@ -64,7 +67,7 @@ class Content extends Base protected ?SessionManager $_sessionManager = null; /** - * @param Application $app + * @param Application|null $app */ public function __construct( ?Application $app = null ) { @@ -189,24 +192,24 @@ public function setUrl( string $url ): Content } /** - * @throws \Neuron\Core\Exceptions\NotFound - * @throws \League\CommonMark\Exception\CommonMarkException + * Render a markdown page. + * + * @param Request $request + * @throws NotFound + * @throws CommonMarkException */ - public function markdown( array $parameters ): string + public function markdown( Request $request ): string { $viewData = array(); - $title = $parameters[ 'page' ]; - - $title = str_replace( '-', ' ', $title ); - $title = ucwords( $title ); + $page = $request->getRouteParameter( 'page' ); $viewData[ 'Title' ] = $this->getName() . ' | ' . $this->getTitle(); return $this->renderMarkdown( HttpResponseStatus::OK, $viewData, - $parameters[ 'page' ] + $page ); } @@ -241,6 +244,7 @@ protected function redirect( string $routeName, array $parameters = [], ?array $ [ $type, $message ] = $flash; $this->getSessionManager()->flash( $type, $message ); } + $url = $this->urlFor( $routeName, $parameters ) ?? '/'; header( 'Location: ' . $url ); exit; @@ -260,6 +264,7 @@ protected function redirectToUrl( string $url, ?array $flash = null ): never [ $type, $message ] = $flash; $this->getSessionManager()->flash( $type, $message ); } + header( 'Location: ' . $url ); exit; } diff --git a/src/Cms/Controllers/Home.php b/src/Cms/Controllers/Home.php index ff81f00..b9e58ec 100644 --- a/src/Cms/Controllers/Home.php +++ b/src/Cms/Controllers/Home.php @@ -1,8 +1,10 @@ get( 'RegistrationService' ); + $registrationService = Registry::getInstance()->get( 'RegistrationService' ); if( $registrationService && method_exists( $registrationService, 'isRegistrationEnabled' ) ) { diff --git a/src/Cms/Controllers/Member/Dashboard.php b/src/Cms/Controllers/Member/Dashboard.php index f8fc433..1160efb 100644 --- a/src/Cms/Controllers/Member/Dashboard.php +++ b/src/Cms/Controllers/Member/Dashboard.php @@ -4,7 +4,9 @@ use Neuron\Cms\Controllers\Content; use Neuron\Cms\Auth\CsrfTokenManager; +use Neuron\Core\Exceptions\NotFound; use Neuron\Mvc\Application; +use Neuron\Mvc\Requests\Request; use Neuron\Mvc\Responses\HttpResponseStatus; use Neuron\Patterns\Registry; @@ -27,10 +29,12 @@ public function __construct( ?Application $app = null ) /** * Show member dashboard - * @param array $parameters + * + * @param Request $request * @return string + * @throws NotFound */ - public function index( array $parameters ): string + public function index( Request $request ): string { // Get authenticated user from Registry $user = Registry::getInstance()->get( 'Auth.User' ); diff --git a/src/Cms/Controllers/Member/Profile.php b/src/Cms/Controllers/Member/Profile.php index 775307c..8d5add3 100644 --- a/src/Cms/Controllers/Member/Profile.php +++ b/src/Cms/Controllers/Member/Profile.php @@ -8,6 +8,7 @@ use Neuron\Cms\Auth\PasswordHasher; use Neuron\Cms\Auth\CsrfTokenManager; use Neuron\Mvc\Application; +use Neuron\Mvc\Requests\Request; use Neuron\Mvc\Responses\HttpResponseStatus; use Neuron\Patterns\Registry; @@ -41,11 +42,12 @@ public function __construct( ?Application $app = null ) /** * Show profile edit form - * @param array $parameters + * + * @param Request $request * @return string * @throws \Exception */ - public function edit( array $parameters ): string + public function edit( Request $request ): string { $user = Registry::getInstance()->get( 'Auth.User' ); @@ -80,11 +82,12 @@ public function edit( array $parameters ): string /** * Update profile - * @param array $parameters + * + * @param Request $request * @return never * @throws \Exception */ - public function update( array $parameters ): never + public function update( Request $request ): never { $user = Registry::getInstance()->get( 'Auth.User' ); @@ -93,11 +96,11 @@ public function update( array $parameters ): never throw new \RuntimeException( 'Authenticated user not found' ); } - $email = $_POST['email'] ?? ''; - $timezone = $_POST['timezone'] ?? ''; - $currentPassword = $_POST['current_password'] ?? ''; - $newPassword = $_POST['new_password'] ?? ''; - $confirmPassword = $_POST['confirm_password'] ?? ''; + $email = $request->post( 'email', '' ); + $timezone = $request->post( 'timezone', '' ); + $currentPassword = $request->post( 'current_password', '' ); + $newPassword = $request->post( 'new_password', '' ); + $confirmPassword = $request->post( 'confirm_password', '' ); // Validate password change if requested if( !empty( $newPassword ) ) diff --git a/src/Cms/Controllers/Member/Registration.php b/src/Cms/Controllers/Member/Registration.php index 632c83a..84a0840 100644 --- a/src/Cms/Controllers/Member/Registration.php +++ b/src/Cms/Controllers/Member/Registration.php @@ -7,9 +7,9 @@ use Neuron\Cms\Auth\EmailVerificationManager; use Neuron\Cms\Auth\ResendVerificationThrottle; use Neuron\Cms\Services\Member\RegistrationService; -use Neuron\Data\Filter\Get; -use Neuron\Data\Filter\Post; +use Neuron\Core\Exceptions\NotFound; use Neuron\Mvc\Application; +use Neuron\Mvc\Requests\Request; use Neuron\Mvc\Responses\HttpResponseStatus; use Neuron\Patterns\Registry; use Neuron\Routing\DefaultIpResolver; @@ -59,11 +59,12 @@ public function __construct( ?Application $app = null ) } /** - * Show registration form - * @param array $parameters + * Show the registration form + * + * @param Request $request * @return string */ - public function showRegistrationForm( array $parameters ): string + public function showRegistrationForm( Request $request ): string { // Check if registration is enabled if( !$this->_registrationService->isRegistrationEnabled() ) @@ -101,15 +102,13 @@ public function showRegistrationForm( array $parameters ): string /** * Process registration - * @param array $parameters + * @param Request $request * @return never */ - public function processRegistration( array $parameters ): never + public function processRegistration( Request $request ): never { - $post = new Post(); - // Validate CSRF token - $token = $post->filterScalar( 'csrf_token' ); + $token = $request->post( 'csrf_token' ); if( !$this->_csrfManager->validate( $token ) ) { @@ -117,10 +116,10 @@ public function processRegistration( array $parameters ): never } // Get form data - $username = $post->filterScalar( 'username' ) ?? ''; - $email = $post->filterScalar( 'email' ) ?? ''; - $password = $post->filterScalar( 'password' ) ?? ''; - $passwordConfirmation = $post->filterScalar( 'password_confirmation' ) ?? ''; + $username = $request->post( 'username' ) ?? ''; + $email = $request->post( 'email' ) ?? ''; + $password = $request->post( 'password' ) ?? ''; + $passwordConfirmation = $request->post( 'password_confirmation' ) ?? ''; try { @@ -156,10 +155,12 @@ public function processRegistration( array $parameters ): never /** * Show verification email sent page - * @param array $parameters + * + * @param Request $request * @return string + * @throws NotFound */ - public function showVerificationSent( array $parameters ): string + public function showVerificationSent( Request $request ): string { $viewData = [ 'Title' => 'Verify Your Email | ' . $this->getName(), @@ -177,15 +178,15 @@ public function showVerificationSent( array $parameters ): string /** * Verify email address - * @param array $parameters + * + * @param Request $request * @return string + * @throws NotFound */ - public function verify( array $parameters ): string + public function verify( Request $request ): string { - $get = new Get(); - // Get token from query string - $token = $get->filterScalar( 'token' ) ?? ''; + $token = $request->get( 'token' ) ?? ''; if( empty( $token ) ) { @@ -262,15 +263,14 @@ public function verify( array $parameters ): string /** * Resend verification email - * @param array $parameters + * + * @param Request $request * @return never */ - public function resendVerification( array $parameters ): never + public function resendVerification( Request $request ): never { - $post = new Post(); - // Validate CSRF token - $token = $post->filterScalar( 'csrf_token' ); + $token = $request->post( 'csrf_token' ); if( !$this->_csrfManager->validate( $token ) ) { @@ -278,7 +278,7 @@ public function resendVerification( array $parameters ): never } // Get email and client IP - $email = $post->filterScalar( 'email' ) ?? ''; + $email = $request->post( 'email' ) ?? ''; $clientIp = $this->_ipResolver->resolve( $_SERVER ); if( empty( $email ) ) diff --git a/tests/Cms/BlogControllerTest.php b/tests/Cms/BlogControllerTest.php index b5f8f28..ff1d295 100644 --- a/tests/Cms/BlogControllerTest.php +++ b/tests/Cms/BlogControllerTest.php @@ -267,7 +267,7 @@ public function testIndexReturnsPublishedPosts(): void $this->createTestPost( 'Draft Post', 'draft-1', Post::STATUS_DRAFT ); $blog = $this->createBlogWithInjectedRepositories(); - $result = $blog->index( [], null ); + $result = $blog->index( new Request() ); $this->assertIsString( $result ); // Should contain published posts but not drafts @@ -278,7 +278,9 @@ public function testShowWithValidSlug(): void $post = $this->createTestPost( 'Test Article', 'test-article', Post::STATUS_PUBLISHED ); $blog = $this->createBlogWithInjectedRepositories(); - $result = $blog->show( [ 'title' => 'test-article' ], null ); + $request = new Request(); + $request->setRouteParameters( [ 'slug' => 'test-article' ] ); + $result = $blog->show( $request ); $this->assertIsString( $result ); } @@ -286,7 +288,9 @@ public function testShowWithValidSlug(): void public function testShowWithNonexistentSlug(): void { $blog = $this->createBlogWithInjectedRepositories(); - $result = $blog->show( [ 'title' => 'nonexistent' ], null ); + $request = new Request(); + $request->setRouteParameters( [ 'slug' => 'nonexistent' ] ); + $result = $blog->show( $request, null ); $this->assertIsString( $result ); // Should handle gracefully @@ -303,7 +307,9 @@ public function testTagFiltersPostsByTag(): void $this->createTestPost( 'Other Post', 'other-post', Post::STATUS_PUBLISHED ); $blog = $this->createBlogWithInjectedRepositories(); - $result = $blog->tag( [ 'tag' => $tag->getSlug() ], null ); + $request = new Request(); + $request->setRouteParameters( [ 'tag' => $tag->getSlug() ] ); + $result = $blog->tag( $request ); $this->assertIsString( $result ); } @@ -319,7 +325,9 @@ public function testCategoryFiltersPostsByCategory(): void $this->createTestPost( 'Other Post', 'other-post', Post::STATUS_PUBLISHED ); $blog = $this->createBlogWithInjectedRepositories(); - $result = $blog->category( [ 'category' => $category->getSlug() ], null ); + $request = new Request(); + $request->setRouteParameters( [ 'category' => $category->getSlug() ] ); + $result = $blog->category( $request ); $this->assertIsString( $result ); } @@ -347,20 +355,4 @@ public function testBlogExtendsContentController(): void $this->assertEquals( 'http://test.com', $blog->getUrl() ); $this->assertEquals( 'http://test.com/blog/rss', $blog->getRssUrl() ); } - - public function testRequestParameterIsOptional(): void - { - $this->createTestPost( 'Test Post', 'test-post', Post::STATUS_PUBLISHED ); - - $blog = $this->createBlogWithInjectedRepositories(); - - // Test all methods with null Request - $this->assertIsString( $blog->index( [], null ) ); - $this->assertIsString( $blog->show( [ 'title' => 'test-post' ], null ) ); - - // Test with actual Request object - $mockRequest = $this->createMock( Request::class ); - $this->assertIsString( $blog->index( [], $mockRequest ) ); - $this->assertIsString( $blog->show( [ 'title' => 'test-post' ], $mockRequest ) ); - } } diff --git a/tests/Cms/ContentControllerTest.php b/tests/Cms/ContentControllerTest.php index abf2fce..f5fe9a4 100644 --- a/tests/Cms/ContentControllerTest.php +++ b/tests/Cms/ContentControllerTest.php @@ -4,6 +4,7 @@ use Neuron\Cms\Controllers\Content; use Neuron\Data\Setting\Source\Memory; +use Neuron\Mvc\Requests\Request; use Neuron\Mvc\Responses\HttpResponseStatus; use Neuron\Patterns\Registry; use Neuron\Routing\Router; @@ -164,8 +165,9 @@ public function testMarkdownMethod() ) ->willReturn( 'Test Content' ); - $parameters = [ 'page' => 'test-page' ]; - $result = $controller->markdown( $parameters ); + $request = new Request(); + $request->setRouteParameters( [ 'page' => 'test-page' ] ); + $result = $controller->markdown( $request ); $this->assertEquals( 'Test Content', $result ); } From 44c8c19dfbe8359502d814895d0bb58f3aa0c44d Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Fri, 14 Nov 2025 09:19:00 -0600 Subject: [PATCH 2/2] Update tests/Cms/BlogControllerTest.php Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- tests/Cms/BlogControllerTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Cms/BlogControllerTest.php b/tests/Cms/BlogControllerTest.php index ff1d295..1839211 100644 --- a/tests/Cms/BlogControllerTest.php +++ b/tests/Cms/BlogControllerTest.php @@ -290,7 +290,7 @@ public function testShowWithNonexistentSlug(): void $blog = $this->createBlogWithInjectedRepositories(); $request = new Request(); $request->setRouteParameters( [ 'slug' => 'nonexistent' ] ); - $result = $blog->show( $request, null ); + $result = $blog->show( $request ); $this->assertIsString( $result ); // Should handle gracefully