Im new to Yii2 and I have a need to modify the registerAssetBundle() function of kartiks FileInput widget in Yii2. I realize this is in the vendor folder, so I wanted to do an override. FYI, this is using the advanced template. Can anyone tell me why I cannot override or what Im doing wrong? Yii just doesnt pick this file up/ doesnt choke/ no errors/ nothing, just goes about its merry way and renders my page as normal.
In common\components I have a file called FileInputOveride.php:
namespace common\components;
use Yii;
use \kartik\file\FileInput;
class FileInputOveride extends \kartik\file\FileInput
{
//...override function, ...do stuff...
Edit -Heres some more code:
Here is the declaration at the top of _form.php which is using the fileInput
use yii\helpers\Html;
use yii\widgets\ActiveForm;
use yii\helpers\Url;
use yii\bootstrap\Modal;
use kartik\widgets\FileInput; <-- if I take this out, it errors that it cant find ::FileInput
use common\components\FileInputOveride; <--this has no effect
Below this line is some view html, until we get to the fileInput field which looks like this:
<?=
//fileinput widget for single file upload
$form->field($model, 'cover_file')->widget(FileInput::classname(),
[
'options'=>
[
'accept'=>'image/*',
'multiple' => false,
'id'=>'cover_file',
],
'pluginOptions' =>
[
'uploadUrl' => $upload_url,
'maxFileCount' => 1,
'allowedFileExtensions' => ['jpg', 'png','jpeg'],
'initialPreviewShowUpload' => false,
'uploadAsync'=> false,
'autoReplace'=>true,
],
'pluginEvents' =>
[
'fileuploaded'=>"function(event, data, previewId, index){
$.get( './call-image?id=".$model->id."', function( response ) {
$('#thumb-container-image').html(response);
});
}",
],
])->label(false);
?>
Trying to override the registerAssetBundle() function in this kartik FileInput.php with my own FileInputOveride.php:
namespace kartik\file;
use Yii;
use yii\helpers\ArrayHelper;
use yii\helpers\Html;
use kartik\base\InputWidget;
use kartik\base\TranslationTrait;
/**
* Wrapper for the Bootstrap FileInput JQuery Plugin by Krajee. The FileInput widget is styled for Bootstrap 3.x with
* ability to multiple file selection and preview, format button styles and inputs. Runs on all modern browsers
* supporting HTML5 File Inputs and File Processing API. For browser versions IE9 and below, this widget will
* gracefully degrade to normal HTML file input.
*
* #see http://plugins.krajee.com/bootstrap-fileinput
* #see https://github.com/kartik-v/bootstrap-fileinput
*
* #author Kartik Visweswaran <kartikv2#gmail.com>
* #since 2.0
* #see http://twitter.github.com/typeahead.js/examples
*/
class FileInput extends InputWidget
{
and here is the entire FileInputOveride.php file:
namespace common\components;
use Yii;
class FileInputOveride extends \kartik\file\FileInput
{
/**
* Registers the asset bundle and locale
*/
public function registerAssetBundle()
{
$view = $this->getView();
if ($this->resizeImages) {
PiExifAsset::register($view);
$this->pluginOptions['resizeImage'] = true;
}
$theme = ArrayHelper::getValue($this->pluginOptions, 'theme');
if (!empty($theme) && in_array($theme, self::$_themes)) {
FileInputThemeAsset::register($view)->addTheme($theme);
}
if ($this->sortThumbs) {
SortableAsset::register($view);
}
if ($this->purifyHtml) {
DomPurifyAsset::register($view);
$this->pluginOptions['purifyHtml'] = true;
}
//above is the existing code
//below is the additional code i added to this function
$assetsRegistered = FileInputAsset::register($view)->addLanguage($this->language, '', 'js/locales');
//array of pages/paths we dont want to include the asset on
$pageArray = ['releases/update'];
//array of assets we dont want to use for the above pages
$fileArray = ['js/fileinput.js'];
//for each page, see if the file(s) specified is/are included, if so, unset them in the assets array
foreach($pageArray as $path)
if(in_array($path, $pageArray)){
foreach($fileArray as $file){
if(in_array($file,$assetsRegistered->js)){
$key= array_search($file, $assetsRegistered->js);
unset($assetsRegistered->js[$key]);
}
}
}
}
}
As an extra, I could also use the syntax to list the assets belonging to a action/view from within its action.
so:
public function actionUpdate(){
//show me all the js registered to this page
Thanks everyone!
In your _form.php file use "FileInputOveride::classname()" instead of "FileInput::classname()" - then you can remove use line for kartik input. When you extend any plugin then you must call your plugin class name instead of plugin you extend.
Related
I want to create a CakePHP Widget in order to create a custom form control. The end goal is to make it a plugin, but for now I am trying to determine the general structure of a Widget. I have created a file in src/View/Widget/DateTimeWidget.php containing
<?php
namespace App\View\Widget;
use Cake\View\Form\ContextInterface;
use Cake\View\Widget\WidgetInterface;
class DateTimeWidget implements WidgetInterface
{
protected $_templates;
public function __construct($templates)
{
$this->_templates = $templates;
}
public function render(array $data, ContextInterface $context)
{
$data += [
'name' => '',
];
return $this->_templates->format('DateTime', [
'name' => $data['name'],
'attrs' => $this->_templates->formatAttributes($data, ['name'])
]);
}
public function secureFields(array $data)
{
return [$data['name']];
}
}
?>
I load the Widget in a View with the code
$this->Form->addWidget(
'datetime',
['DateTime']
);
and then create a form control with it using
echo $this->Form->control('end_time', ['type' => 'datetime']);
However, I get the error Cannot find template named 'DateTime'.
I have created the basic template code
<?php
$this->Form->setTemplates([
'DateTime' => '<p {{attrs}}>Test template</p>'
]);
But I have no idea where in the folder structure to put it? In most plugins I have looked at it is in a helper file, but I wonder if this is the default way to do it? What are my options? And how do i tell CakePHP to load it? What is the preferred way of doing this?
Thank you!
If you want your widget to come with default string templates, then you could for example define them in the widget itself, by adding it to the string template instance that is being passed to the widget's constructor. You'd do it in the widget's render() method though, it wouldn't work properly in the constructor, as widget instances are being reused, ie they are only being constructed once, for example:
public function render(array $data, ContextInterface $context)
{
if (!array_key_exists('customDateTime', $this->_templates->getConfig())) {
$this->_templates->add([
'customDateTime' => '<p {{attrs}}>Test template</p>',
// ...
]);
}
// ...
}
Another option is to put the string templates in a config file:
// in path_to_your_plugin/config/form_helper_templates.php
<?php
return [
'customDateTime' => '<p {{attrs}}>Test template</p>',
// ...
];
and ask the users to load the form helper string templates in their view templates when they want to use your widgets:
$this->Form->templater()->load('YourPluginName.form_helper_templates');
Both options will integrate properly with the form helper, so that users can still override the templates by setting custom templates either via FormHelper::setTemplates(), StringTemplate::load()/add(), or the templates option for FormHelper::control().
I think you should use Cells for it.
Take a look at: https://book.cakephp.org/3/en/views/cells.html
I have trouble rendering a template from a controller in a custom Drupal 8 module.
I am calling this controller method :
public function displayEngineUI() {
$build['#theme'] = 'bretagnecom-search-engine';
return $build;}
There is no problem reaching controller, i can var_dump inside. But the content of the template is not rendered.
My module file structure look like this :
bretagnecom_search_engine.module src
./src:
Controller
./src/Controller:
DefaultController.php
./templates:
bretagnecom-search-engine.html.twig
Any idea about what i'm doing wrong? I usually render a few html directly from controller with inline-template but i would like to isolate my html in his template file this time.
Thank's for the help everyone!
I guess template is not defined in hook_theme().
First just change hyphens to underscores:
public function displayEngineUI() {
$build['#theme'] = 'bretagnecom_search_engine';
return $build;
}
and in bretagnecom_search_engine.module add:
/**
* Implements hook_theme().
*/
function bretagnecom_search_engine_theme() {
$themes = [
'bretagnecom_search_engine' => [
'variables' => [
'your_custom_variable_1' => NULL,
'your_custom_variable_2' => NULL
]
];
If you do not have variables, just remove that part of code.
You can find more info here: https://www.drupal.org/docs/8/theming/twig/create-custom-twig-templates-for-custom-module
I overrieded a controller in Prestashop 1.7 like this :
/override/controllers/front/MyAccountController.php
class MyAccountController extends MyAccountControllerCore
{
/**
* Assign template vars related to page content
* #see FrontController::initContent()
*/
public function initContent()
{
$this->context->smarty->assign([
'logout_url' => $this->context->link->getPageLink('index', true, null, 'mylogout')
]);
parent::initContent();
$this->setTemplate("module:configurateur/views/templates/front/my-account.tpl");
}
}
So I'm trying to call a view in my custom module "configurateur" with this line :
$this->setTemplate("module:configurateur/views/templates/front/my-account.tpl");
This file exists and is in the right folder (I think) :
\modules\configurateur\views\templates\front\my-account.tpl
When I try to load the page, I have this error :
No template found for module:configurateur/views/templates/front/my-account.tpl
at line 68 in file classes/Smarty/TemplateFinder.php
Can anyone tell my what's wrong please ?
The syntax "module:..." is only for ModuleFrontController objects, not for FrontController :
In your case your should use the hook DisplayOverrideTemplate or redirect the page myaccount to a module controller.
I would like to have Silverstripe's userforms add on submit values to a CRM, namely Active Campaign.
I see there is a SubmittedForm class but how would I go about taking the data before it is submitted and submit it via my API as well?
Alternatively, is there a way that once the form data has been submitted to the DB it redirects to a custom page with the ID of the form that has just been submitted? Then I can grab the fields and submit to the API.
You can retrieve submitted form data from a specific UserDefinedForm page like this:
/** #var SubmittedForm[] $submissions */
$submissions = UserDefinedForm::get()->filter(['URLSegment' => 'my-integrated-form'])->Submissions();
Or retrieve all submissions for all user form pages:
$submissions = SubmittedForm::get();
From here to integrate your data to an external system you could write a BuildTask that does what you need to do. You could plug this into the crontask module, or the queuedjobs module to have it run on a schedule daily:
class IntegrateUserFormSubmissionsTask extends BuildTask
{
protected $title = 'Integrate userforms submissions somewhere';
protected $api;
public function run($request)
{
$submissions = SubmittedForm::get();
foreach ($submissions as $submission) {
$formatted = [
'user' => [
'first_name' => $submission->SubmittedBy()->FirstName,
'surname' => $submission->SubmittedBy()->Surname,
],
// ...
];
$this->getYourApi()->submitData($formatted);
}
}
public function getYourApi()
{
if (!$this->api) {
$this->api = new RestfulService(...);
}
return $this->api;
}
}
Of course this is just a quick example, you'd need to map your data structures. Take a look at SubmittedForm for the actual submission structure, and note that most of the actual form field values will be under $submission->Values(). You could use the SubmittedFormField::getExportValue method to return something useful for all "values".
Note that I'd suggest strongly that you don't run this integration inline with extensions to the user defined form, since that will introduce a synchronous dependency which could prevent your forms from working if the other server went down, you experience network latency etc.
If you need a way of monitoring which records have been exported you could use a DataExtension to provide an "ExportedTimestamp" field or something which you could set when you've successfully sent the data to your API:
public function ExternalApiExtension extends DataExtension
{
private static $db = [
'LastExported' => 'SS_Datetime',
];
public function markAsExported()
{
$this->owner->LastExported = SS_Datetime::now();
$this->owner->write();
}
}
Apply the extension to SubmittedForm with YAML configuration (plenty in the docs about this), then in your export BuildTask you can just add $submission->markAsExported(); when you've validated a successful result from your API. Include ->filter(['LastExported' => null]) or something in the filter for your DataList before you run through all your records.
Good luck!
I think you should be able to add a DataExtension to SubmittedForm that implements updateAfterProcess.
It's an extension hook on SubmittedForm that will be called once all user-data has been validated and the email (if applicable) has been sent.
Your extension could look like this:
<?php
class UserFormCRMExtension extends DataExtension
{
public function updateAfterProcess()
{
/** #var SubmittedFormField $field */
foreach ($this->owner->Values() as $field) {
/* prepare data for submittal to CRM */
}
/* send data to CRM */
}
}
Apply as usual, via config.yml :
SubmittedForm:
extensions:
- UserFormCRMExtension
You could go with extending the class and have it submitted manually, based on a certain prerequisite.
Same for redirection, you'll need to write an Extension.
I have designed a template using the template library of codeigniter, the template has the following regions:
$template['template_ar']['template'] = 'template_ar';
$template['template_ar']['regions'] = array(
'header',
'title',
'content',
'topcontent',
'sidebar',
'footer',
'options',
'script',
);
I used the following code to render my template
class faq extends MY_Controller {
/**
* Index
* This function views the Home Page
*
* #access public
* #return
*/
public function index() {
$this->template->write_view('content','comment/questions');
$this->template->write('options','You one',TRUE);
$this->template->render();
}
}
The problem that I want to eliminate is that I want to prevent the top content from appearing in my template. I need only the content, the header and the footer. Can anyone tell me how to do this?
Template Library for CodeIgniter
Set regions for writing to
$this->template->set_regions($regions);
Dynamically add region to the currently set template
$this->template->add_regions($name, $props);
Empty a region's content
$this->template->empty_region($name);