Before the Slim 3 is released, codes below work fine:
settings.php,
return [
'settings' => [
'displayErrorDetails' => true,
'modules' => [
'core' => 'config/core/modules.php',
'local' => 'config/local/modules.php'
],
],
];
index.php
// Instantiate the app
$settings = require __DIR__ . '/../src/settings.php';
$app = new \Slim\App($settings);
$MyClass = new MyClass($app);
MyClass.php
class MyClass
{
private $app;
public function __construct($app)
{
$this->app = $app;
$local = require $app->settings['modules']['local'];
}
But after the release, I get this error below:
Notice: Undefined property: Slim\App::$settings in /...
So I can't use $app->settings anymore? What should I use then?
You can get settings like this:
$container = $app->getContainer();
$settings = $container->get('settings');
You can access settings route callables via $this
$modulesSettings = $this->get('settings')['modules']['local'];
For more information read here
The address of the SLIM 3 configuration file is pro/src/settings.php,
and you can add additional settings; In any route you can access them like this:
var_dump($this->get('settings')['logger']);
Related
I am relatively new to Slim so I am not sure if I am making an obvious mistake. I am trying to build the application in a secure way so the get function is not in the index file. The index requires a file that instantiates the slim app and requires the dependencies, settings, and routes files, the route file then requires the homepage which is where the error comes from.
When the code is run the page output is the get function from the homepage is displayed in plain text and then a error message underneath that reads:
"Page Not Found
The page you are looking for could not be found. Check the address bar to ensure your URL is spelled correctly. If all else fails, you can visit our home page at the link below.
Visit the Home Page"
I am sure php is installed properly as when I try the get function in the index page it run fine, I also tested it with phpinfo().
I am using xampp as my development environment.
/**
* Index.php
*/
ini_set('xdebug.trace_output_name', 'football_trivia_game');
ini_set('display_errors', 'On');
ini_set('html_errors', 'On');
ini_set('xdebug.trace_format', 1);
// Include bootstrap
include_once '../includes/bootstrap.php';
/**
* Bootstrap.php
*/
// Start the session
session_start();
// Require vendor
require 'vendor/autoload.php';
// Define app path
$app_path = __DIR__ . "/app/";
// Require settings
$settings = require $app_path . 'settings.php';
// Instantiate container
$container = new \Slim\Container($settings);
// Require the dependencies
require $app_path . 'dependencies.php';
// Instantiate app
$app = new \Slim\App($container);
// Require routes
require $app_path . 'routes.php';
// Execute app
$app->run();
session_regenerate_id(true);
/**
* Setttings.php
*/
// Display errors
ini_set('display_errors', 'On');
ini_set('html_errors', 'On');
// Get app url
$app_url = dirname($_SERVER['SCRIPT_NAME']);
// Get css path
$css_path = $app_url . '/css/app.css';
// Define css path
define('CSS_PATH', $css_path);
// Set settings
$settings = [
"settings" => [
'displayErrorDetails' => true,
'addContentLengthHeader' => false,
'mode' => 'development',
'debug' => true,
'view' => [
'template_path' => __DIR__ . '/templates/',
'twig' => [
'cache' => false,
'auto_reload' => true,
]],
'pdo_settings' => [
'rdbms' => 'mysql',
'host' => 'localhost',
'db_name' => 'fbta_db',
'port' => '3306',
'user_name' => 'username',
'user_password' => 'password',
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'options' => [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => true,
]
]
]
];
return $settings;
/**
* Dependencies
*/
$container['view'] = function ($container) {
$view = new \Slim\Views\Twig(
$container['settings']['view']['template_path'],
$container['settings']['view']['twig'],
[
'debug' => true // This line should enable debug mode
]
);
// Instantiate and add Slim specific extension
$basePath = rtrim(str_ireplace('index.php', ''. $container['request']->getUri()->getBasePath()), '/');
$view->addExtension(new Slim\Views\TwigExtension($container['router'], $basePath));
return $view;
};
/**
* routes.php
*/
require 'routes/homepage.php';
/**
* Homepage Route
*/
// Get Request and Response
use \Psr\Http\Message\ServerRequestInterface as Request;
use \Psr\Http\Message\ResponseInterface as Response;
$app->get('/', function(Request $request, Response $response) {
$message = 'test';
$response->getBody()->write($message);
return $response;
});
I apologise if I have included too much code, I am just unsure where the problem stems from, any help would be appreciated.
Slim is very flexible. Your must to specify how you are include the route.php script.
My way
index.php:
declare(strict_types=1);
(require __DIR__ . '/../config/bootstrap.php')->run();
bootstrap.php
declare(strict_types=1);
use DI\ContainerBuilder;
use Slim\App;
require_once __DIR__.'/../vendor/autoload.php';
(Dotenv\Dotenv::createImmutable(dirname(__DIR__)))->load();
$containerBuilder = new ContainerBuilder();
// Set up settings
$containerBuilder->addDefinitions(__DIR__.'/container.php');
// Build PHP-DI Container instance
$container = $containerBuilder->build();
// Только для WEB
if ('cli' !== php_sapi_name()) {
// Create App instance
$app = $container->get(App::class);
// Register routes
(require __DIR__.'/routes.php')($app);
// Register middleware
(require __DIR__.'/middleware.php')($app);
} else {
$app = $container;
}
return $app;
In my way routes.php is a script wich MUST return a function:
return function (App $app) {...}
So, in my way, your routes.php returns nothing, because homepage.php returns nothing
So, in my way, your homepage.php muyst be looks like:
return function (App $app) {
$app->get('/', function(Request $request, Response $response) {
$message = 'test';
$response->getBody()->write($message);
return $response;
});
}
So, you must be pass road path from the index.php to route.php in slim. )
I want to execute ZF3 action with zf-console.
I can do this using zend-mvc-console module and it works fine.
For example.
Application/config/module.config.php:
'console' => [
'router' => [
'routes' => [
'cronroute' => [
'options' => [
'route' => 'sync',
'defaults' => [
'controller' => Controller\ConsoleController::class,
'action' => 'syncEvents'
]
]
]
]
]
],
Application/src/Controller/ConsoleController.php
class ConsoleController extends AbstractActionController
{
/**
* Entity manager.
* #var Doctrine\ORM\EntityManager
*/
private $entityManager;
/**
* User Manager
* #var Application\Service\UserManager
*/
private $userManager;
/**
* Constructor.
*/
public function __construct($entityManager, $userManager)
{
$this->entityManager = $entityManager;
$this->userManager = $userManager;
}
public function syncAction()
{
$response = $this->userManager->syncUserInfo();
return $response ? 'Sync Success' : 'Failed to sync';
}
}
But it says that it will be deprecated:
https://zendframework.github.io/zend-mvc-console/intro/#deprecated
It suggest to use zf-console from zfcampus:
https://github.com/zfcampus/zf-console
But I cannot find a way to execute Controller action or to use my build services (like UserManager).
There is example to build Zend Application and retrieve Service manager:
use Zend\Console\Console;
use Zend\Console\ColorInterface as Color;
use ZF\Console\Application;
use ZF\Console\Dispatcher;
chdir(dirname(__DIR__));
require __DIR__ . '/../vendor/autoload.php'; // Composer autoloader
$application = Zend\Mvc\Application::init(require 'config/application.config.php');
$services = $application->getServiceManager();
$buildModel = $services->get('My\BuildModel');
Is there a way to execute Controller action with it? Or Can I load my UserManager service?
I tried to get My UserManager:
$buildModel = $services->get('Application\Service\UserManager');
But receiving error:
PHP Fatal error: Uncaught exception 'Zend\ServiceManager\Exception\ServiceNotFoundException' with message 'Unable to resolve service "Application\Service\UserManager" to a factory; are you certain you provided it during configuration?' in /var/www/html/vendor/zendframework/zend-servicemanager/src/ServiceManager.php:687
The zend-mvc-console module does seem to be on the edge of deprecation. Just like you I was trying to implement zfcampus/zf-console. Since the mvc-console module seems to be (almost) deprecated, I suggest you use something different than (mvc) controllers for your console work. I used a class that can handle the call (in a way zf-console expects).
This is a dummy example I was working on for my project;
This is script that is called on the command line:
use Zend\Console\Console;
use Zend\ServiceManager\ServiceManager;
use Zend\Stdlib\ArrayUtils;
use Zend\Stdlib\Glob;
use ZF\Console\Application;
use ZF\Console\Dispatcher;
require_once __DIR__ . '/vendor/autoload.php'; // Composer autoloader
$configuration = [];
foreach (Glob::glob('config/{{*}}{{,*.local}}.php', Glob::GLOB_BRACE) as $file) {
$configuration = ArrayUtils::merge($configuration, include $file);
}
// Prepare the service manager
$smConfig = isset($config['service_manager']) ? $configuration['service_manager'] : [];
$smConfig = new \Zend\Mvc\Service\ServiceManagerConfig($smConfig);
$serviceManager = new ServiceManager();
$smConfig->configureServiceManager($serviceManager);
$serviceManager->setService('ApplicationConfig', $configuration);
// Load modules
$serviceManager->get('ModuleManager')->loadModules();
$routes = [
[
'name' => 'dumb',
'route' => '[--foo=]',
'description' => 'Some really cool feature',
'short_description' => 'Cool feature',
'options_descriptions' => [
'foo' => 'Lorem Ipsum',
],
'defaults' => [
'foo' => 'bar',
],
'handler' => function($route, $console) use ($serviceManager) {
$handler = new \Application\Command\DumbCommand();
return $handler($route, $console);
}
],
];
$config = $serviceManager->get('config');
$application = new Application(
$config['app'],
$config['version'],
$routes,
Console::getInstance(),
new Dispatcher()
);
$exit = $application->run();
exit($exit);
The handler function can use the service manager to inject any dependencies to the command handler:
'handler' => function($route, $console) use ($serviceManager) {
/** #var \Doctrine\ORM\EntityManager $entityManager */
$entityManager = $serviceManager->get(\Doctrine\ORM\EntityManager::class);
/** #var mixed $repository */
$contactRepository = $entityManager->getRepository(\Application\Entity\Contact::class);
$handler = new \Application\Command\DumbCommand($contactRepository);
return $handler($route, $console);
}
The command class is placed in a Command folder, it looks like:
<?php
namespace Application\Command;
use Application\Entity\Contact;
use Application\Repository\ContactRepository;
use Zend\Console\Adapter\AdapterInterface;
use ZF\Console\Route;
class DumbCommand
{
/** #var ContactRepository */
private $contactRepository;
public function __construct($contactRepository)
{
$this->contactRepository = $contactRepository;
}
/**
* #param Route $route
* #param AdapterInterface $console
* #throws \Doctrine\ORM\ORMException
*/
public function __invoke(Route $route, AdapterInterface $console)
{
$console->writeLine('Bob was here');
foreach ($this->contactRepository->findAll() as $item) {
/** #var Contact $item */
$console->writeLine($item->getFirstName() . ' was here');
}
}
}
(
This is my solution:
I addedd console command routes to my module.config.php files
'console' => array(
'commands' => array(
array(
'name' => 'sendemail',
'handler' => PostCommand::class,
),
array(
'name' => 'sendsms',
'handler' => SmsTransferCommand::class,
)
)
),
I created a console.php in /public (this will be run with arguments to start a CLI app)
use Zend\Console\Console;
use Zend\ServiceManager\ServiceManager;
use ZF\Console\Application;
use ZF\Console\Dispatcher;
chdir(dirname(__DIR__));
require_once 'vendor/autoload.php'; // Composer autoloader
// Prepare application and service manager
$appConfig = require 'config/application.config.php';
$application = Zend\Mvc\Application::init($appConfig);
$serviceManager = $application->getServiceManager();
// Load modules
$serviceManager->get('ModuleManager')->loadModules();
$config = $serviceManager->get('config');
$routes = $config['console']['commands']; // This depends on your structure, this is what I created (see. 1.)
$application = new Application(
$config['app'],
$config['version'],
$routes,
Console::getInstance(),
new Dispatcher($serviceManager) // Use service manager as a dependency injection container
);
$exit = $application->run();
exit($exit);
I separated my CLI command handlers into the src/Command folder. My CLI command handlers are services I have defined, created by factories. (This is why I use the service manager as the container - see. 2.)
[serviceEmail here is a local class variable, which is loaded by the factory of this command handler.]
/**
* #param Route $route
* #param AdapterInterface $console
*
* #return int
*/
public function __invoke(Route $route, AdapterInterface $console)
{
$mails = $this->serviceEmail->sendMailFromDb();
$console->writeLine('Sent mails: ' . \count($mails), ColorInterface::WHITE, ColorInterface::RED);
return 0;
}
I want to configure several middleware in Dependency Container in Slim, so that I can set several constants in a same place and add middleware in a ease.
E.G.
$configuration = [
'settings' => [
'displayErrorDetails' => true,
],
'auth_settings' => [
'serect' => 'garyAPIserver',
],
];
$container = new Slim\Container($configuration);
$container['auth'] = function ($c) {
return new AuthMiddleware($c['auth_settings']);
};
$app = new Slim\App($container);
And I try to invoke the middleware in DI:
$app->add($app->get('auth'));
And I got the warning message print by php:
Warning: Missing argument 2 for Slim\App::get(), called in E:\www\slimServer-3.0\index.php on line 12 and defined in E:\www\slimServer-3.0\vendor\slim\slim\Slim\App.php on line 146
And the error message print by Slim:
Type: RuntimeException
Message: is not resolvable
File: E:\www\slimServer-3.0\vendor\slim\slim\Slim\CallableResolver.php
Line: 82
I am new in Slim, there it possible to set middleware in DI? Is there any guides with the similar scenario?
You can do it using the $container variable:
$app->add($container->get('auth'));
Then you can use it in your router functions using:
$auth = $this->get('auth');
Take a look here for more information.
I have the following index.php:
<?php
use Phalcon\Loader;
use Phalcon\Mvc\View;
use Phalcon\DI\FactoryDefault;
use Phalcon\Mvc\Url as UrlProvider;
use Phalcon\Db\Adapter\Pdo\Mysql as DbAdapter;
use Phalcon\Mvc\Micro;
try {
// Register an autoloader
$loader = new Loader();
$loader->registerDirs(array(
__DIR__ . '/controllers/',
__DIR__ . '/models/'
))->register();
// Create a DI
$app = new Micro();
$di = new FactoryDefault();
$app->setDI($di);
// Setup the view component
$di->set('view', function () {
$view = new View();
$view->setViewsDir('/views/');
return $view;
});
// Setup a base URI so that all generated URIs include the "legacy" folder
$di->set('url', function () {
$url = new UrlProvider();
$url->setBaseUri('/legacy/api/v1/');
return $url;
});
$di->set('router', function() {
// require __DIR__.'/config/routes.php';
// return $router;
$router = new Phalcon\Mvc\Router(false);
$router->add('/', array(
"controller" => "site",
"action" => "index"
));
$router->notFound(
[
"controller" => "site",
"action" => "ping"
]
);
var_dump($router);
return $router;
});
$app->handle();
} catch (\Exception $e) {
// Do Something I guess, return Server Error message
$app->response->setStatusCode(500, "Server Error");
$app->response->setContent($e->getMessage());
$app->response->send();
}
and the following structure:
--api
----v1
------config
-------- routes.php
------controllers
--------SiteController.php
------models
------views
The problem is that I think my application ignores the router, because I'm getting the following error: if I navigate to "/" - Matched route doesn't have an associated handler. While if I go to some random location like "/12321" it returns Not-Found handler is not callable or is not defined.
Any idea what I'm doing wrong?
Remember that you're setting as base uri /legacy/api/v1/ so all your routes are intended to be appended to that.
$di->set('url', function () {
$url = new UrlProvider();
$url->setBaseUri('/legacy/api/v1/');
return $url;
});
You can't simply access: / but instead, you've to visit /legacy/api/v1/ or if you want to visit /user, you've to visit /legacy/api/v1/user.
Greetings!
I also had some problems with phalcon (1.3.x) routes too. Here's what I did to make them working the way I wanted. Took me a long time to figure that out:
/** #var \Phalcon\Mvc\Router $router */
$router = new Phalcon\Mvc\Router(FALSE); // does not create default routes
$router->removeExtraSlashes(TRUE);
$router->setDefaults(array(
'namespace' => 'Namespace\Controller',
'controller' => 'index',
'action' => 'index'
));
$router->notFound(array(
'controller' => 'index',
'action' => 'show404'
));
Hope it helps.
I am fiddling with this issue and cannot resolve it - just wanted to check if anyone here can help with tips
I am loading the class and calling the constructor like this
include_once './Myaws.php';
$aws = new Myaws();
$aws->bucket = $images['config']['bucket'];
Myaws.php is as follows
class Myaws {
public $bucket;
function __construct() {
$this->aws = Aws::factory('./config/aws_config.php');
}
}
It works like a charm!
Now the issue
The './config/aws_config.php' is just an array that will change depending on the deployment stage - so I want to make it dynamic. Here is what I do and it doesnt work
include_once './Myaws.php';
$aws = new Myaws();
$aws->bucket = $images['config']['bucket'];
$aws->config = $images['config']['awsconfig'];
And in the Myaws.php, I change the following
class Myaws {
public $bucket;
public $config;
function __construct() {
$this->aws = Aws::factory($this->config);
}
}
It doesn't work :( and neither does the below one
include_once './Myaws.php';
$aws = new Myaws($images['config']['awsconfig']);
$aws->bucket = $images['config']['bucket'];
class Myaws {
public $bucket;
function __construct($config) {
$this->aws = Aws::factory($config);
}
}
This is pretty basic Oops and I don't seem to get it I think. Can anyone suggest me how can I make that variable $config dynamic?
I found the formatting on the included file vs in a passed array to be not 100% compatible. Also check the in the api docs how they use my_profile to pass those credentials.
here is a example of the current method I am using to generation the config
$aws = Aws::factory($this->getAwsConfig());
private function getAwsConfig()
{
return array(
// Bootstrap the configuration file with AWS specific features
'credentials' => array(
'key' => $this->awsKey,
'secret' => $this->awsSecret
),
'includes' => array('_aws'),
'services' => array(
// All AWS clients extend from 'default_settings'. Here we are
// overriding 'default_settings' with our default credentials and
// providing a default region setting.
'default_settings' => array(
'params' => array(
'region' => $this->awsRegion
)
)
)
);
}