Custom Page in SilverStripe Admin - php

I want to create a fully custom Page in SilverStripe's (v3.4) Admin.
It should just display a Form (consisting of an UploadField and a FormAction to submit the File) which submits to a custom action.
So far this is my Code.
class ImporterAdmin extends LeftAndMain {
private static $url_segment = 'importer';
private static $url_rule = '/$Action';
private static $menu_title = 'Produkt Import';
private static $menu_icon = 'mysite/icons/pimport-icon.png';
private static $allowed_actions = array(
"run_import" => true
);
public function init() {
parent::init();
// Gather required client side resources
Requirements::javascript(CMS_DIR . '/javascript/CMSMain.EditForm.js');
}
public function index($req){
return $this->renderWith("ImporterAdmin_Content");
}
public function getResponseNegotiator() {
// Get the reponse negotiator
$negotiator = parent::getResponseNegotiator();
$controller = $this;
// Set the callback template
$negotiator->setCallback('CurrentForm', function() use(&$controller) {
return $controller->renderWith('ImporterAdmin_Content');
});
return $negotiator;
}
public function getImportForm($id = null, $fields = null) {
$fields = new FieldList(
UploadField::create("XMLFile", "XML File")
);
// Get the form actions
$actions = new FieldList(
FormAction::create('run_import', _t('CMSMain.SAVE', 'Save'))->addExtraClass('ss-ui-action-constructive')->setAttribute('data-icon', 'accept')
);
// Create the form
$form = CMSForm::create($this, 'ImportForm', $fields, $actions)->setHTMLID('Form_ImportForm');
// Set the response action, mostly for returning the correst template
$form->setResponseNegotiator($this->getResponseNegotiator());
// Add required classes to the form
$form->addExtraClass('cms-content center cms-edit-form');
// Convert buttons to button tags (apprently required for jQuery styling)
$actions = $actions->dataFields();
if($actions) {
foreach($actions as $action) {
$action->setUseButtonTag(true);
}
}
return $form;
}
/**
* Save the settings
* #param array $data The form data
* #param CMSForm $form The form object
* #return SS_HTTPResponse The SilverStripe viewresponse
*/
public function run_import($data, $form) {
print_r($data, $form);
}
But it displays nothing...
The ImportForm.ss file just contains the Variable $ImportForm

Related

How to share data between classes in PHP (PrestaShop 1.7 module)

I'm trying to create a PrestaShop module that will have some logic triggered by an action hook (e.g. actionValidateOrder) and temporarily store the result of that logic so it can be used when a display hook is triggered (e.g. displayHeader).
In my main class I am assigning a Store class singleton to it as $this is being passed onto classes triggered on hooks:
class PrestashopCustomModule extends Module
{
public function __construct()
{
/* ... */
parent::__construct();
$this->customStore = CustomStore::getInstance();
/* ... */
}
/* ... */
public function hookActionValidateOrder($params)
{
$hook = new HookActionValidateOrder($this, $this->context);
$hook->setParams($params);
return $hook->run();
}
public function hookDisplayHeader($params)
{
$hook = new HookDisplayHeader($this, $this->context);
$hook->setParams($params);
return $hook->run();
}
}
This is the Store class:
class Store
{
private static $instance = null;
private $store = [];
private function __construct()
{
}
public static function getInstance()
{
if (self::$instance === null) {
self::$instance = new self();
}
return self::$instance;
}
public function push($code)
{
$this->store[] = $code;
return;
}
public function get()
{
return $this->store;
}
}
When I $this->module->customStore->push('something') in the action hook I see it in the array within Store but when later the display hook calls $this->module->customStore->get() the array within is empty again.
What am I doing wrong, why does it not persist between those calls even though the Store class is a singleton?

SilverStripe 3.6.1 - Use renderWith to display a loop of data objects

I'm working on rendering an array of data objects to a template using renderWith() but having some difficulty. What I have now does not render anything in the specified template except for whatever is in the basic Content WYSIWYG editor.
As a side note, I'm using the shortcodable module for reference, hence why the code is setup the way it is.
This is the function I have setup in a data object called Drawer which is meant to display a list of DrawerContents into the FaqLisitng template:
public function parse_shortcode($attributes, $content, $parser, $shortcode)
{
$drawers = "";
if (isset($attributes['Drawers'])) {
$Idx = explode(',', $attributes['Drawers']);
$drawerIdx = [];
foreach ($Idx as $did) {
$d = Drawer::get()
->filter('ID', $did)
->first();
if ($d->ID) {
array_push($drawerIdx, $d->ID);
}
}
$drawers = implode(',', $drawerIdx);
}
$drawerContents = DrawerContent::get()->filter(
array("DrawerID" => $drawers));
$drawerContentArray = array();
foreach($drawerContents as $dca){
$drawerContentArray = new ArrayData(array(
'FaqQuestion' => $dca->FaqQuestion,
'FaqAnswer' => $dca->FaqAnswer
));
}
return $drawerContentArray->renderWith('FaqListing');
}
And this is the FaqListing template contents:
<% with $getFaqListing %>
<strong>$FaqQuestion</strong><br/>
$FaqAnswer
<% end_with %>
I noticed that if I remove the with block, I do get the last entry for each DrawerContent data object that is being called in the parse_shorcode function, only the first entry--not the entire list for each DrawerContent data object. I get the same results if I use a loop instead of with.
I'm not sure what I'm doing wrong, but I feel like I'm close to getting things setup correctly.
For reference, in case it may help in providing a solution, here is the entire code for the Drawer data object:
<?php
class Drawer extends DataObject {
private static $db = array(
'FaqCategoryName' => 'varchar(250)',
);
private static $summary_fields = array(
'FaqCategoryName' => 'FAQ Category Name',
);
private static $has_many = array(
'DrawerContents' => 'DrawerContent',
);
/**
* Parse the shortcode and render as a string, probably with a template
Add a comment to this line
* #param array $attributes the list of attributes of the shortcode
* #param string $content the shortcode content
* #param ShortcodeParser $parser the ShortcodeParser instance
* #param string $shortcode the raw shortcode being parsed
* #return String
**/
public function parse_shortcode($attributes, $content, $parser, $shortcode) {
$drawers = "";
if (isset($attributes['Drawers'])) {
$Idx = explode(',', $attributes['Drawers']);
$drawerIdx = [];
foreach ($Idx as $did) {
$d = Drawer::get()
->filter('ID', $did)
->first();
if ($d->ID) {
array_push($drawerIdx, $d->ID);
}
}
$drawers = implode(',', $drawerIdx);
}
$drawerContents = DrawerContent::get()->filter(
array("DrawerID" => $drawers));
$drawerContentArray = array();
foreach($drawerContents as $dca){
$drawerContentArray = new ArrayData(array(
'FaqQuestion' => $dca->FaqQuestion,
'FaqAnswer' => $dca->FaqAnswer
));
}
return $drawerContentArray->renderWith('FaqListing');
}
public function getShortcodableRecords() {
return Drawer::get()
->map('ID')
->toArray();
}
/**
* Returns a list of fields for editing the shortcode's attributes
* in the insert shortcode popup window
*
* #return Fieldlist
**/
public function getShortcodeFields()
{
$all = Drawer::get()->map('ID');
$DrawersMultiList = ListboxField::create("Drawers", "Drawers")
->setMultiple(true)
->setSource($all);
return FieldList::create([
$DrawersMultiList,
]);
}
public function canView($member = null){
return true;
}
public function canEdit($member = null) {
return true;
}
public function canCreate($member = null) {
return true;
}
public function getTitle(){
$title = $this->FaqCategoryName;
return $title;
}
}
class DrawerAdmin extends ModelAdmin {
private static $managed_models = array('Drawer');
private static $url_segment = 'Drawers';
private static $menu_title = 'Drawers';
}
And code for the DrawerContent data object:
<?php
class DrawerContent extends DataObject {
private static $db = array(
'FaqQuestion' => 'varchar',
'FaqAnswer' => 'HTMLText',
);
private static $has_one = array(
'Drawer' => 'Drawer',
);
private static $summary_fields = array(
'FaqQuestion' => 'FAQ Question',
);
}
And the $getFaqListing function, which is created in Page.php
public function getFaqListing() {
return DrawerContent::get();
}

Joomla Comonent update data

I'm working on a Joomla 3 component. Currently I'm programming the backend. I'm having a form to add new data and it is working quite well. But when I want to update the data the component creates a new item instead of updating the existing.
I was searching for position which let Joomla know, that this is an update, but without success.
So my question: what is the information that makes Joomla updating the data?
My Code:
Table:ia.php
class mkTableia extends JTable
{
/**
* Constructor
*
* #param object Database connector object
*/
function __construct(&$db)
{
parent::__construct('#__tbl_ia', 'ID', $db);
}
}
Model: ia.php
class mkModelia extends JModelAdmin
{
public function getTable($type = 'ia', $prefix = 'mkTable', $config = array())
{
return JTable::getInstance($type, $prefix, $config);
}
public function getForm($data = array(), $loadData = true)
{
// Get the form.
$form = $this->loadForm('com_mk.ia', 'ia',
array('control' => 'jform', 'load_data' => $loadData));
if (empty($form))
{
return false;
}
return $form;
}
protected function loadFormData()
{
// Check the session for previously entered form data.
$data = JFactory::getApplication()->getUserState('com_mk.edit.ia.data', array());
if (empty($data))
{
$data = $this->getItem();
}
return $data;
}
}
View:view.html.php
class mkViewia extends JViewLegacy
{
/**
* display method of Hello view
* #return void
*/
public function display($tpl = null)
{
// get the Data
$form = $this->get('Form');
$item = $this->get('Item');
// Check for errors.
if (count($errors = $this->get('Errors')))
{
JError::raiseError(500, implode('<br />', $errors));
return false;
}
// Assign the Data
$this->form = $form;
$this->item = $item;
// Set the toolbar
$this->addToolBar();
// Display the template
parent::display($tpl);
}
/**
* Setting the toolbar
*/
protected function addToolBar()
{
$input = JFactory::getApplication()->input;
$input->set('hidemainmenu', true);
$isNew = ($this->item->ID == 0);
JToolBarHelper::title($isNew ? JText::_('COM_MK_MANAGER_MK_NEW')
: JText::_('COM_MK_MANAGER_MK_EDIT'));
JToolBarHelper::save('IA.save');
JToolBarHelper::cancel('IA.cancel', $isNew ? 'JTOOLBAR_CANCEL'
: 'JTOOLBAR_CLOSE');
}
}

Sub views (layouts, templates) in Slim php framework

I'm trying out the Slim php framework
Is it possible to have layouts or sub views in Slim? I'd like to use a view file as a template with variables as placeholders for other views loaded separately.
How would I do that?
filename: myview.php
<?php
class myview extends Slim_View
{
static protected $_layout = NULL;
public static function set_layout($layout=NULL)
{
self::$_layout = $layout;
}
public function render( $template ) {
extract($this->data);
$templatePath = $this->getTemplatesDirectory() . '/' . ltrim($template, '/');
if ( !file_exists($templatePath) ) {
throw new RuntimeException('View cannot render template `' . $templatePath . '`. Template does not exist.');
}
ob_start();
require $templatePath;
$html = ob_get_clean();
return $this->_render_layout($html);
}
public function _render_layout($_html)
{
if(self::$_layout !== NULL)
{
$layout_path = $this->getTemplatesDirectory() . '/' . ltrim(self::$_layout, '/');
if ( !file_exists($layout_path) ) {
throw new RuntimeException('View cannot render layout `' . $layout_path . '`. Layout does not exist.');
}
ob_start();
require $layout_path;
$_html = ob_get_clean();
}
return $_html;
}
}
?>
example index.php:
<?php
require 'Slim/Slim.php';
require 'myview.php';
// instantiate my custom view
$myview = new myview();
// seems you need to specify during construction
$app = new Slim(array('view' => $myview));
// specify the a default layout
myview::set_layout('default_layout.php');
$app->get('/', function() use ($app) {
// you can override the layout for a particular route
// myview::set_layout('index_layout.php');
$app->render('index.php',array());
});
$app->run();
?>
default_layout.php:
<html>
<head>
<title>My Title</title>
</head>
<body>
<!-- $_html contains the output from the view -->
<?= $_html ?>
</body>
</html>
The slim framework makes use of other templating engines such as Twig or Smarty so as long as you choose a templating engine that allows subviews, then it'll work. For more info on view templating in Slim, check here.
I'm working with my View:
class View extends \Slim\View
{
protected $layout;
public function setLayout($layout)
{
$this->layout = $layout;
}
public function render($template)
{
if ($this->layout){
$content = parent::render($template);
$this->setData(array('content' => $content));
return parent::render($this->layout);
} else {
return parent::render($template);
}
}
}
You may add some method like setLayoutData(..) or appendLayoutData(..)
Few minutes ago:
class View extends \Slim\View
{
/** #var string */
protected $layout;
/** #var array */
protected $layoutData = array();
/**
* #param string $layout Pathname of layout script
*/
public function setLayout($layout)
{
$this->layout = $layout;
}
/**
* #param array $data
* #throws \InvalidArgumentException
*/
public function setLayoutData($data)
{
if (!is_array($data)) {
throw new \InvalidArgumentException('Cannot append view data. Expected array argument.');
}
$this->layoutData = $data;
}
/**
* #param array $data
* #throws \InvalidArgumentException
*/
public function appendLayoutData($data)
{
if (!is_array($data)) {
throw new \InvalidArgumentException('Cannot append view data. Expected array argument.');
}
$this->layoutData = array_merge($this->layoutData, $data);
}
/**
* Render template
*
* #param string $template Pathname of template file relative to templates directory
* #return string
*/
public function render($template)
{
if ($this->layout){
$content = parent::render($template);
$this->appendLayoutData(array('content' => $content));
$this->data = $this->layoutData;
$template = $this->layout;
$this->layout = null; // allows correct partial render in view, like "<?php echo $this->render('path to parial view script'); ?>"
return parent::render($template);;
} else {
return parent::render($template);
}
}
}
With Slim 3
namespace Slim;
use Psr\Http\Message\ResponseInterface;
class View extends Views\PhpRenderer
{
protected $layout;
public function setLayout($layout)
{
$this->layout = $layout;
}
public function render(ResponseInterface $response, $template, array $data = [])
{
if ($this->layout){
$viewOutput = $this->fetch($template, $data);
$layoutOutput = $this->fetch($this->layout, array('content' => $viewOutput));
$response->getBody()->write($layoutOutput);
} else {
$output = parent::render($response, $template, $data);
$response->getBody()->write($output);
}
return $response;
}
}
In layout:
<?=$data['content'];?>
You can use this in your parent view:
$app = \Slim\Slim::getInstance();
$app->render('subview.php');
If you want to capture the output in a variable, it's as easy as using the view's fetch() method:
//assuming $app is an instance of \Slim\Slim
$app->view()->fetch( 'my_template.php', array( 'key' => $value ) );
Yes it is possible. If you do not want to use any template engine like smarty or twig. If you want to use only .php view file. Follow these steps.
Step 1. Make a new directory in your project's root directory. e.g templates.
Step 2. Open dependencies.php and paste below code
$container = $sh_app->getContainer();
$container['view'] = function ($c) {
$view = new Slim\Views\PhpRenderer('src/templates/');
return $view;
};
Step 3. In your controller's method for rendering view code should be looking like this.
$this->container->view->render($response,'students/index.php',['students' => $data]);

Custom Zend_Form element disappearing after validation

I've created a custom form element that allows me to place text in an arbitrary location in my form:
<?php
class Plano_Form_Element_Note extends Zend_Form_Element_Xhtml
{
public $helper = 'formNote';
/**
* Default decorators
*
* #return void
*/
public function loadDefaultDecorators()
{
if ($this->loadDefaultDecoratorsIsDisabled()) {
return;
}
$decorators = $this->getDecorators();
if (empty($decorators)) {
$this->addDecorator('ViewHelper')
->addDecorator('Errors')
->addDecorator('Label')
->addDecorator(array('row' => 'HtmlTag'), array('tag' => 'div', 'class' => 'form-row clearfix'));
}
}
}
This works like a charm, but as soon as I hit $form->isValid() the element turns up empty and only the wrapper shows:
<div class="form-row clearfix"></div>
The elements are added using subforms (method in my form class below):
/**
* Setup form elements and generate subforms
*
* #return Event_Form_Feedback_Enter
*/
protected function setupForm()
{
$partMapper = new Event_Model_FeedbackPart_Mapper();
$parts = $partMapper->fetchByFeedbackId($this->getFeedback()->getId(), array('order ASC', 'id DESC'));
foreach ($parts as $part)
{
switch ($part->getType())
{
case Event_Model_FeedbackPart::TYPE_TEXT:
$subform = new Event_Form_Feedback_Enter_Text();
break;
case Event_Model_FeedbackPart::TYPE_QUESTION_OPEN:
$subform = new Event_Form_Feedback_Enter_Question();
break;
case Event_Model_FeedbackPart::TYPE_QUESTION_MC:
$subform = new Event_Form_Feedback_Enter_MultipleChoiceQuestion();
break;
}
$subform->setup($part);
$this->addSubForm($subform, 'part-' . $part->getId());
}
$this->addSubmit();
}
... and here is the element creation in the actual form class (Event_Form_Feedback_Enter_Text):
protected function setupForm()
{
$element = new Plano_Form_Element_Note('description');
$element->setValue($this->getPart()->getDescription());
$this->addElement($element);
}
It turns out the validation was breaking for static form element. To solve this, I have overridden the isValid() method in my Plano_Form_Element_Note class:
public function isValid($value)
{
return true;
}
An alternative approach for placing arbitrary static content into a form is the AnyMarkup decorator.

Categories