I have a controller:
class PageCrudController extends CrudController
{
public function search()
{
$res = parent::search();
return $res;
}
public function setup()
{
/*
|--------------------------------------------------------------------------
| CrudPanel Basic Information
|--------------------------------------------------------------------------
*/
$this->crud->setModel('App\Models\Page');
$this->crud->setRoute(config('backpack.base.route_prefix') . '/page');
$this->crud->setEntityNameStrings('page', 'pages');
$this->crud->setListView('vendor.backpack.crud.page.list');
$this->search();
/*
|--------------------------------------------------------------------------
| CrudPanel Configuration
|--------------------------------------------------------------------------
*/
// Select all roots elements with their children
$pagesTree = collect([]);
$roots = Page::where('parent_id', null)->get();
$roots->each(function ($value) use(&$pagesTree) {
$tree = $value->getDescendantsAndSelf();
$pagesTree = $pagesTree->merge($tree);
});
In the controller I have the variable $pagesTree. It contains sorted data. I need to show it on a view page of list instead of the default data.
$this->crud->orderBy is not suitable. Because of as you can see, here I have special order of items. I have got it with the help of this package https://github.com/etrepat/baum#inserting-nodes.
Related
create a module for custom column but still filter is not working
namespace Vendore\Modulename\Model\ResourceModel\modulename\Grid;
use Magento\Framework\Data\Collection\Db\FetchStrategyInterface as FetchStrategy;
use Magento\Framework\Data\Collection\EntityFactoryInterface as EntityFactory;
use Magento\Framework\Event\ManagerInterface as EventManager;
use Magento\Framework\View\Element\UiComponent\DataProvider\SearchResult;
use Psr\Log\LoggerInterface as Logger;
class Collection extends SearchResult
public function __construct(
EntityFactory $entityFactory,
Logger $logger,
FetchStrategy $fetchStrategy,
EventManager $eventManager,
$mainTable = 'unicommerce_sync_order',
$resourceModel = 'vendorename\modulename\Model\ResourceModel\modulename',
$identifierName = null,
$connectionName = null
) {
parent::__construct($entityFactory, $logger, $fetchStrategy, $eventManager, $mainTable, $resourceModel, $identifierName, $connectionName);
}
/**
* #return Collection|void
*/
protected function _initSelect()
{
$this->addFilterToMap('created_at', 'salesOrder.created_at');
parent::_initSelect();
}
protected function _renderFiltersBefore()
{
$this->getSelect()
->joinLeft(
['salesOrder' => $this->getConnection()->getTableName('sales_order')],
'main_table.magento_order_id = salesOrder.entity_id',
['created_at'=>'salesOrder.created_at']
);
//echo $this->getSelect();
parent::_renderFiltersBefore();
}
Note : create_at column date get proper but filter is not working
please check my code and let me know if any issue
Thanks
I've created my own service class and I have a function inside it, handleRedirect() that's supposed to perform some minimal logical check before choosing to which route to redirect.
class LoginService
{
private $CartTable;
private $SessionCustomer;
private $Customer;
public function __construct(Container $SessionCustomer, CartTable $CartTable, Customer $Customer)
{
$this->SessionCustomer = $SessionCustomer;
$this->CartTable = $CartTable;
$this->Customer = $Customer;
$this->prepareSession();
$this->setCartOwner();
$this->handleRedirect();
}
public function prepareSession()
{
// Store user's first name
$this->SessionCustomer->offsetSet('first_name', $this->Customer->first_name);
// Store user id
$this->SessionCustomer->offsetSet('customer_id', $this->Customer->customer_id);
}
public function handleRedirect()
{
// If redirected to log in, or if previous page visited before logging in is cart page:
// Redirect to shipping_info
// Else
// Redirect to /
}
public function setCartOwner()
{
// GET USER ID FROM SESSION
$customer_id = $this->SessionCustomer->offsetGet('customer_id');
// GET CART ID FROM SESSION
$cart_id = $this->SessionCustomer->offsetGet('cart_id');
// UPDATE
$this->CartTable->updateCartCustomerId($customer_id, $cart_id);
}
}
This service is invoked in the controller after a successful login or registration. I'm not sure what's the best way to access redirect()->toRoute(); from here (or if I should do it here).
Also if you have other comments on how my code is structured please feel free to leave them.
Using plugins within your services is a bad idea as they require a controller to be set. When a service is created and you inject a plugin it has no idea of the controller instance so it will result in an error exception. If you want to redirect the user you might just edit the response object as the redirect plugin does.
Notice that I stripped the code to keep the example clear and simple.
class LoginServiceFactory implements FactoryInterface
{
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
return new LoginService($container->get('Application')->getMvcEvent());
}
}
class LoginService
{
/**
* #var \Zend\Mvc\MvcEvent
*/
private $event;
/**
* RedirectService constructor.
* #param \Zend\Mvc\MvcEvent $event
*/
public function __construct(\Zend\Mvc\MvcEvent $event)
{
$this->event = $event;
}
/**
* #return Response|\Zend\Stdlib\ResponseInterface
*/
public function handleRedirect()
{
// conditions check
if (true) {
$url = $this->event->getRouter()->assemble([], ['name' => 'home']);
} else {
$url = $this->event->getRouter()->assemble([], ['name' => 'cart/shipping-info']);
}
/** #var \Zend\Http\Response $response */
$response = $this->event->getResponse();
$response->getHeaders()->addHeaderLine('Location', $url);
$response->setStatusCode(302);
return $response;
}
}
Now from within your controller you can do the following:
return $loginService->handleRedirect();
In a custom extbase extension, I need to call a show action, passing it another value than uid (this is a continuation of Use other than primary key as RealURL id_field).
As the value "other than uid" is not resolved, it results in the exception http://wiki.typo3.org/Exception/CMS/1297759968
EDIT: here's the current working (but ugly) Controller code:
/**
* ItemController
*/
class ItemController extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionController {
/**
* itemRepository
*
* #var \STUBR\Weiterbildung\Domain\Repository\ItemRepository
* #inject
*/
protected $itemRepository = NULL;
/**
* action list
*
* #return void
*/
public function listAction(\STUBR\Weiterbildung\Domain\Model\Item $item=null) {
if (!empty(\TYPO3\CMS\Core\Utility\GeneralUtility::_GET('tx_weiterbildung_pi1'))){
$this->forward('show');
}
$items = $this->itemRepository->findAll();
$this->view->assign('items', $items);
}
/**
* action show
*
* #param \STUBR\Weiterbildung\Domain\Model\Item $item
* #return void
*/
public function showAction(\STUBR\Weiterbildung\Domain\Model\Item $item=null) {
$tx_weiterbildung_pi1_get = \TYPO3\CMS\Core\Utility\GeneralUtility::_GET('tx_weiterbildung_pi1');
if (!empty($tx_weiterbildung_pi1_get)){
$dfid = intval($tx_weiterbildung_pi1_get['durchfuehrungId']);
}
$items = $this->itemRepository->findByDurchfuehrungId($dfid);
// helpful:
//\TYPO3\CMS\Extbase\Utility\DebuggerUtility::var_dump($item);
$this->view->assign('item', $items[0]);
}
}
PS here are the 5 lines that could be used in the Repository if the magical method wouldn't work:
//public function findByDurchfuehrungId($dfid) {
// $query = $this->createQuery();
// $query->matching($query->equals('durchfuehrungId', $dfid));
// return $query->execute();
//}
Yes, when you're using actions with model binding in param it will always look for object by field defined as ID - in our case it's always uid, but remember, that you do not need to bind model automatically, as you can retrive it yourself.
Most probably you remember, that some time ago I advised to use <f:link.page additionalParams="{originalUid:myObj.originalUid}"Click here</f:link.page> instead of <f:link.action...>
In that case your show action would look like this:
public function showAction() {
$item = $this->itemRepository->findByOriginalUid(intval(GeneralUtility::_GET('originalUid')));
$this->view->assign('item', $item);
}
Where findByOriginalUid should work magically without declaration, but even if it doesn't it's just matter of 5 lines in the repo ;)
Other sample
According to the code you pasted I'd use it rather like this, in this case listAction gets a role of dispatcher for whole plugin:
public function listAction() {
// access get param in array
$tx_weiterbildung_pi1_get = \TYPO3\CMS\Core\Utility\GeneralUtility::_GET('tx_weiterbildung_pi1');
$dfId = intval($tx_weiterbildung_pi1_get['durchfuehrungId']);
if ($dfId > 0) { // tx_weiterbildung_pi1 exists and is positive, that means you want to go to showAction
$item = $this->itemRepository->findByDurchfuehrungId($dfId);
if (!is_null($item)) { // Forward to showAction with found $item
$this->forward('show', null, null, array('item' => $item));
}else { // Or redirect to the view URL after excluding single item ID from GET params
$this->redirectToUri($this->uriBuilder->setArgumentsToBeExcludedFromQueryString(array('tx_weiterbildung_pi1'))->build());
}
}
// No `tx_weiterbildung_pi1` param, so it should be displayed as a listAction
$items = $this->itemRepository->findAll();
$this->view->assign('items', $items);
}
/**
* #param \STUBR\Weiterbildung\Domain\Model\Item $item
*/
public function showAction(\STUBR\Weiterbildung\Domain\Model\Item $item = null) {
$this->view->assign('item', $item);
}
Your finder should also getFirst() object if possible:
public function findByDurchfuehrungId($DfId) {
$query = $this->createQuery();
$query->matching($query->equals('durchfuehrungId', $DfId));
return $query->execute()->getFirst();
}
I wonder why no one ever asked this question.
Every zend Action function in controller class has 3 paramters, namely 'module', 'controller', and 'action'.
What happens, when I get a parameter named 'action' from a form or url, for example "?action=edit" ??
I tested it: action holds its value from router, not 'edit'.
public function someAction() {
$params = $this->getRequest()->getParams();
...
How could I pass the parameter named "action", if I had to ??
Thanks in advance.
The default route is Zend_Controller_Router_Route_Module which uses default keys for module, controller, & action:
protected $_moduleKey = 'module';
protected $_controllerKey = 'controller';
protected $_actionKey = 'action';
// ...
/**
* Set request keys based on values in request object
*
* #return void
*/
protected function _setRequestKeys()
{
if (null !== $this->_request) {
$this->_moduleKey = $this->_request->getModuleKey();
$this->_controllerKey = $this->_request->getControllerKey();
$this->_actionKey = $this->_request->getActionKey();
}
if (null !== $this->_dispatcher) {
$this->_defaults += array(
$this->_controllerKey => $this->_dispatcher->getDefaultControllerName(),
$this->_actionKey => $this->_dispatcher->getDefaultAction(),
$this->_moduleKey => $this->_dispatcher->getDefaultModule()
);
}
$this->_keysSet = true;
}
/**
* Matches a user submitted path. Assigns and returns an array of variables
* on a successful match.
*
* If a request object is registered, it uses its setModuleName(),
* setControllerName(), and setActionName() accessors to set those values.
* Always returns the values as an array.
*
* #param string $path Path used to match against this routing map
* #return array An array of assigned values or a false on a mismatch
*/
public function match($path, $partial = false)
{
$this->_setRequestKeys();
$values = array();
$params = array();
if (!$partial) {
$path = trim($path, self::URI_DELIMITER);
} else {
$matchedPath = $path;
}
if ($path != '') {
$path = explode(self::URI_DELIMITER, $path);
if ($this->_dispatcher && $this->_dispatcher->isValidModule($path[0])) {
$values[$this->_moduleKey] = array_shift($path);
$this->_moduleValid = true;
}
if (count($path) && !empty($path[0])) {
$values[$this->_controllerKey] = array_shift($path);
}
if (count($path) && !empty($path[0])) {
$values[$this->_actionKey] = array_shift($path);
}
if ($numSegs = count($path)) {
for ($i = 0; $i < $numSegs; $i = $i + 2) {
$key = urldecode($path[$i]);
$val = isset($path[$i + 1]) ? urldecode($path[$i + 1]) : null;
$params[$key] = (isset($params[$key]) ? (array_merge((array) $params[$key], array($val))): $val);
}
}
}
if ($partial) {
$this->setMatchedPath($matchedPath);
}
$this->_values = $values + $params;
return $this->_values + $this->_defaults;
}
You can see that the default module route has default keys for mvc params, however, it will use the keys set by the request object if it exists and we can modify these keys.
e.g. in your bootstrap:
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
{
protected function _initRequestKeys()
{
$this->bootstrap('frontcontroller');
$frontController = $this->getResource('frontcontroller');
/* #var $frontController Zend_Controller_Front */
$request = new Zend_Controller_Request_Http();
// change action key
$request->setActionKey("new_action_key");
// change module
$request->setModuleKey("new_module_key");
// change controller
$request->setControllerKey("new_controller_key");
// don't forget to set the configured request
// object to the front controller
$frontController->setRequest($request);
}
}
Now you can use module, controller, & action as $_GET params.
After a little testing it seems that how you pass the key "action" matters.
If you try and pass a parameter named "action" with $this->_request->getParams() you will get the controller action value key pair.
If you pass the "action" key from a form with $form->getValues() you will retrieve the value from the form element named "action".
As with so many things, your use case determines how you need to handle the situation.
Good Luck.
i wonder if many of my pages may use a FlashMessenger, whats the best way to automatically render out all messages say at the top of the page (like those here in SO, telling the user they got a badge etc)
I have this view helper:
<?php
class Zf_View_Helper_FlashMessenger extends Zend_View_Helper_Abstract
{
/**
* #var Zend_Controller_Action_Helper_FlashMessenger
*/
private $_flashMessenger = null;
/**
* Display Flash Messages.
*
* #param string $key Message level for string messages
* #param string $template Format string for message output
* #return string Flash messages formatted for output
*/
public function flashMessenger($key = 'success',
$template='<div id="flash-message" style="display:none"><p class="%s">%s</p></div>')
{
$flashMessenger = $this->_getFlashMessenger();
//get messages from previous requests
$messages = $flashMessenger->getMessages();
//add any messages from this request
if ($flashMessenger->hasCurrentMessages()) {
$messages = array_merge(
$messages,
$flashMessenger->getCurrentMessages()
);
//we don't need to display them twice.
$flashMessenger->clearCurrentMessages();
}
//initialise return string
$output ='';
//process messages
foreach ($messages as $message)
{
if (is_array($message)) {
list($key,$message) = each($message);
}
$output .= sprintf($template,$key,$message);
}
return $output;
}
/**
* Lazily fetches FlashMessenger Instance.
*
* #return Zend_Controller_Action_Helper_FlashMessenger
*/
public function _getFlashMessenger()
{
if (null === $this->_flashMessenger) {
$this->_flashMessenger =
Zend_Controller_Action_HelperBroker::getStaticHelper(
'FlashMessenger');
}
return $this->_flashMessenger;
}
}
In my controller I have this:
if($form->isValid($formData))
{
$Model = $this->getModel();
$id = $Model->add($formData);
$this->_helper->flashMessenger('The category has been inserted.');
$this->_helper->redirector('list');
}
So, in my view I just echo the helper:
<?php echo $this->flashMessenger(); ?>
You could use a preDispatch-Plugin to inject the content of the FlashMessenger into your view and output it in your layout template.