-
Notifications
You must be signed in to change notification settings - Fork 4
Upgrade Guide
Below are the significant changes when upgrading from specified versions due to backward compatibility breaks:
Note
There should be no backward compatibility issues if using the public methods of Slytherin components that are documented starting from v0.3.0
. The following below should be considered if there are custom implementations that uses Slytherin's interfaces (e.g., ContainerInterface
, MiddlewareInterface
, etc.).
The Container
component has been reworked to support the official PSR-11 implementation (psr/container
). The ContainerInterface
was moved from IoC
to Container
directory. The add
method was also changed to set
to complement the get
method from the official ContainerInterface
:
-namespace Rougin\Slytherin\IoC;
+namespace Rougin\Slytherin\Container;
-use Interop\Container\ContainerInterface as InteropContainerInterface;
+use Psr\Container\ContainerInterface as PsrContainerInterface;
-interface ContainerInterface extends InteropContainerInterface
+interface ContainerInterface extends PsrContainerInterface
{
/**
- * @param string $id
- * @param mixed $concrete
+ * @param string $id
+ * @param mixed $concrete
+ * @return self
*/
- public function add($id, $concrete = null);
+ public function set($id, $concrete);
}
The DebuggerInterface
is renamed to ErrorHandlerInterface
for the Debug
component. Although there is no backward compatibility break in this change, the specified interface removes required methods and may not be used in Slytherin:
namespace Rougin\Slytherin\Debug;
-interface DebuggerInterface
+interface ErrorHandlerInterface
{
- /**
- * Sets up the environment to be used.
- *
- * @param string $environment
- * @return void
- */
- public function setEnvironment($environment);
-
- /**
- * Returns the specified environment.
- *
- * @return string
- */
- public function getEnvironment();
/**
* Registers the instance as a debugger.
*
* @return object
*/
public function display();
}
The Middleware
component has been reworked due to the transition to the official PSR-15 implementation (psr/http-server-middleware
). The MiddlewareInterface
has also been changed and it should be compatible with the various implementations of PSR-15:
namespace Rougin\Slytherin\Middleware;
-use Psr\Http\Message\ResponseInterface as Response;
-use Psr\Http\Message\ServerRequestInterface as Request;
+use Psr\Http\Message\ServerRequestInterface;
interface MiddlewareInterface
{
/**
- * @param \Psr\Http\Message\RequestInterface $request
- * @param \Psr\Http\Message\ResponseInterface $response
- * @param array $queue
- * @return \Psr\Http\Message\ResponseInterface|null
+ * @param \Psr\Http\Message\ServerRequestInterface $request
+ * @param \Rougin\Slytherin\Middleware\HandlerInterface $handler
+ * @return \Psr\Http\Message\ResponseInterface
*/
- public function __invoke(Request $request, Response $response, array $queue = []);
+ public function process(ServerRequestInterface $request, HandlerInterface $handler);
}
Note
Although the MiddlewareInterface
does not extend to the official MiddlewareInterface
, Slytherin automatically converts the currently installed PSR-15 middleware (http-interop/http-middleware
or psr/http-server-middleware
) to its Slytherin counterpart. With this, existing middlewares based from the mentioned implementations should not be affected.
The Dispatching
directory is now moved to its new name as Routing
. There should be no backward compatibility breaks in this change as the former directory is extended to the latter:
-namespace Rougin\Slytherin\Dispatching;
+namespace Rougin\Slytherin\Routing;
The DispatcherInterface
from the Routing
component has a new method named setRouter
. If using the specified interface, kindly implement the recent method:
-namespace Rougin\Slytherin\Dispatching;
+namespace Rougin\Slytherin\Routing;
/**
* Dispatcher Interface
*
* An interface for handling third-party route dispatchers.
*
* @package Slytherin
* @author Rougin Gutib <[email protected]>
*/
interface DispatcherInterface
{
/**
* Dispatches against the provided HTTP method verb and URI.
*
* @param string $method
* @param string $uri
- * @return array|string
+ * @return \Rougin\Slytherin\Routing\RouteInterface
*
* @throws \BadMethodCallException
*/
public function dispatch($method, $uri);
+ /**
+ * Sets the router and parse its available routes if needed.
+ *
+ * @param \Rougin\Slytherin\Routing\RouterInterface $router
+ * @return self
+ *
+ * @throws \UnexpectedValueException
+ */
+ public function setRouter(RouterInterface $router);
}
The methods for RouterInterface
has been changed and added additional methods for its usage in the Application
instance:
-namespace Rougin\Slytherin\Dispatching;
+namespace Rougin\Slytherin\Routing;
interface RouterInterface
{
/**
* Adds a new raw route.
*
- * @param string|string[] $httpMethod
- * @param string $route
- * @param mixed $handler
+ * @param string $method
+ * @param string $uri
+ * @param callable|string[]|string $handler
+ * @param \Rougin\Slytherin\Middleware\MiddlewareInterface[]|string[] $middlewares
+ * @return self
*/
- public function addRoute($httpMethod, $route, $handler);
+ public function add($method, $uri, $handler, $middlewares = array());
+ /**
+ * Merges a listing of parsed routes to current one.
+ *
+ * @param \Rougin\Slytherin\Routing\RouteInterface[] $routes
+ * @return self
+ */
+ public function merge(array $routes);
+
+ /**
+ * Returns a listing of parsed routes.
+ *
+ * @param \Rougin\Slytherin\Routing\RouteInterface[] $routes
+ * @return mixed|null
+ */
+ public function parsed(array $routes = array());
/**
* Returns a listing of available routes.
*
- * @return mixed
+ * @return \Rougin\Slytherin\Routing\RouteInterface[]
*/
- public function getRoutes();
+ public function routes();
}
No known backward compatibility issues found.
Although no backward compatibility issues found in Slytherin's code, one of the Slytherin's supported third-party packages, filp/whoops
, has an issue regarding PHP errors. With this, kindly change its version to ~2.0
in the composer.json
then perform composer update
after:
{
"require":
{
- "filp/whoops": "~1.0",
+ "filp/whoops": "~2.0",
}
}
See the Issue #341 from the filp/whoops
repository for reference.
No known backward compatibility issues found.
No known backward compatibility issues found.
The v0.4.0
version requires a PSR-07 compliant package for the Http
component. See the v0.4.0
in Additional Notes (Erratum) for updating the composer.json
.
With the transition to PSR-07, kindly update the following classes from index.php
:
use Rougin\Slytherin\Application;
use Rougin\Slytherin\ComponentCollection;
use Rougin\Slytherin\Dispatching\Dispatcher;
use Rougin\Slytherin\ErrorHandler\Whoops;
-use Rougin\Slytherin\Http\Request;
-use Rougin\Slytherin\Http\Response;
use Rougin\Slytherin\IoC\Auryn;
use Rougin\Slytherin\Template\RendererInterface;
use Rougin\Slytherin\Template\Twig;
+use Zend\Diactoros\Response;
+use Zend\Diactoros\ServerRequestFactory;
// ...
// Initialize the RequestInterface and ResponseInterface -----------------------------
-$stream = file_get_contents('php://input');
-$request = new \Http\HttpRequest($_GET, $_POST, $_COOKIE, $_FILES, $_SERVER, $stream);
-$request = new Request($request);
-$response = new Response(new \Http\HttpResponse);
+$request = ServerRequestFactory::fromGlobals();
+$response = new Response;
$component->setHttp($request, $response);
// -----------------------------------------------------------------------------------
// ...
This version also introduced support for a PSR-11 compliant package for the Container
component. With this, the DependencyInjectorInterface
has been deprecated and was replaced by ContainerInterface
which extends to the container-interop
package but added a new method:
namespace Rougin\Slytherin\IoC;
+use Interop\Container\ContainerInterface as InteropContainerInterface;
+
-interface DependencyInjectorInterface
+interface ContainerInterface extends InteropContainerInterface
{
/**
- * Instantiates/provisions a class instance.
- *
- * @param string $name
- * @param array $args
- * @return mixed
+ * Adds a new instance to the container.
+ *
+ * @param string $id
+ * @param mixed $concrete
*/
- public function make($name, array $args = array());
+ public function add($id, $concrete = null);
}
The ErrorHandlerInterface
has been moved from the ErrorHandler
directory to the Debug
directory and renamed as DebuggerInterface
. No backward compatibility break should occur as the latter interface extends to the former:
-namespace Rougin\Slytherin\ErrorHandler;
+namespace Rougin\Slytherin\Debug;
/**
- * Error Handler Interface
+ * Debugger Interface
*
- * An interface for handling third party error handlers
+ * An interface for handling third party debuggers.
*
* @package Slytherin
* @author Rougin Royce Gutib <[email protected]>
*/
-interface ErrorHandlerInterface
+interface DebuggerInterface
Due to transition from an application project to a micro-framework package, the following updates must be performed:
Update the following details in composer.json
:
{
"require":
{
- "rougin/slytherin": "~0.2.0"
+ "filp/whoops": "~2.0",
+ "nikic/fast-route": "~1.0",
+ "patricklouys/http": "~1.0",
+ "rdlowrey/auryn": "~1.0",
+ "rougin/slytherin": "~0.3.0",
+ "twig/twig": "~1.0"
},
"autoload":
{
"psr-4":
{
- "Controllers\\": "app/controllers",
- "Libraries\\": "app/libraries",
- "Models\\": "app/models"
+ "Rougin\\Nostalgia\\": "src"
}
- },
- "scripts":
- {
- "post-update-cmd":
- [
- "Rougin\\Slytherin\\Installer::deploy"
- ]
}
}
Note
Rougin\\Nostalgia\\
is only an example for the namespace. The src
directory should have its own namespace for easy importing of its classes.
Then execute composer update
to update the packages:
$ composer update
After updating the packages, copy the index.php
to app/web
directory:
+app/
+├─ web/
+│ ├─ index.php
-index.php
Then copy the following code below to the said index.php
:
use Rougin\Slytherin\Application;
use Rougin\Slytherin\ComponentCollection;
use Rougin\Slytherin\Dispatching\Dispatcher;
use Rougin\Slytherin\ErrorHandler\Whoops;
use Rougin\Slytherin\Http\Request;
use Rougin\Slytherin\Http\Response;
use Rougin\Slytherin\IoC\Auryn;
use Rougin\Slytherin\Template\RendererInterface;
use Rougin\Slytherin\Template\Twig;
$root = dirname(dirname(__DIR__));
require $root . '/vendor/autoload.php';
$component = new ComponentCollection;
// Initialize the RendererInterface -------------
$views = (string) realpath($root . '/app/views');
$loader = new Twig_Loader_Filesystem($views);
$twig = new Twig(new Twig_Environment($loader));
$renderer = RendererInterface::class;
// ----------------------------------------------
// Initialize the DependencyInjectorInterface ---
$auryn = new Auryn(new \Auryn\Injector);
// Create an alias for the RendererInterface ---
$auryn->share($twig);
$auryn->alias($renderer, get_class($twig));
// ---------------------------------------------
$component->setDependencyInjector($auryn);
// ----------------------------------------------
// Initialize the ErrorHandlerInterface ---
$whoops = new Whoops(new \Whoops\Run);
$component->setErrorHandler($whoops);
// ----------------------------------------
// Initialize the RequestInterface and ResponseInterface -----------------------------
$stream = file_get_contents('php://input');
$request = new \Http\HttpRequest($_GET, $_POST, $_COOKIE, $_FILES, $_SERVER, $stream);
$request = new Request($request);
$response = new Response(new \Http\HttpResponse);
$component->setHttp($request, $response);
// -----------------------------------------------------------------------------------
// Initialize the routing dispatcher interface ---
$router = require "$root/app/config/routes.php";
$dispatcher = new Dispatcher($router, $response);
$component->setDispatcher($dispatcher);
// -----------------------------------------------
// Initialize then run the Application ---
$app = new Application($component);
$app->run();
// ---------------------------------------
From the app/config/routes.php
file, change the syntax with the following below:
use Rougin\Slytherin\Dispatching\Router;
$name = 'Rougin\Nostalgia\Routes';
$router = new Router;
$router->addRoute('GET', '/', [ "$name\Welcome", 'index' ]);
$router->addRoute('GET', '/users', [ "$name\Users", 'index' ]);
return $router;
Create a src
directory then copy controllers
, libraries
, and models
to src/Routes
, src/Packages
, and src/Models
respectively:
app/
-├─ controllers/
-├─ packages/
-├─ models/
+src/
+├─ Models/
+├─ Packages/
+├─ Routes/
Once copied, remove the extends Controller
in each of the files in the src/Routes
directory. If the route uses View
, replace it with RendererInterface
:
-namespace Controllers;
+namespace Rougin\Nostalgia\Routes;
-use Rougin\Slytherin\Controller;
-use Rougin\Slytherin\View;
+use Rougin\Slytherin\Template\RendererInterface;
-class Welcome extends Controller
+class Welcome
{
+ protected $renderer;
+
+ public function __construct(RendererInterface $renderer)
+ {
+ $this->renderer = $renderer;
+ }
+
public function index()
{
- return View::render('welcome/index');
+ return $this->renderer->render('welcome/index');
}
}
If using the View
class for handling templates, rename the files in the view
directory with .html
:
app/
├─ views/
│ ├─ users/
+│ │ ├─ index.html
-│ │ ├─ index.php
│ ├─ welcome/
+│ │ ├─ index.html
-│ │ ├─ index.php
If using the Model
class for handling database results, replace it with the implementation of PDO
:
-namespace Models;
+namespace Rougin\Nostalgia\Models;
-use Rougin\Slytherin\Model;
-
-class User extends Model
+class User
{
+ protected $pdo;
+
+ public function __construct()
{
+ $items = require __DIR__ . '/../../app/config/databases.php';
+
+ $data = $items['default'];
+
+ $dsn = "{$data['driver']}:host={$data['hostname']};dbname={$data['database']}";
+
+ $pdo = new \PDO($dsn, $data['username'], $data['password']);
+ $pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
+
+ $this->pdo = $pdo;
+ }
+
public function get($page = 1, $limit = 10)
{
- $pdo = $this->databaseHandle;
-
$query = 'SELECT * FROM users';
$offset = ($page - 1) * $limit;
$query .= " LIMIT $limit OFFSET $offset";
- $st = $pdo->prepare($query);
+ $st = $this->pdo->prepare($query);
$st->execute();
Tip
Use a third-party PDO
implementation for improving code maintainability and readability.