I am trying to get my slim application to work, but I get this error:
( ! ) Fatal error: Uncaught RuntimeException: Callable Quiz\Controller\QuizController::index() does not exist in /var/www/html/vendor/slim/slim/Slim/CallableResolver.php on line 138
( ! ) RuntimeException: Callable Quiz\Controller\QuizController::index() does not exist in /var/www/html/vendor/slim/slim/Slim/CallableResolver.php on line 138
I'm using PHP 8.1 and Slim 4.11
Project structure:
My autoload config:
"autoload": {
"psr-4": {"Quiz\\": "source/"}
}
Method which should be called:
<?php
declare(strict_types=1);
namespace Quiz\Trivia\Controller;
use Psr\Container\ContainerInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Slim\Http\Response;
final class QuizController
{
private $container;
public function __construct(ContainerInterface $container)
{
$this->container = $container;
}
public function index(ServerRequestInterface $request, Response $response, array $args): ResponseInterface
{
return $this->container->get('views')->render(
$response,
'index.twig'
);
}
}
I define the route in routes.php as follows:
<?php
declare(strict_types=1);
use Quiz\Trivia\Controller\QuizController;
return [
'index' => [
'type' => 'get',
'path' => '/',
'class' => QuizController::class . ':index'
]
];
Later, I add the route in index.php with $app->map(...) to the slim app.
I already tried some solutions from older posts, but nothing worked so far. So I think I'm missing something crucial.
Thanks in Advance!
This is because your autoload config is set to "Quiz\": "source/ so it expects to find all classes belonging to the Quiz namespace in that folder, when in fact the controller you're trying to use is not located there.
You should move the trivia folder inside your source directory (with a capital T to respect conventions) or update the map to include the trivia namespacing and it's directory.
"Quiz\": "source/
"Quiz\\Trivia\": "trivia/"
(the double-backslash \\ is intentional.)
Related
I want to use dependency injection to pass an instance of Plates to my controllers with PHP-DI that is integrated with my routing system Simple Router.
I've tried to inject an instance of Plates, but I get this error:
<?php
namespace Controllers;
use \League\Plates\Engine;
use \League\Plates\Template\Template;
use \League\Plates\Extension\Asset;
class Controller {
public function __construct(\League\Plates\Engine $templates)
{
$this->templates = $templates;
}
?>
Uncaught LogicException: The template name "home" is not valid. The default directory has not been defined
How I can solve this issue? I need also to pass the assets path with the asset() method. Any help will be appreciated.
UPDATE
Thanks to the help of jcHache I've managed the injection of a Plates instance inside my base controller with this DI code:
<?php
// config.php
return [
League\Plates\Engine::class => DI\create()
->constructor(TEMPLATE_ROOT)
->method('loadExtension', DI\get('League\Plates\Extension\Asset')),
League\Plates\Extension\Asset::class => DI\create()
->constructor(APP_ROOT),
];
index.php file
<?php
use Pecee\SimpleRouter\SimpleRouter;
use DI\ContainerBuilder;
$container = (new \DI\ContainerBuilder())
->useAutowiring(true)
->addDefinitions('config.php')
->build();
SimpleRouter::enableDependencyInjection($container);
This is great but I'm facing a problem and I can't find a fix for it.
I get this error that is relative to the assets loader of plates, it seems that it's instantiated more than once. I've extended my controllers with my base controller where the asset loader is instantiated, but I don't think is this the problem? Is there a fix?
Uncaught Pecee\SimpleRouter\Exceptions\NotFoundHttpException: The template function name "asset" is already registered
Plates engine factory require a view folder parameter (see Plates doc):
so you have to add this creation in your PHP-DI configuration file:
For Plates V4:
// config.php
return [
// ...
\League\Plates\Engine::class => function(){
return League\Plates\Engine::create('/path/to/templates', 'phtml');
},
];
For Plates V3, I'll try:
// config.php
return [
// ...
\League\Plates\Engine::class => function(){
return new League\Plates\Engine('/path/to/templates');
},
];
or
// config.php
return [
// ...
\League\Plates\Engine::class => DI\create()
->constructor('/path/to/templates')
,
];
Design Note:
Personally, I won't use dependency injection for a template engine, I think it would be better to instantiate Plates engine in a base controller class.
namespace controllers;
use League\Plates\Engine;
abstract class BaseController
{
/**
* #var \League\Plates\Engine
*/
protected $templates;
public function __construct()
{
$this->templates=new Engine(\TEMPLATE_ROOT);
$this->templates->loadExtension(new \League\Plates\Extension\Asset(\APP_ROOT));
}
protected function renderView(string $viewname, array $variables=[])
{
return $this->templates->render($viewname,$variables);
}
}
For a child controller using Plates:
namespace controllers;
class MyController extends BaseController
{
public function index()
{
return $this->renderView('home');
}
}
I registering a controller with the container, but it seems not working because it doesn't match to the correct location.
\slim\src\routes.php
<?php
// Routes
$app->get('/dd', 'App\controllers\HomeController:home');
\slim\App\controllers\HomeController.php
<?php
class HomeController
{
protected $container;
// constructor receives container instance
public function __construct(ContainerInterface $container) {
$this->container = $container;
}
public function home($request, $response, $args) {
// your code
// to access items in the container... $this->container->get('');
return $response;
}
public function contact($request, $response, $args) {
// your code
// to access items in the container... $this->container->get('');
return $response;
}
}
My project folder structure:
\slim
\public
index.php
.htaccess
\App
\controllers
HomeController.php
\src
dependencies.php
middleware.php
routes.php
settings.php
\templates
index.phtml
\vendor
\slim
Maybe I should to setting \slim\src\settings.php?
Because it show Slim Application Error:
Type: RuntimeException Message: Callable
App\controllers\HomeController does not exist File:
D:\htdocs\slim\vendor\slim\slim\Slim\CallableResolver.php Line: 90
Last, I also refer to these articles:
https://www.slimframework.com/docs/objects/router.html#container-resolution
PHP Slim Framework Create Controller
PHP Slim Framework Create Controller
How can i create middleware on Slim Framework 3?
How can i create middleware on Slim Framework 3?
Add psr-4 to your composer file so that you're able to call your namespaces.
{
"require": {
"slim/slim": "^3.12
},
"autoload": {
"psr-4": {
"App\\": "app"
}
}
}
This PSR describes a specification for autoloading classes from file paths. Then in your routes.php file add this at the top :
<?php
use app\controllers\HomeController;
// Routes
$app->get('/dd', 'App\controllers\HomeController:home');
and finally in your HomeController.php file add :
<?php
namespace app\controllers;
class HomeController
{
//.. your code
}
hope this helps...:)
I just started using Slim Framework to create my rest API. Everything works well until I try to route HTTP request to a static class method (I used the anonymous function before). Below is my new route code on index.php:
include "vendor/autoload.php";
$config = ['settings' => [
'addContentLengthHeader' => false,
'displayErrorDetails' => true,
'determineRouteBeforeAppMiddleware' => true
]
];
$app = new \Slim\App($config);
$app->get('/user/test', '\App\Controllers\UserController:test');
$app->run();
And below is my UserController class on UserController.php
class UserController{
public function test($request, $response, $args){
$array = ['message'=>'your route works well'];
return $response->withStatus(STAT_SUCCESS)
->withJson($array);
}
}
Error details:
Type : RuntimeException
Message: Callable \Controllers\UserController does not exist
File : /var/www/html/project_api/vendor/slim/slim/Slim/CallableResolver.php
Below is my project folder tree
project_api/
index.php
vendor/
slim/slim/Slim/CallableResolver.php
Controllers/
UserController.php
my composer.json
{
"require": {
"slim/slim": "^3.8",
"sergeytsalkov/meekrodb": "*",
"slim/http-cache": "^0.3.0"
}
},
"autoload": {
"psr-4": {
"Controllers\\": "Controllers/"
}
}
It seems that your namespace is define improperly. In your composer.json, class UserController under the namespace Controllers.
you should define a namespace at the top of your UserController.php:
namespace Controllers;
and change $app->get() in your index.php to:
$app->get('/user/test', 'Controllers\UserController:test');
I am trying to implement a Billing interface which uses Stripe.
I have created the Billing interface, Stripe class and binded the interface using a Service Provider.
I receive a Class not found error when trying to run the code:
ReflectionException in Container.php line 737: Class
Acme\Billing\StripeBilling does not exist
I can't figure out what the issue is, I've double checked for small issues like correct case etc.
Here is the code I've used:
app/Acme/Billing/BillingInterface.php
<?php
namespace Acme\Billing;
interface BillingInterface {
public function charge(array $data);
}
app/Acme/Billing/StripeBilling.php
<?php
namespace Acme\Billing;
use Stripe;
use Stripe_Charge;
use Stripe_Customer;
use Stripe_InvalidRequestError;
use Stripe_CardError;
use Exception;
class StripeBilling implements BillingInterface {
public function __construct()
{
Stripe::setApiKey(env('STRIPE_SECRET_KEY'))
}
public function charge(array $data)
{
try
{
return Stripe_Charge::create([
'amount' => 1000, // £10
'currency' => 'gbp',
'description' => $data['email'],
'card' => $data['token']
]);
}
catch(Stripe_CardError $e)
{
dd('card was declined');
}
}
}
app/Providers/BillingServiceProvider.php (UPDATED)
class BillingServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->bind('Billing\BillingInterface', 'Billing\StripeBilling');
}
}
BasketController.php (ADDED)
public function store(Request $request)
{
$billing = \App::make('Billing\BillingInterface');
return $billing->charge([
'email' => $request->email,
'stripe-token' => $request->token,
]);
I have added App\Providers\BillingServiceProvider::class to my app.php file, and updated my composer.json to include Acme folder "Acme\\": "app/"
Your problem looks two-fold:
The PSR-4 autoload definition in your composer.json file is incorrect.
If your Acme folder lives inside the app folder, e.g. /dir/project_root/app/Acme/Billing/BillingInterface.php, then your composer.json definition should look like this:
"psr-4": {
"Acme\\": "app/Acme"
}
This is the root cause of the error you are receiving, which is not a Laravel-specific error. The autoloader simply cannot find the class you are asking for, even though the requested fully qualified class name is correct.
Your interface and class are not bound to the container properly (missing the Acme portion of the namespace).
Because you've defined both of them in the Acme namespace, you need to ensure Acme is present in your service provider definitions. So your service provider should look like this:
class BillingServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->bind('Acme\Billing\BillingInterface', 'Acme\Billing\StripeBilling');
}
}
(Or, better yet, use the ::class syntax for improved IDE support.)
You will also need to make sure the fully qualified classname is correct when requesting the class in your controller: App::make('Acme\Billing\BillingInterface'). (I would recommend using dependency injection instead of this syntax, anyway.)
I am trying to include a third party library into my Symfony 2 project as explained here. However, I keep getting the error message Fatal error: Class 'Sprain_Images' not found in /src/MyProject/MyBundle/Controller/BackendController.php on line 267.
Here is what I did:
I put a third party class into the src folder (not directly in vendors because this class is not available to be loaded by deps).
#Directory structure
-src
-MyProject
-vendor
-sprain
-lib
-Images
-src
Images.php
Then I created the class to be used:
# /src/vendor/sprain/lib/Images/Images.php
require_once __DIR__.'/src/class.Images.php';
class Sprain_Images extends Images {
}
I also registered the prefix in autoload.php:
# /app/autoload.php
$loader->registerPrefixes(array(
'Twig_Extensions_' => __DIR__.'/../vendor/twig-extensions/lib',
'Twig_' => __DIR__.'/../vendor/twig/lib',
'Sprain_' => __DIR__.'/../src/vendor/sprain/lib',
));
And eventually I called the class in my controller:
# /src/MyProject/MyBundle/Controller/BackendController.php
$image = new \Sprain_Images();
However the class is not being found. Where did I make the mistake?
The class Sprain_Images should be in src/vendor/sprain/lib/Sprain/Images.php.
You can read more about the PSR-0 standard : https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md#underscores-in-namespaces-and-class-names
You just need to modify your composer.json file for the autoload value:
http://getcomposer.org/doc/04-schema.md#autoload
//composer.json in your symfony 2.1 project
"autoload": {
"psr-0": {
"": "src/",
"YourLibrary": "src/location/of/lib"
}
},
And then in your controller for example:
namespace Acme\UserBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use YourLibrary\FolderName\ClassName.php;
class DefaultController extends Controller {
/**
* #Route("/")
* #Template()
*/
public function indexAction()
{
$lib = new ClassName();
$lib->getName();
return array('name' => $name);
}
}