skip to Main Content

I’m moving a project of mine into Slim Microframework, by using PHP-DI containerization.
I need to POST some JSON data to http://localhost/api/base (XAMPP) and get a confirmation (at least at the beginning).
This is my index.php:

<?php

use PsrHttpMessageResponseInterface as Response;
use PsrHttpMessageServerRequestInterface as Request;
use SlimFactoryAppFactory;
use SlimExceptionHttpMethodNotAllowedException;
use SlimExceptionHttpNotFoundException;
use SlimRoutingRouteContext;
use DIContainerBuilder;

// Set error reporting to display all errors
error_reporting(E_ALL);
ini_set('display_errors', 'On');

// Autoloading using Composer's autoload
require __DIR__ . '/../vendor/autoload.php';

// Include dependencies file
$container = require_once __DIR__ . '/../config/dependencies.php';

// Create Slim app
$app = AppFactory::create();

// Include routes
require __DIR__ . '/../src/routes.php';

$app->run();

This is routes.php:

<?php

use PsrHttpMessageResponseInterface as Response;
use PsrHttpMessageServerRequestInterface as Request;
use AppControllersHotelBaseController;

// Include dependencies file
$container = require_once __DIR__ . '/../config/dependencies.php';

// Define basic route
$app->get('/', function (Request $request, Response $response) {
    $response->getBody()->write('Hello, World!');
    return $response;
});


// Route for handling POST request to /api/base
$app->post('/api/base', function (Request $request, Response $response) use ($container) {
    // Get the HotelBaseController service from the container
    $hotelBaseController = $container->get('HotelBaseController');

    // Call the handlePostRequest method
    return $hotelBaseController->handlePostRequest($request, $response);
});


$app->get('/api/base/', function (Request $request, Response $response) {
    return $response->withStatus(301)->withHeader('Location', '/api/base');
});

This is the dependencies.php:

<?php

use DIContainerBuilder;
// use PsrHttpMessageResponseInterface as Response;
// use PsrHttpMessageServerRequestInterface as Request;

require __DIR__ . '/../vendor/autoload.php';

// Create ContainerBuilder instance
$containerBuilder = new ContainerBuilder();

// Set up your container configuration
$containerBuilder->addDefinitions([
    'HotelBaseController' => DIcreate(AppControllersHotelBaseController::class),
]);

// Build the container
return $containerBuilder->build();

And, finally, this is hotelBaseController.php:

<?php

namespace AppControllers;

use PsrHttpMessageResponseInterface as Response;
use PsrHttpMessageServerRequestInterface as Request;

class HotelBaseController {
    public function handlePostRequest(Request $request, Response $response) {
        // Get the JSON data from the request body
        $data = $request->getParsedBody();

        // You can access the individual fields from the JSON data
        $userId = $data['userId'] ?? '';
        $apiKey = $data['apiKey'] ?? '';
        $documentType = $data['document_type'] ?? '';
        $hotelId = $data['hotel_id'] ?? '';
        $hotelName = $data['name'] ?? '';

        $res = 'Who knows';
        
        return $res;
    }
}

?>

When sending any POST request, containing a simple JSON, I get the error:

<b>Fatal error</b>: Uncaught Error: Call to a member function get() on bool in C:xampphtdocssrcroutes.php:20
Stack trace:
#0 C:xampphtdocsvendorslimslimSlimHandlersStrategiesRequestResponse.php(38):
{closure}(Object(SlimHttpServerRequest), Object(SlimHttpResponse), Array)
#1 C:xampphtdocsvendorslimslimSlimRoutingRoute.php(358):
SlimHandlersStrategiesRequestResponse-&gt;__invoke(Object(Closure), Object(SlimHttpServerRequest),
Object(SlimHttpResponse), Array)
#2 C:xampphtdocsvendorslimslimSlimMiddlewareDispatcher.php(65):
SlimRoutingRoute-&gt;handle(Object(SlimHttpServerRequest))
#3 C:xampphtdocsvendorslimslimSlimMiddlewareDispatcher.php(65):
SlimMiddlewareDispatcher-&gt;handle(Object(SlimHttpServerRequest))
#4 C:xampphtdocsvendorslimslimSlimRoutingRoute.php(315):
SlimMiddlewareDispatcher-&gt;handle(Object(SlimHttpServerRequest))
#5 C:xampphtdocsvendorslimslimSlimRoutingRouteRunner.php(68):
SlimRoutingRoute-&gt;run(Object(SlimHttpServerRequest))
#6 C:xampphtdocsvendorslimslimSlimMiddlewareDispatcher.php(65):
SlimRoutingRouteRunner-&gt;handle(Object(SlimHttpServerRequest))
#7 C:xampphtdocsvendorslimslimSlimApp.php(199):
SlimMiddlewareDispatcher-&gt;handle(Object(SlimHttpServerRequest))
#8 C:xampphtdocsvendorslimslimSlimApp.php(183): SlimApp-&gt;handle(Object(SlimHttpServerRequest))
#9 C:xampphtdocspublicindex.php(50): SlimApp-&gt;run()
#10 {main}
thrown in <b>C:xampphtdocssrcroutes.php</b> on line <b>20</b><br />

I would like to understand where am I making a mistake.
Thanks

2

Answers


  1. The error message contains bool? You have $container = require_once? I know exactly what’s going on.

    See, require_once acts differently than require. Not just in the fact that it only requires the code once, but also for scripts that return a value.

    The first time you require it, you’ll get your value as expected.

    The second time however, you’ll only get false. That’s because since the file had already been loaded, it didn’t load it again.

    There’s no "global require_once return value cache" sadly.

    What you’ll have to do is require it only once, and propagate that variable instead of loading it another time.

    Login or Signup to reply.
  2. Vivick’s answer explains well what causes the error mentioned in question. But, it doesn’t explain how to setup Slim’s routes properly.

    First, in your dependencies.php file you are importing the composer’s autoloader that is already imported in index.php. You don’t need to import it again so you should remove the line require __DIR__ . '/../vendor/autoload.php'; from there.
    Another thing there is that I would recommend using fully qualified class name instead of unqualified alias for the controller definition.
    So your dependencies.php can look like this:

    <?php
    
    use DIContainerBuilder;
    
    // Create ContainerBuilder instance
    $containerBuilder = new ContainerBuilder();
    
    // Set up your container configuration
    $containerBuilder->addDefinitions([
        AppControllersHotelBaseController::class => DIcreate(),
    ]);
    
    // Build the container
    return $containerBuilder->build();
    

    I’ve took advantage of the fact that you can leave out the class name parameter in DIcreate() function call if it’s same as the name of definition.

    In your index.php you are not passing the container you’ve created to SlimFactoryAppFactory so your container is created but it’s not used by Slim. Pass your container to AppFactory before creating app instance like this:

    // Include dependencies file
    $container = require_once __DIR__ . '/../config/dependencies.php';
    AppFactory::setContainer($container);
    // Create Slim app
    $app = AppFactory::create();
    

    Now that the DI container is properly set up, you can use it in routes.php. When you define route as anonymous callback function the function is automatically bound to DI container, so you don’t need to pass it into function using use ($container).
    Your routes.php might look like this:

    <?php
    
    use PsrHttpMessageResponseInterface as Response;
    use PsrHttpMessageServerRequestInterface as Request;
    use AppControllersHotelBaseController;
    
    // Define basic route
    $app->get('/', function (Request $request, Response $response) {
        $response->getBody()->write('Hello, World!');
        return $response;
    });
    
    // Route for handling POST request to /api/base
    $app->post('/api/base', function (Request $request, Response $response) {
        // Get the HotelBaseController service from the container
        $hotelBaseController = $this->get(HotelBaseController::class);
    
        // Call the handlePostRequest method
        return $hotelBaseController->handlePostRequest($request, $response);
    });
    
    $app->get('/api/base/', function (Request $request, Response $response) {
        return $response->withStatus(301)->withHeader('Location', '/api/base');
    });
    

    What’s more, you can take advantage of Slim’s container resolution of routes to make it even more simple:

    <?php
    
    use PsrHttpMessageResponseInterface as Response;
    use PsrHttpMessageServerRequestInterface as Request;
    use AppControllersHotelBaseController;
    
    // Define basic route
    $app->get('/', function (Request $request, Response $response) {
        $response->getBody()->write('Hello, World!');
        return $response;
    });
    
    // Route for handling POST request to /api/base
    $app->post('/api/base', HotelBaseController::class . ':handlePostRequest');
    // Or alternative
    // $app->post('/api/base', [HotelBaseController::class, 'handlePostRequest']);
    
    $app->get('/api/base/', function (Request $request, Response $response) {
        return $response->withStatus(301)->withHeader('Location', '/api/base');
    });
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search