I am trying to add slim flash message to be accessed with my controller
using Slim framework 3 & Twig, But I get the following error :
Call to a member function addMessage() on null,
Buzz\Controllers\MailController::$flash in
C:\xampp\htdocs\myapp\app\Controllers\MailController.php on line 63
// bootfile.php
<?php
$container['MailController'] = function($container){ return new \Buzz\Controllers\MailController($container); };
$container['flash'] = function($container){ return new \Slim\Flash\Messages; };
$container['view'] = function($container){
$twig = new \Slim\Views\Twig(__DIR__ . '/../pages/views', [ 'cache' => false, ]);
$twig->addExtension(new \Slim\Views\TwigExtension( $container->router, $container->request->getUri()));
$view->getEnvironment()->addGlobal('flash', $container->flash);
return $twig;
};
// MailController.php
public function sendmail($request, $response){
$sent = mail->send();
if ($sent) {
$this->flash->addMessage('mailsuccess', 'Thank you for contacting');
}
}
Related
I am working on a website using the Slim framework. I am trying to make a link that takes the user to a specific place on the home page.
This is the normal link:
Home
First I tried to write an absolute link like:
Anchor
But this doesn't work and results in https://example.com/#anchor
This doesn't work either:
Home
How can I get the link to work and take me to the specified anchor?
The path_for twig extension can't handle anchors:
Home
UPD:
class DecoratedTwigExtension
{
private TwigExtension $twigExtension;
public function __construct(TwigExtension $twigExtension)
{
$this->twigExtension = $twigExtension;
}
public function __call($name, $arguments)
{
if (is_callable([$this->twigExtension, $name])) {
return $this->twigExtension->$name(...$arguments);
}
$message = sprintf('There is no callable method %s::%s', get_class($this->twigExtension), $name);
throw new \BadMethodCallException($message);
}
public function pathFor($name, $data = [], $queryParams = [], $appName = 'default', $anchor = '')
{
$path = $this->twigExtension->pathFor($name, $data, $queryParams);
// some manipulations with $path
if ($anchor !== '') {
}
return $path;
}
}
// Register Twig View helper
$container['view'] = function ($c) {
$view = new \Slim\Views\Twig('path/to/templates', [
'cache' => 'path/to/cache'
]);
// Instantiate and add Slim specific extension
$router = $c->get('router');
$uri = \Slim\Http\Uri::createFromEnvironment(new \Slim\Http\Environment($_SERVER));
// ======= the main lines =======
$twigExtension = new \Slim\Views\TwigExtension($router, $uri);
$view->addExtension(new \App\Namespace\DecoratedTwigExtension($twigExtension));
return $view;
};
I trying to add new function to Twig Extension file which includes template and parses variables from included template. And I have no clue how to get variable from imported template.
My Templates
Config.html
{% set myVariable= "MyVariable" %}
template.html
{{layout("config") }}
My Config Variable: {{ myVariable }}
This is my Twig Extension Class.
class TwigExtensions extends \Twig_Extension {
public function getFunctions()
{
return array(
new \Twig_SimpleFunction(
'layout', array($this, 'twig_layout', ), [ 'needs_environment' => true, 'needs_context' => true, 'is_safe' => ['all'] ]
)
);
}
function twig_layout(\Twig_Environment &$env, &$context, $template, $variables = [], $withContext = true, $ignoreMissing = false, $sandboxed = false)
{
$file_name = (string)$template . ".html";
if ($withContext) {
$variables = array_merge($context, $variables);
}
$result = '';
try {
$result = $env->resolveTemplate($file_name)->render($variables);
// how to get variables from $file_name tempalte
} catch (Throwable $e) {
return "NULL"
}
return $result;
}
}
I am using PhalconPHP and storing values in session after login something like below.
$this->session->start();
$this->session->set('auth', array(
'dealer_id' => $dealers->getDealerId(),
'username' => $dealers->getUserName(),
'language_id' => $dealers->getLanguageId(),
'dealername' => $dealername,
));
session_write_close();
which set the values in session, even just after that if I try printing
print_r($this->session->get('auth'))
it returns
Array
(
[dealer_id] => 78
[username] => swiftmailcomm
[language_id] => 1
[dealername] => Swiftmail Communication
)
But when I try to get this session values using $this->session->get('auth') in ControllerBase in some action it doesn't return anything. It seems to be destroyed.
Module.Php
public function registerServices(\Phalcon\DiInterface $di)
{
$di->set('dispatcher',function(){
$eventsManager = new EventsManager;
/**
* Check if the user is allowed to access certain action using the SecurityPlugin
*/
$eventsManager->attach('dispatch:beforeDispatch', new SecurityPlugin);
/**
* Handle exceptions and not-found exceptions using NotFoundPlugin
*/
$eventsManager->attach('dispatch:beforeException', new NotFoundPlugin);
$dispatcher = new MvcDispatcher;
$dispatcher->setEventsManager($eventsManager);
$dispatcher = new \Phalcon\Mvc\Dispatcher();
$dispatcher->setDefaultNamespace("NBBD_SkyWebTech\Dealer\Controllers\\");
return $dispatcher;
});
/**
* Read configuration
*/
$config = include __DIR__ . "/config/config.php";
//Register Volt as a service
$di['view'] = function () use ($config) {
$view = new View();
$view->setViewsDir($config->application->viewsDir);
//activating volt engine
$view->registerEngines(array(
".volt" => 'voltService'
));
return $view;
};
$di->set('voltService', function($view, $di) use ($config) {
$volt = new Volt($view, $di);
$volt->setOptions(array(
"compiledPath" => $config->application->voltCacheDir,
'compiledSeparator' => '_',
"compiledExtension" => ".compiled"
));
return $volt;
});
/*
* Setting up the view component
$di['view'] = function () use ($config) {
$view = new View();
$view->setViewsDir($config->application->viewsDir);
//activating volt engine
$view->registerEngines(array(
".phtml" => 'voltService'
));
return $view;
}; */
//Set the views cache service
$di->set('viewCache', function() use ($config) {
// Cache the files for 1hour using a Output frontend
$frontCache = new Output(array(
"lifetime" => 3600
));
//Cache data for one day by default
$cache = new File($frontCache, array(
"cacheDir" => $config->application->cacheDir
));
return $cache;
});
//Model Cache
$di->set('modelsCache', function() use ($config) {
//Cache data for one day by default
$frontCache = new \Phalcon\Cache\Frontend\Data(array(
"lifetime" => 3600
));
//Cache data for one day by default
$cache = new File($frontCache, array(
"cacheDir" => $config->application->cacheDir
));
return $cache;
});
//Set up the flash service
$di->set('flash', function() {
return new \Phalcon\Flash\Session(array(
'error' => 'alert alert-danger',
'success' => 'alert alert-success',
'notice' => 'alert alert-info',
));
});
/**
* Start the session the first time some component request the session service
*/
$di->set('session', function () {
$session = new SessionAdapter();
$session->start();
return $session;
});
}
In your declaration of the session service you use the dependency injector method "set". I believe you need to use "setShared" as this makes the session service act as a singleton which will make anything you set in it available to other controllers.
I have this exact setup and it works for me.
I think using the set method is causing it to create new session each time rather than pulling the existing one that contains your data.
$di->setShared('session', function () {
$session = new SessionAdapter();
$session->start();
return $session;
});
I'm using PHP on IIS, Phalcon framework. I have a login controller which I'm working on (yes, password isn't encrypted yet, but that's later) but I can't seem to get it to work.
I have a form action posting to signin/doSignin. This is a snippet of the SigninController.php:
public function doSigninAction(){
//$this->view->disable();
$user = User::findFirst([
'conditions' => 'email = :email: AND password = :password:'
, 'bind' => [
'email' => $this->request->getPost('email')
, 'password' => $this->request->getPost('password')
]
]);
if ($user){
echo 1;
return;
}
echo 2;
What results when I run this code is a blank page that simply reports:
Call to undefined method or service 'getDI'
Something somewhere is not lined up properly for the internals of phalcon, but I don't know what I need to check. When I change the above code to this, I get a proper rendering of the view, printing 1 for the user:
$user = new User()/*::findFirst([
'conditions' => 'email = :email: AND password = :password:'
, 'bind' => [
'email' => $this->request->getPost('email')
, 'password' => $this->request->getPost('password')
]
]);*/;
if ($user){
echo 1;
return;
}
echo 2;
My bootstrap is the following:
<?php
try {
set_include_path('c:/workspace/GIIAnalytics/app/views');
//Autoloader
$loader = new \Phalcon\Loader();
$loader->registerDirs([
'../app/controllers/'
, '../app/models/'
, '../app/config/'
]);
/** For MSSQL connections */
$loader->registerNamespaces([
"Twm\Db\Adapter\Pdo" => "../app/library/db/adapter/"
, "Twm\Db\Dialect" => "../app/library/db/dialect/"
]);
$loader->register();
//Dependancy Injection
$di = new \Phalcon\DI\FactoryDefault();
//Config
$configFile = __DIR__ . '/../app/config/config.json';
$config = json_decode ( file_get_contents ( $configFile ) );
$di->setShared('config',$config);
//MSSQL Database connection
$di->set("db", function() use ($di) {
//Database info
/** For MSSQL connections */
$mc = $di->getDI()->getShared('config')['db'];
$db = new Twm\Db\Adapter\Pdo\Mssql($mc);
return $db;
});
//View
$di->set('view', function(){
$view = new \Phalcon\Mvc\View();
$view->setViewsDir('../app/views');
/*
$view->registerEngines([
'.volt' => '\Phalcon\Mvc\View\Engine\Volt'
]);
*/
return $view;
});
// Router
$di->set('router',function(){
$router = new \Phalcon\Mvc\Router();
$router->mount(new Routes());
return $router;
});
// Session
$di->setShared('session', function() {
$session = new \Phalcon\Session\Adapter\Files();
$session->start();
return $session;
});
//Flash Data (temp data)
$di->set('flash', function() {
$flash = new \Phalcon\Flash\Session([
'error' => 'alert alert-danger'
, 'success' => 'alert alert-success'
, 'notice' => 'alert alert-info'
, 'warning' => 'alert alert-warning'
]);
return $flash;
});
//Metadata
$di['modelsMetadata'] = function() {
$metaData = new \Phalcon\Mvc\Model\MetaData\Memory([
'lifetime' => 86400
, 'prefix' => 'metaData'
]);
return $metaData;
};
// custom dispatcher overrides the default
$di->set('dispatcher', function() use ($di) {
$eventsManager = $di->getShared('eventsManager');
// Custom ACL class
$permission = new Permission();
// Listen for events from the $permission class
$eventsManager->attach('dispatch', $permission);
$dispatcher = new \Phalcon\Mvc\Dispatcher();
$dispatcher->setEventsManager($eventsManager);
return $dispatcher;
});
//Deploy the app
$app = new \Phalcon\Mvc\Application($di);
echo $app->handle()->getContent();
} catch(\Phalcon\Exception $e) {
echo $e->getmessage();
}
?>
How do I fix the dependency problem?
Found the issue. Phalcon is not good about giving you the line for invalid function calls. It was in my db constructor, where I'm doing $di->getDI this got changed (along with the config reader) to this snippet:
//MSSQL Database connection
$di->set("db", function() use ($di) {
//Database info
/** For MSSQL connections */
$mc = (array) $di->getShared('config')->db;
$db = new Twm\Db\Adapter\Pdo\Mssql($mc);
return $db;
});
With the following code, how do I place the on_stats function in one area? So it can be shared and called in all functions on this page instead of copying and pasting the same code over and over again. Also how do I declare $logger just once instead of over and over again.
class API extends Controller
{
public function __construct() {
}
public function api_call1() {
$client = new GuzzleHttp\Client(['defaults' => ['verify' => false]]);
$logger = new Logger('View Logs');
$logger->pushHandler(new StreamHandler(storage_path() . '/logs/api_log.log', Logger::INFO));
$res = $client->get($this->url . "/my/url/", [
'on_stats' => function (TransferStats $stats) use ($logger) {
$logger->info('Request' . $stats->getRequest()->getMethod() .
'Response' . $stats->getResponse()->getStatusCode() .
'Tx Time' . $stats->getTransferTime()
);
}
]);
$response = Response::make($res->getBody(), 200);
$response->header('Content-Type', 'application/json');
return $response;
}
public function api_call2() {
$client = new GuzzleHttp\Client(['defaults' => ['verify' => false]]);
$logger = new Logger('View Logs');
$logger->pushHandler(new StreamHandler(storage_path() . '/logs/api_log.log', Logger::INFO));
$res = $client->get($this->url . "/my/url2/", [
'on_stats' => function (TransferStats $stats) use ($logger) {
$logger->info('Request' . $stats->getRequest()->getMethod() .
'Response' . $stats->getResponse()->getStatusCode() .
'Tx Time' . $stats->getTransferTime()
);
}
]);
$response = Response::make($res->getBody(), 200);
$response->header('Content-Type', 'application/json');
return $response;
}
}
From my viewpoint, it would be a great idea to:
Declare a class property as $logger
Move logger initialization to the constructor
Rewrite the "on_stats" method as a class method, say logEvent(TransferStats $stats) using $this->logger, this way you can avoid using "use" keyword
Pass the client event "on_stats" as a standard PHP callable array:
['on_stats' => [$this, 'logEvent']]