-
Notifications
You must be signed in to change notification settings - Fork 2
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
GitAuto: [FEATURE] Add MVC Capability to Pancake Toolkit #252
base: main
Are you sure you want to change the base?
Changes from all commits
31d33a3
50a487e
953436d
1cfd359
095fe21
9ad55ab
4a3357d
b3d3a50
e89c955
5df60ba
febfa9a
549a487
c5d27ff
451e4ec
45f59d7
9e33ba5
671d750
1bd5884
1b76325
3a9cd71
26da64a
7d2c19e
b54eac0
240c0b0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
# MVC Usage Guide | ||
|
||
This document provides an overview of how to use the new MVC components in the Pancake toolkit. | ||
|
||
## BaseController | ||
|
||
The `BaseController` class provides common functionality for rendering views and redirecting URLs. | ||
|
||
### Example | ||
|
||
```php | ||
use Pancake\MVC\BaseController; | ||
|
||
$templateEngine = new YourTemplateEngine(); | ||
$controller = new BaseController($templateEngine); | ||
|
||
$controller->render('home', ['key' => 'value']); | ||
$controller->redirect('http://example.com'); | ||
``` | ||
|
||
## ApiController | ||
|
||
The `ApiController` class extends `BaseController` and is designed for API responses, rendering JSON. | ||
|
||
### Example | ||
|
||
```php | ||
use Pancake\MVC\ApiController; | ||
|
||
$controller = new ApiController(null); | ||
$controller->render(['key' => 'value']); | ||
``` | ||
|
||
## Router | ||
|
||
The `Router` class manages route registration and dispatching. | ||
|
||
### Example | ||
Check warning Code scanning / Markdownlint (reported by Codacy) Multiple headings with the same content Warning documentation
Multiple headings with the same content
|
||
|
||
```php | ||
use Pancake\MVC\Router; | ||
|
||
$router = new Router(); | ||
$router->add('GET', '/home', 'HomeController', 'index'); | ||
$router->dispatch('GET', '/home'); | ||
``` | ||
|
||
## DIContainer Integration | ||
|
||
The `DIContainer` is used to manage dependencies for controllers and the template engine. | ||
|
||
### Example | ||
Check warning Code scanning / Markdownlint (reported by Codacy) Multiple headings with the same content Warning documentation
Multiple headings with the same content
|
||
|
||
```php | ||
$container = new Pancake\DIContainer(); | ||
$controller = $container->resolve('BaseController'); | ||
$controller->render('home', ['key' => 'value']); | ||
``` | ||
|
||
``` |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
<?php | ||
|
||
namespace Pancake; | ||
|
||
class DIContainer | ||
{ | ||
private $bindings = []; | ||
|
||
public function registerSingleton($name, $resolver) | ||
{ | ||
$this->bindings[$name] = ['resolver' => $resolver, 'shared' => true, 'instance' => null]; | ||
} | ||
|
||
public function registerTransient($name, $resolver) | ||
{ | ||
$this->bindings[$name] = ['resolver' => $resolver, 'shared' => false]; | ||
} | ||
|
||
public function resolve($name) | ||
{ | ||
if (!isset($this->bindings[$name])) { | ||
throw new \Exception("No binding registered for {$name}"); | ||
} | ||
|
||
$binding = $this->bindings[$name]; | ||
|
||
if ($binding['shared']) { | ||
if ($binding['instance'] === null) { | ||
$binding['instance'] = $binding['resolver'](); | ||
} | ||
return $binding['instance']; | ||
} | ||
|
||
return $binding['resolver'](); | ||
} | ||
} | ||
|
||
// Registering components | ||
$container = new DIContainer(); | ||
$container->registerSingleton('templateEngine', function () { | ||
return new DefaultTemplateEngine(); // Assume DefaultTemplateEngine is defined elsewhere | ||
}); | ||
$container->registerTransient('BaseController', function () use ($container) { | ||
return new MVC\BaseController($container->resolve('templateEngine')); | ||
}); | ||
$container->registerTransient('ApiController', function () use ($container) { | ||
return new MVC\ApiController($container->resolve('templateEngine')); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
<?php | ||
|
||
namespace Pancake\MVC; | ||
|
||
class ApiController extends BaseController | ||
{ | ||
public function render($data = []) | ||
{ | ||
header('Content-Type: application/json'); | ||
echo json_encode($data); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
<?php | ||
|
||
namespace Pancake\MVC; | ||
|
||
class BaseController | ||
{ | ||
protected $templateEngine; | ||
|
||
public function __construct($templateEngine) | ||
{ | ||
$this->templateEngine = $templateEngine; | ||
} | ||
|
||
public function render($view, $data = []) | ||
{ | ||
echo $this->templateEngine->render($view, $data); | ||
} | ||
|
||
public function redirect($url) | ||
{ | ||
header('Location: ' . $url); | ||
exit(); | ||
|
||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
<?php | ||
|
||
namespace Pancake\MVC; | ||
|
||
class Router | ||
{ | ||
private $routes = []; | ||
|
||
public function add($method, $uri, $controller, $action) | ||
{ | ||
$this->routes[] = compact('method', 'uri', 'controller', 'action'); | ||
} | ||
|
||
public function dispatch($method, $uri) | ||
{ | ||
foreach ($this->routes as $route) { | ||
if ($route['method'] === $method && $route['uri'] === $uri) { | ||
$controller = new $route['controller'](); | ||
$action = $route['action']; | ||
return $controller->$action(); | ||
} | ||
} | ||
// Handle 404 | ||
header("HTTP/1.0 404 Not Found"); | ||
echo "404 Not Found"; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
<?php | ||
|
||
namespace GuiBranco\Pancake\Tests\MVC; | ||
|
||
use PHPUnit\Framework\TestCase; | ||
use Pancake\MVC\ApiController; | ||
|
||
class ApiControllerTest extends TestCase | ||
{ | ||
public function testRenderJson() | ||
{ | ||
$controller = new ApiController(null); | ||
|
||
$this->expectOutputString('{"key":"value"}'); | ||
$controller->render(['key' => 'value']); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
<?php | ||
|
||
namespace GuiBranco\Pancake\Tests\MVC; | ||
|
||
use PHPUnit\Framework\TestCase; | ||
use Pancake\MVC\BaseController; | ||
|
||
class BaseControllerTest extends TestCase | ||
{ | ||
public function testRender() | ||
{ | ||
$templateEngine = $this->createMock(TemplateEngine::class); | ||
$templateEngine->expects($this->once()) | ||
->method('render') | ||
->with('view', ['key' => 'value']) | ||
->willReturn('rendered view'); | ||
|
||
$controller = new BaseController($templateEngine); | ||
$this->expectOutputString('rendered view'); | ||
$controller->render('view', ['key' => 'value']); | ||
} | ||
|
||
public function testRedirect() | ||
{ | ||
$controller = new BaseController(null); | ||
|
||
$this->expectException(\PHPUnit\Framework\Error\Warning::class); | ||
$this->expectExceptionMessage('Cannot modify header information'); | ||
|
||
$controller->redirect('http://example.com'); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
<?php | ||
|
||
namespace GuiBranco\Pancake\Tests\MVC; | ||
|
||
use PHPUnit\Framework\TestCase; | ||
use Pancake\MVC\Router; | ||
|
||
class RouterTest extends TestCase | ||
{ | ||
public function testAddAndDispatch() | ||
{ | ||
$router = new Router(); | ||
|
||
$mockController = $this->createMock(\stdClass::class); | ||
$mockController->expects($this->once()) | ||
->method('testAction') | ||
->willReturn('action executed'); | ||
|
||
$router->add('GET', '/test', get_class($mockController), 'testAction'); | ||
|
||
$this->expectOutputString('action executed'); | ||
$router->dispatch('GET', '/test'); | ||
} | ||
|
||
public function testDispatchNotFound() | ||
{ | ||
$router = new Router(); | ||
|
||
$this->expectOutputString('404 Not Found'); | ||
$router->dispatch('GET', '/non-existent'); | ||
} | ||
} |
Check warning
Code scanning / Markdownlint (reported by Codacy)
Multiple headings with the same content Warning documentation