Skip to content
Rougin Gutib edited this page Nov 1, 2024 · 12 revisions

← What is Slytherin?

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.).

From v0.8.0 to v0.9.0

Transition to the official PSR-11 implementation

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);
 }

Change of DebuggerInterface to ErrorHandlerInterface

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();
 }

Transition to the official PSR-15 implementation

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.

Dispatching directory renamed to Routing

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;

Additional method for DispatcherInterface in 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);
 }

Changed and added methods in RouterInterface

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();
 }

From v0.7.0 to v0.8.0

No known backward compatibility issues found.

From v0.6.0 to v0.7.0

Upgrade version of filp/whoops

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.

From v0.5.0 to v0.6.0

No known backward compatibility issues found.

From v0.4.0 to v0.5.0

No known backward compatibility issues found.

From v0.3.0 to v0.4.0

Transition to PSR-07 (HTTP messages)

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);
// -----------------------------------------------------------------------------------

 // ...

Transition to PSR-11 (Containers)

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);
 }

Change from ErrorHandler to Debug

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

From v0.2.0 to v0.3.0

Migrating to a micro-framework package

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.

← What is Slytherin?

Clone this wiki locally