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;
};
Related
How do I make a condition the if the country is US the setViewFileName will use Which_Online_Shopper_Are_You_US/default.html.twig
public function routeWhich_Online_Shopper_Are_You(Get $request, Twig $response): array
{
global $CONFIG;
if (I18l::getCountryByDomain() !== "GB") {
$response->redirect('/');
}
$siteName = $CONFIG['site_name'];
$siteUrl = $CONFIG['site_url'];
$context = [
'siteName' => $siteName,
'siteUrl' => $siteUrl
];
$page = $this->project->config->getPage();
$response->setViewFilename('Which_Online_Shopper_Are_You/default.html.twig');
$page->setPageTitle('Which Online Shopper Are You');
$page->updateMeta();
return $context;
}
You can set the view as a variable which you can overwrite depending on the current country.
I also made sure the US isn't redirected.
More details are added as comments in the code below:
public function routeWhich_Online_Shopper_Are_You(Get $request, Twig $response): array
{
global $CONFIG;
// Add all the allowed countries
$allowed = ['GB', 'US'];
// Get the current country
$currentCountry = I18l::getCountryByDomain();
// Check if the current country is in the allowed array. If not, redirect
if (in_array($currentCountry, $allowed) === false) {
$response->redirect('/');
}
// Set the default view
$viewFile = 'Which_Online_Shopper_Are_You/default.html.twig';
// Now override the view if the country is US
if ($currentCountry === 'US') {
$viewFile = 'Which_Online_Shopper_Are_You_US/default.html.twig';
}
$siteName = $CONFIG['site_name'];
$siteUrl = $CONFIG['site_url'];
$context = [
'siteName' => $siteName,
'siteUrl' => $siteUrl
];
$page = $this->project->config->getPage();
// Let's use our dynamic viewFile variable to set the view
$response->setViewFilename($viewFile);
$page->setPageTitle('Which Online Shopper Are You');
$page->updateMeta();
return $context;
}
I try to create a block for the main page based on list action sonata admin is possible?
example
dashboard:
blocks:
- { type: mea.task.block, position: center, roles: [ ROLE_WORKER ] }
Here is block render
class TaskListAdminBlock extends AbstractAdminBlockService
{
/**
* {#inheritdoc}
*/
public function execute(BlockContextInterface $blockContext, Response $response = null)
{
$controller = 'Mea\TaskBundle\Sonata\Controller\TaskCrudController::listAction';
$path = [
'_controller' => $controller,
];
$subRequest = $this->requestStack->getMasterRequest()->duplicate($query, null, $path);
return $this->kernel->handle($subRequest, HttpKernelInterface::SUB_REQUEST);
}
}
TaskCrudController is sonata admin controller for task
this throw error
There is no `_sonata_admin` defined for the controller `Mea\TaskBundle\Sonata\Controller\TaskCrudController` and the current route ``
Is possible to fix this code or archive this in another way?
Ok I found beautifully solution
This renders in ajax made admin list
public function execute(BlockContextInterface $blockContext, Response $response = null)
{
$controller = 'Mea\TaskBundle\Sonata\Controller\TaskCrudController::listAction';
$path = array(
'_controller' => $controller
);
$query = [
'filter'=>[
'_per_page'=>4,
],
];
$subRequest = $this->requestStack->getMasterRequest()->duplicate($query, null, $path);
$subRequest->headers->set('X-Requested-With','XMLHttpRequest');
$subRequest->request->set('_sonata_admin','mea.task.task.admin');
$response = $this->kernel->handle($subRequest, HttpKernelInterface::SUB_REQUEST);
return $response;
}
Not fully work fine - ajax mode switch actions to select.
I'm migrating from zend framework 1 to 3 , and I have a function that returns twig template but I don't know what should I use to render view twig template on zf3
How to:
use class of viewer
set my template path
set array to render it in template
return template
code:
protected function convertItemList($aItemList)
{
$aSet = [];
//$config['template_paths'] = [APPLICATION_PATH . '/../library/Core/Backend/SRO/Views/'];
//$oView = new Core_Twig_View($config);
if (!$aItemList) {
return [];
}
foreach ($aItemList as $iKey => $aCurItem) {
$aSpecialInfo = [];
$aInfo = $aCurItem;
$aInfo['info'] = $this->getItemInfo($aCurItem);
$aInfo['blues'] = $this->getBluesStats($aCurItem, $aSpecialInfo);
$aInfo['whitestats'] = $this->getWhiteStats($aCurItem, $aSpecialInfo);
//$oView->assign('aItem', $aInfo);
$i = isset($aCurItem['Slot']) ? $aCurItem['Slot'] : $aCurItem['ID64'];
if ($aCurItem['MaxStack'] > 1) {
$aSet[$i]['amount'] = $aCurItem['Data'];
}
$aSet[$i]['TypeID2'] = $aInfo['TypeID2'];
$aSet[$i]['OptLevel'] = $aInfo['OptLevel'];
$aSet[$i]['RefItemID'] = !isset($aCurItem['RefItemID']) ? 0 : $aCurItem['RefItemID'];
$aSet[$i]['special'] = isset($aInfo['info']['sox']) && $aInfo['info']['sox'] ? true : false;
$aSet[$i]['ItemID'] = $aCurItem['ID64'];
$aSet[$i]['ItemName'] = $aInfo['info']['WebName'];
$aSet[$i]['imgpath'] = $this->getItemIcon($aCurItem['AssocFileIcon128']);
//$aSet[$i]['data'] = $oView->render('itemData.twig');
}
return $aSet;
}
I use this module https://github.com/OxCom/zf3-twig.
You can install it by github instructions and add this parameter to zf3 configuration array:
'service_manager' => array(
'factories' => array(
...
'TwigStrategy' => \ZendTwig\Service\TwigStrategyFactory::class,
...
),
)
1) After this you can use Twig in some action of some controller by this code:
function someAction(){
...
$viewModel = new ZendTwig\View\TwigModel(['foo'=>'bar']);
return $viewModel;
}
2) To set other template:
function someAction(){
$viewModel = new ZendTwig\View\TwigModel(['foo'=>'bar']);
$viewModel->setTemplate('application/controller/name'); //set path here
return $viewModel;
}
3) You can to set array variables by TwigModel "__construct" parameter:
function someAction(){
$viewModel = new ZendTwig\View\TwigModel($someVariablesArray);
$viewModel->setTemplate('application/controller/name'); //set path here
return $viewModel;
}
4) If you need to return html code, you need to do something:
Add in services config one more param:
'service_manager' => array(
'factories' => array(
...
'TwigStrategy' => \ZendTwig\Service\TwigStrategyFactory::class,
'TwigRenderer' => \ZendTwig\Service\TwigRendererFactory::class,
...
),
)
Add TwigRenderer service in your controller factory:
class YourControllerFactory implements FactoryInterface
{
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
return new YourController($twigRenderer);
}
}
and get twigRenderer in your Controller:
private $twigRenderer;
public function __construct($twigRenderer)
{
$this->twigRenderer = $twigRenderer;
}
After this get html:
function someAction(){
$viewModel = new ZendTwig\View\TwigModel(['foo'=>'bar']);
$viewModel->setTemplate('mails/order/order_in_process');
$html = $this->twigRenderer->render($viewModel);
return $html;
}
Sorry for my english!
I want to create one controller file which is creating automatically a function if i create a menu dynamically and also want to create view page which is connencted to this main controller.. how to do that?
Current code:
public function our_history()
{
$data['category']= $this->menu_model->getCategory('$lang');
$data['subcategory']= $this->menu_model->getSubCategory('$lang');
$this->load->view('vwMain',$data);//Left Menu }
}
Follow below steps Hope that makes sense.
-- Admin section --
/*content.php -- controller starts here */
class Content extends VCI_Controller {
# Class constructor
function __construct()
{
parent::__construct();
$this->load->model('content_model');
}
/*
Add page logic
*/
function edit_page($id = null)
{
$this->_vci_layout('your_layoutname');
$this->load->library('form_validation');
$view_data = array();
//Set the view caption
$view_data['caption'] = "Edit Content";
//Set the validation rules for server side validation
// rule name editcontent should be defined
if($this->form_validation->run('editcontent')) {
//Everything is ok lets update the page data
if($this->content_model->update(trim($id))) {
$this->session->set_flashdata('success', "<li>Page has been edited successfully.</li>");
$this->output->set_header('location:' . base_url() . 'content/manage_content');
} else {
$this->session->set_flashdata('error', "<li>Unknown Error: Unable to edit page.</li>");
$this->output->set_header('location:' . base_url() . 'content/manage_content');
}
} else {
$page = $this->content_model->get_content_page(trim($id));
$view_data["id"] = $page->id;
$view_data["page_title"] = $page->page_title;
$view_data["page_menu_slug"] = $page->page_menu_slug;
$view_data["page_name"] = $page->page_name;
$view_data["page_content"] = $page->page_content;
$view_data["status"] = $page->status;
$this->_vci_view('content_editpage', $view_data);
}
}
/*
Edit page logic
*/
function add_page()
{
$this->_vci_layout('your_layoutname');
$this->load->library('form_validation');
$view_data = array();
$view_data['caption'] = "Edit Content";
if($this->form_validation->run('editcontent')) {
// after passing validation rule data to be saved
// editcontent rule must be defined in formvalidations file
//Everything is ok lets update the page data
if($this->content_model->add()) {
$this->session->set_flashdata('success', "<li>Page has been edited successfully.</li>");
$this->output->set_header('location:' . base_url() . 'content/manage_content');
} else {
$this->session->set_flashdata('error', "<li>Unknown Error: Unable to edit page.</li>");
$this->output->set_header('location:' . base_url() . 'content/manage_content');
}
} else {
$page = $this->content_model->get_content_page(trim($id));
$view_data["id"] = $page->id;
$view_data["page_title"] = $page->page_title;
$view_data["page_menu_slug"] = $page->page_menu_slug;
$view_data["page_name"] = $page->page_name;
$view_data["page_content"] = $page->page_content;
$view_data["status"] = $page->status;
$this->_vci_view('content_editpage', $view_data);
}
}
}
/**
* content.php -- controller ends here
*/
/*
Content_model starts here
*/
class Content_model extends CI_Model {
// update logic goes here
function update($id = null) {
if(is_null($id)) {
return false;
}
$data = array(
'page_title' => htmlspecialchars($this->input->post('page_title',true)),
'page_name' => htmlspecialchars($this->input->post('page_name',true)),
'page_content' => $this->input->post('page_content',true),
'page_menu_slug' => htmlspecialchars($this->input->post('page_menu_slug',true)),
'status' => htmlspecialchars($this->input->post('status',true))
);
$this->db->where('id', $id);
$this->db->update('content', $data);
return true;
}
// Add logic goes here
function add() {
$data = array(
'page_title' => htmlspecialchars($this->input->post('page_title',true)),
'page_name' => htmlspecialchars($this->input->post('page_name',true)),
'page_content' => $this->input->post('page_content',true),
'page_menu_slug' => htmlspecialchars($this->input->post('page_menu_slug',true)),
'status' => htmlspecialchars($this->input->post('status',true))
);
$this->db->where('id', $id);
$this->db->insert('content', $data);
return true ;
}
}
/*
Content_model ends here # Admin section changes ends here
*/
-- Add view files also to admin section content_editpage.php
Now go to your routes.php file for front section --
add below line at last --
$route['(:any)'] = 'page/view_usingslug/$1';
This will be for all urls like --- http://yourdomainname/your_slug_name
// create again a controller in front section page.php --
class page extends VCI_Controller {
function __construct()
{
parent::__construct();
}
function view_usingslug($slug='')
{
// retrieve the data by slug from content table using any model class and assign result to $view_dat
$this->_vci_view('page',$view_data);
//page.php will be your view file
}
}
Suppose Your URL is
www.example.com/controllername/methodname/menutitle1
or
www.example.com/controllername/methodname/menutitle2
So this is how you handle these pages.
public function method()
{
$menutitle = $this->uri->segment(3);
$query = $this->db->get_where('TableName',array('Menutitle'=>$menutitle))
$data['content'] = $query->row()->page_content;
$this->load->view('common_page',$data);
}
I'm writing a REST API with Slim. I have written a small middleware to protect the resources so only authenticated users will be able to access them:
<?php
class SecurityMiddleware extends \Slim\Middleware
{
protected $resource;
public function __construct($resource)
{
$this->resource = $resource;
}
public function call()
{
//get a reference to application
$app = $this->app;
//skip routes that are exceptionally allowed without an access token:
$publicRoutes = ["/","/login","/about"];
if (in_array($app->request()->getPathInfo(),publicRoutes)){
$this->next->call(); //let go
} else {
//Validate:
if ($this->resource->isValid()){
$this->next->call(); //validation passed, let go
} else {
$app->response->setStatus('403'); //validation failed
$app->response->body(json_encode(array("Error"=>"Access token problem")));
return;
}
}
}
}
This works, but the undesired side effect is the middleware does not make a distinction between existing routes and non-existing routes. For example, if a the user attempts to request a route like /dfghdfgh which does not exist, instead of getting an HTTP status code of 404 he'll get a 403 saying there is no access token. I would like to add an implementation similar to the following check on the middleware class:
if ($app->hasRoute($app->request->getPathInfo()){
$this->next->call(); //let go so user gets 404 from the app.
}
Any ideas how this can be achieved?
I use a hook to do what you're trying to do, as MamaWalter suggested, but you want to use slim.before.dispatch rather than an earlier hook. If the route your user is trying to visit doesn't exist, the hook will never be called and the 404 gets thrown.
I'm doing exactly that in my own Authorization Middleware. Works like a charm.
Maybe my implementation will work for you:
<?php
class CustomAuth extends \Slim\Middleware {
public function hasRoute() {
$dispatched = false;
// copied from Slim::call():1312
$matchedRoutes = $this->app->router->getMatchedRoutes($this->app->request->getMethod(), $this->app->request->getResourceUri());
foreach ($matchedRoutes as $route) {
try {
$this->app->applyHook('slim.before.dispatch');
$dispatched = $route->dispatch();
$this->app->applyHook('slim.after.dispatch');
if ($dispatched) {
break;
}
} catch (\Slim\Exception\Pass $e) {
continue;
}
}
return $dispatched;
}
public function call() {
if ($this->hasRoute()) {
if ($authorized) {
$this->next->call();
}
else {
$this->permissionDenied();
}
}
else {
$this->next->call();
}
}
}
Not exactly what you asking for, but personnaly when i need to check authentification on some routes i do it like this.
config:
$config = array(
...,
'user.secured.urls' => array(
array('path' => '/user'),
array('path' => '/user/'),
array('path' => '/user/.+'),
array('path' => '/api/user/.+')
),
...
);
middleware:
/**
* Uses 'slim.before.router' to check for authentication when visitor attempts
* to access a secured URI.
*/
public function call()
{
$app = $this->app;
$req = $app->request();
$auth = $this->auth;
$config = $this->config;
$checkAuth = function () use ($app, $auth, $req, $config) {
// User restriction
$userSecuredUrls = isset($config['user.secured.urls']) ? $config['user.secured.urls'] : array();
foreach ($userSecuredUrls as $url) {
$urlPattern = '#^' . $url['path'] . '$#';
if (preg_match($urlPattern, $req->getPathInfo()) === 1 && $auth->hasIdentity() === false) {
$errorData = array('status' => 401,'error' => 'Permission Denied');
$app->render('error.php', $errorData, 401);
$app->stop();
}
}
};
$app->hook('slim.before.router', $checkAuth);
$this->next->call();
}
but if almost all your routes need authentification maybe not the best solution.
great example: http://www.slideshare.net/jeremykendall/keeping-it-small-slim-php