How to redirect user to previous page after deleting Entity?
#[Route('/panel/remove/{id}', name: 'removethis')]
public function RemoveThis(int $id)
{
$url = $this->adminUrlGenerator
->setController(SomethingCrudController::class)
->setAction('delete')
->setEntityId($id)
->generateUrl();
return $this->redirect($url);
}
Right now it redirects to homepage
private $adminUrlGenerator;
public function __construct(AdminUrlGenerator $adminUrlGenerator)
{
$this->adminUrlGenerator = $adminUrlGenerator;
}
#[Route('/admin/sync', name: 'admin_sync')]
public function sync()
{
$url = $this->adminUrlGenerator
->setController(SyncCrudController::class)
->setAction(Action::INDEX)
->generateUrl();
return $this->redirect($url);
}
Related
I am working on a SilverStripe project. In my project, I am trying to create a GridField custom button. I followed the official documentation. Following is the class form the SilverStripe official page.
class GridFieldCustomAction implements GridField_ColumnProvider, GridField_ActionProvider, GridField_ActionMenuItem
{
public function getTitle($gridField, $record, $columnName)
{
return 'Custom action';
}
public function getCustomAction($gridField, $record)
{
if (!$record->canEdit()) {
return;
}
return GridField_FormAction::create(
$gridField,
'CustomAction'.$record->ID,
'Custom action',
"docustomaction",
['RecordID' => $record->ID]
)->addExtraClass(
'action-menu--handled'
);
}
public function getExtraData($gridField, $record, $columnName)
{
$field = $this->getCustomAction($gridField, $record);
if (!$field) {
return;
}
return $field->getAttributes();
}
public function getGroup($gridField, $record, $columnName)
{
return GridField_ActionMenuItem::DEFAULT_GROUP;
}
public function augmentColumns($gridField, &$columns)
{
if (!in_array('Actions', $columns)) {
$columns[] = 'Actions';
}
}
public function getColumnAttributes($gridField, $record, $columnName)
{
return ['class' => 'grid-field__col-compact'];
}
public function getColumnMetadata($gridField, $columnName)
{
if ($columnName === 'Actions') {
return ['title' => ''];
}
}
public function getColumnsHandled($gridField)
{
return ['Actions'];
}
public function getColumnContent($gridField, $record, $columnName)
{
$field = $this->getCustomAction($gridField, $record);
if (!$field) {
return;
}
return $field->Field();
}
public function getActions($gridField)
{
return ['docustomaction'];
}
public function handleAction(GridField $gridField, $actionName, $arguments, $data)
{
if ($actionName !== 'docustomaction') {
return;
}
// perform your action here
// output a success message to the user
Controller::curr()->getResponse()->setStatusCode(
200,
'Do Custom Action Done.'
);
}
}
I am struggling to add the custom icon for the button or specify the style class of the button. I can change the column class name. But I cannot find a way for the button. How can I do that?
you can achieve this using ->setAttribute('classNames', 'font-icon-<your-icon>');
i.e. for "edit" icon the code would looks like this:
return GridField_FormAction::create(
$gridField,
'CustomAction'.$record->ID,
'Custom action',
"docustomaction",
[
'RecordID' => $record->ID
]
)
->addExtraClass('action-menu--handled')
->setAttribute('classNames', 'font-icon-edit');
You can find all available icons on this page:
https://gbaumeister.github.io/ss4-icons/
I have this issue where I'm attempting to create a subrequest in Silex and basically forward my parameters to another controllers. Exhibit A is broken below (after attempts to refactor), and Exhibit B, the original version, works:
Exhibit A ($this->app is lost after creating the request):
class EntriesController {
private $app;
private $req;
public function __construct($app, $req) {
$this->app = $app;
$this->req = $req;
}
public function updateAction() {
//...
//$url defined here (eyesore-ingly long, so not shown)
$subRequest = Request::create($url, 'GET', $params, $this->req->cookies->all(), array(), $this->req->server->all());
//$this->app **no longer** exists here
return $this->app->handle($subRequest, HttpKernelInterface::SUB_REQUEST);
}
}
EntriesController instance is created below:
class AppControllerProvider implements ControllerProviderInterface {
public function connect(Application $app) {
$controllers = $app['controllers_factory'];
//...
$controllers->patch('/edit', function (Request $req) use ($app) {
$entriesCtrl = new \EntriesController($app, $req);
return $entriesCtrl->updateAction();
});
//...
}
Exhibit B (works just fine):
class AppControllerProvider implements ControllerProviderInterface {
public function connect(Application $app) {
$controllers = $app['controllers_factory'];
$controllers->patch('/edit', function (Request $req) use ($app) {
//...
//$url defined here
$subRequest = Request::create($url, 'GET', $params, $this->req->cookies->all(), array(), $this->req->server->all());
return $this->app->handle($subRequest, HttpKernelInterface::SUB_REQUEST);
}
//...
});
I basically just reorganized the logic from Exhibit B's 'PATCH' /edit method body into a controller class, and I passed the Silex Application instance $app to a new instance of the controller class.
The only difference between Exhibit A and Exhibit B as far as I can tell is that you instantiate a controller object in the path method callback. Maybe there is something wrong with how this controller is setup or a namespace issue? Shootin' in the dark here.
I can confirm that in my silex application the following code does not produce a null $app container:
GlobalControllerProvider.php
<?php
namespace Dev\Pub\Provider\Controller;
use Silex\Application;
use Silex\ControllerProviderInterface;
use Symfony\Component\HttpFoundation\Request;
class GlobalControllerProvider implements ControllerProviderInterface
{
public function connect(Application $app)
{
$controllers = $app['controllers_factory'];
$controllers
->get('/', 'Dev\Pub\Controller\GlobalController::indexAction')
->bind('homepage')
;
$controllers
->patch('/edit', function (Request $req) use ($app) {
$entriesCtrl = new \Dev\Pub\Controller\GlobalController();
return $entriesCtrl->updateAction($app, $req);
});
return $controllers;
}
}
GlobalController.php
<?php
namespace Dev\Pub\Controller;
use Silex\Application;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\HttpKernelInterface;
class GlobalController
{
public function indexAction(Application $app, Request $request)
{
return new Response($app['twig']->render('index.html.twig'));
}
public function updateAction(Application $app, Request $request)
{
$url = 'http://silex.local/index_dev.php/';
$params = array();
$subRequest = Request::create($url, 'GET', $params, $request->cookies->all(), array(), $request->server->all());
// outputs: 'Silex\Application'
error_log(print_r(get_class($app),1).' '.__FILE__.' '.__LINE__,0);
// outputs: 1
error_log(print_r(is_object($app),1).' '.__FILE__.' '.__LINE__,0);
return $app->handle($subRequest, HttpKernelInterface::SUB_REQUEST);
}
}
index.main.js
$(function(){
console.log('index.main.js');
$.ajax({
url: "http://silex.local/index_dev.php/edit",
method: "PATCH"
}).done(function( data ) {
console.log(data);
}).fail(function( data ) {
console.log(data);
});
});
How do I add a button to the backend of the CMS that fires an action? I can display the button where I want using:
public function getCMSFields()
{
$fields = parent::getCMSFields();
$fields->addFieldsToTab("Root.ButtonTest", array(
FormAction::create('doAction', 'Action button')
)
);
return $fields;
}
public function doAction()
{
//Do something
}
However the button added does nothing when clicked.
I've seen one example of how to put a button on the main action bar (next to save/publish) but that's not what I'm trying to do.
Looking at the only page of documentation I can find, do I need to do something within:
public function getCMSActions()
{
$actions = parent::getCMSActions();
//Something here?
}
It isn't very clear how to create the action that the button calls.
You'll have to extend/decorate LeftAndMain with your own extension and the action you want to call. Here's an example:
<?php
class MyExtension extends LeftAndMainExtension
{
private static $allowed_actions = array(
'doAction'
);
public function doAction($data, $form){
$className = $this->owner->stat('tree_class');
$SQL_id = Convert::raw2sql($data['ID']);
$record = DataObject::get_by_id($className, $SQL_id);
if(!$record || !$record->ID){
throw new SS_HTTPResponse_Exception(
"Bad record ID #" . (int)$data['ID'], 404);
}
// at this point you have a $record,
// which is your page you can work with!
// this generates a message that will show up in the CMS
$this->owner->response->addHeader(
'X-Status',
rawurlencode('Success message!')
);
return $this->owner->getResponseNegotiator()
->respond($this->owner->request);
}
}
Once you have written an extension like this, you'll have to apply it to LeftAndMain by adding the following to your mysite/_config/config.yml:
LeftAndMain:
extensions:
- MyExtension
That's it. Your doAction button should now actually do something!
Not sure if this is helpful, but here's how you can add action-buttons to a ModelAdmin.
(does reload the page)
...in the admin class:
public function getEditForm($id = null, $fields = null)
{
$form = parent::getEditForm($id, $fields);
$form
->Fields()
->fieldByName($this->sanitiseClassName($this->modelClass))
->getConfig()
->getComponentByType('GridFieldDetailForm')
->setItemRequestClass('MyGridFieldDetailForm_ItemRequest');
return $form;
}
MyGridFieldDetailForm_ItemRequest.php
class MyGridFieldDetailForm_ItemRequest extends GridFieldDetailForm_ItemRequest
{
function ItemEditForm()
{
$form = parent::ItemEditForm();
$formActions = $form->Actions();
$button = FormAction::create('myAction');
$button->setTitle('button label');
$button->addExtraClass('ss-ui-action-constructive');
$formActions->push($button);
$form->setActions($formActions);
return $form;
}
public function myAction(){ //do things }
}
I need to get a parameter value in my following twig extension class
namespace xxxx\WebBundle\Twig;
use Symfony\Component\HttpKernel\KernelInterface;
class MyExtension extends \Twig_Extension
{
public function getFilters()
{
return array(
new \Twig_SimpleFilter('affliate', array($this, 'urlFilter')),
);
}
public function urlFilter($url,$aff)
{
$separator = "?";
if (strpos($url,"?")!=false) {
$separator = "&";
}
$parse = parse_url($url);
//echo $parse['host'];
$app_url = $url.$separator.'tag='.$aff;
return $app_url;
}
public function getName()
{
return 'wishbot_extension';
}
}
In controller we can use like this $this->container->getParameter('contact_email');
But I need the value in twig extension class.
Inject the parameters as arguments into your twig extensions's constructor like this:
config.yml
services:
twig.extension.your_extension:
class: Vendor\YourBundle\Twig\Extension\YourExtension
arguments: [ %parameter1%, %parameter2% ]
tags:
- { name: twig.extension }
YourExtension.php
protected $parameter1;
protected $parameter1;
public function __construct($parameter1, $parameter2)
{
$this->parameter1 = $parameter1;
$this->parameter2 = $parameter2;
}
// ....
public function urlFilter($url,$aff)
{
// access the parameters using $this->parameter1
}
I've been searching and haven't really found much useful information. I'm looking to use the symfony2 routing component (and also yaml component) with my own personal framework but haven't found any documentation on basic setup. The documentation on the symfony site does a good job of explaining how to use the component but not much in the way of standalone setup.
Can anyone recommend a good place to start that could explain how to setup individual symfony2 components?
I ended up looking at the documentation on the symfony site, as well as the source code on github (Route.php, RouteCollection.php, RouteCompiler.php) and came up with my own basic router.
Just like symfony, I allow 4 arguments to be passed to the route class -> 1) the pattern, 2) the default controller/action, 3) regex requirements for each variable in the pattern, and 4) any options - I haven't coded for this yet as it's not in my requirements.
My main/front controller (index.php) only talks to the static Router class which has access to the other route classes in the lib\route namespace.
Router::Map basically compiles a regex string (along with default controller/action and variable names) that gets passed to the compiledRouteCollection which is used in Router::_Process to match the httpRequest against. From there, if there is a match in the process method then i set the controller/action/args based on the values of the matched compiledRoute default controller/action. If there is not a preg_match then i use the default controller/action/args from the request object. The rest is cake...
I hope someone finds this useful and it's able to save them the time I spent today working on this. Cheers!
index.php
require_once 'config/config.php';
require_once 'lib/autoload.php';
lib\Router::Map(
'users_username_id',
'users/{username}/{id}',
array('controller' => 'testController', 'action' => 'users')
);
lib\Router::Route(new lib\Request());
router.php
namespace lib;
class Router {
protected static $_controller;
protected static $_action;
protected static $_args;
protected static $_compiledRouteCollection;
private static $_instance;
private function __construct() {
self::$_compiledRouteCollection = new \lib\route\CompiledRouteCollection();
}
public static function Singleton() {
if(!isset(self::$_instance)) {
$className = __CLASS__;
self::$_instance = new $className;
}
return self::$_instance;
}
public static function Route(Request $request, $resetProperties = false) {
self::Singleton();
self::_Process($request,$resetProperties);
$className = '\\app\\controllers\\' . self::$_controller;
if(class_exists($className, true)) {
self::$_controller = new $className;
if(is_callable(array(self::$_controller, self::$_action))) {
if(!empty(self::$_args)) {
call_user_func_array(array(self::$_controller, self::$_action), self::$_args);
} else {
call_user_func(array(self::$_controller, self::$_action));
}
return;
}
}
self::Route(new \lib\Request('error'),true);
}
public static function Map($name, $pattern, array $defaults, array $requirements = array(), array $options = array()) {
self::Singleton();
$route = new \lib\route\Route($pattern,$defaults,$requirements,$options);
$compiledRoute = $route->Compile();
self::$_compiledRouteCollection->Add($name,$compiledRoute);
}
private static function _Process(Request $request, $resetProperties = false) {
$routes = array();
$routes = self::$_compiledRouteCollection->routes;
foreach($routes as $route) {
preg_match($route[0]['regex'], $request->GetRequest(), $matches);
if(count($matches)) {
array_shift($matches);
$args = array();
foreach($route[0]['variables'] as $variable) {
$args[$variable] = array_shift($matches);
}
self::$_controller = (!isset(self::$_controller) || $resetProperties) ? $route[0]['defaults']['controller'] : self::$_controller;
self::$_action = (!isset(self::$_action) || $resetProperties) ? $route[0]['defaults']['action'] : self::$_action;
self::$_args = (!isset(self::$_args) || $resetProperties) ? $args : self::$_args;
return;
}
}
self::$_controller = (!isset(self::$_controller) || $resetProperties) ? $request->GetController() : self::$_controller;
self::$_action = (!isset(self::$_action) || $resetProperties) ? $request->GetAction() : self::$_action;
self::$_args = (!isset(self::$_args) || $resetProperties) ? $request->GetArgs() : self::$_args;
}
}
request.php
namespace lib;
class Request {
protected $_controller;
protected $_action;
protected $_args;
protected $_request;
public function __construct($urlPath = null) {
$this->_request = $urlPath !== null ? $urlPath : $_SERVER['REQUEST_URI'];
$parts = explode('/', $urlPath !== null ? $urlPath : $_SERVER['REQUEST_URI']);
$parts = array_filter($parts);
$this->_controller = (($c = array_shift($parts)) ? $c : 'index').'Controller';
$this->_action = ($c = array_shift($parts)) ? $c : 'index';
$this->_args = (isset($parts[0])) ? $parts : array();
}
public function GetRequest() {
return $this->_request;
}
public function GetController() {
return $this->_controller;
}
public function GetAction() {
return $this->_action;
}
public function GetArgs() {
return $this->_args;
}
}
route.php
namespace lib\route;
class Route {
private $_pattern;
private $_defaults;
private $_requirements;
public $_options;
public function __construct($pattern, array $defaults = array(), array $requirements = array(), array $options = array()) {
$this->SetPattern($pattern);
$this->SetDefaults($defaults);
$this->SetRequirements($requirements);
$this->SetOptions($options);
}
public function SetPattern($pattern) {
$this->_pattern = trim($pattern);
if($this->_pattern[0] !== '/' || empty($this->_pattern)) {
$this->_pattern = '/'.$this->_pattern;
}
}
public function GetPattern() {
return $this->_pattern;
}
public function SetDefaults(array $defaults) {
$this->_defaults = $defaults;
}
public function GetDefaults() {
return $this->_defaults;
}
public function SetRequirements(array $requirements) {
$this->_requirements = array();
foreach($requirements as $key => $value) {
$this->_requirements[$key] = $this->_SanitizeRequirement($key,$value);
}
}
public function GetRequirements() {
return $this->_requirements;
}
public function SetOptions(array $options) {
$this->_options = array_merge(
array('compiler_class' => 'lib\\route\\RouteCompiler'),
$options
);
}
public function GetOptions() {
return $this->_options;
}
public function GetOption($name) {
return isset($this->_options[$name]) ? $this->_options[$name] : null;
}
private function _SanitizeRequirement($key, $regex) {
if($regex[0] == '^') {
$regex = substr($regex, 1);
}
if(substr($regex, -1) == '$') {
$regex = substr($regex,0,-1);
}
return $regex;
}
public function Compile() {
$className = $this->GetOption('compiler_class');
$routeCompiler = new $className;
$compiledRoute = array();
$compiledRoute = $routeCompiler->Compile($this);
return $compiledRoute;
}
}
routeCompiler.php
namespace lib\route;
class RouteCompiler {
//'#\/tellme\/users\/[\w\d_]+\/[\w\d_]+#'
public function Compile(Route $route) {
$pattern = $route->GetPattern();
$requirements = $route->GetRequirements();
$options = $route->GetOptions();
$defaults = $route->GetDefaults();
$len = strlen($pattern);
$tokens = array();
$variables = array();
$pos = 0;
$regex = '#';
preg_match_all('#.\{([\w\d_]+)\}#', $pattern, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER);
if(count($matches)) {
foreach($matches as $match) {
if($text = substr($pattern, $pos, $match[0][1] - $pos)) {
$regex .= str_replace('/', '\/', $text).'\/';
}
if($var = $match[1][0]) {
if(isset($requirements[$var])) {
$regex .= '('.$requirements[$var].')\/';
} else {
$regex .= '([\w\d_]+)\/';
}
$variables[] = $match[1][0];
}
$pos = $match[0][1] + strlen($match[0][0]);
}
$regex = rtrim($regex,'\/').'#';
} else {
$regex .= str_replace('/', '\/', $pattern).'#';
}
$tokens[] = array(
'regex' => $regex,
'variables' => $variables,
'defaults' => $defaults
);
return $tokens;
}
}
compiledRouteCollection.php
namespace lib\route;
class CompiledRouteCollection {
public $routes;
public function __construct() {
$this->routes = array();
}
public function Add($name, array $route) {
$this->routes[$name] = $route;
}
}