I have custom module Block with template file.
How can I add simple ckeditor in twig template?
I already added library dependes in module.library.yml
table:
dependencies:
- core/ckeditor
- ckeditor/drupal.ckeditor
There is an example of block with WYSIWYG
<?php
namespace Drupal\my_module\Plugin\Block;
use Drupal\Core\Form\FormStateInterface;
/**
*
* #Block(
* id = "content_block",
* admin_label = #Translation("content_block"),
* category = #Translation("content_block")
* )
*/
class ContentBlock extends AbstractWebConfigurableBlock {
/**
* {#inheritdoc}
*/
public function defaultConfiguration() {
return [] + parent::defaultConfiguration();
}
/**
* {#inheritdoc}
*/
public function blockForm($form, FormStateInterface $form_state) {
$form['title'] = [
'#type' => 'textfield',
'#title' => $this->t('Title'),
'#default_value' => $this->configuration['title'],
'#maxlength' => 50,
'#size' => 50,
'#weight' => '1',
'#required' => TRUE,
];
$form['content'] = [
'#type' => 'text_format',
'#title' => $this->t('Content'),
'#default_value' => $this->configuration['content'],
'#format' => 'full_html',
'#weight' => '2',
'#required' => TRUE,
];
return $form;
}
/**
* {#inheritdoc}
*/
public function blockSubmit($form, FormStateInterface $form_state) {
$this->configuration['title'] = $form_state->getValue('title');
$this->configuration['content'] = $form_state->getValue('content')['value'];
}
/**
* {#inheritdoc}
*/
public function build() {
return [
'title' => [
'#markup' => $this->configuration['title'],
],
'content' => [
'#markup' => $this->configuration['content'],
],
];
}
}
Related
Through these process I can upload data that contained in Big Excel file, if there is any validation problem on the queue it will skip and upload remaining files. But I don't know how I can get those validation errors through API. I trided if ($import->failures()->isNotEmpty()) way for checking if there any errors I know that won't work. Suggest me the best way to get those validation errors.
On my ImportController
public function import(Request $request)
{
$rules = [
'file' => 'required|mimes:xlsx,xls',
'type' => 'filled|string|not_in:null',
];
$validator = Validator::make($request->all(), $rules);
if ($validator->fails()) {
$errors = $validator->errors();
return response()->json($errors, 404);
}
$type = $request->input('type');
$file = $request->file;
$fileName = time() . '--u-' . auth()->user()->id . '.' .$file->extension();
$location = $file->storeAs('importFile/applicationFile' , $fileName);
$import = new ApplicationImport;
$import->import($location);
if ($import->failures()->isNotEmpty()) {
return response()->json(['response' => 'Imported! And have some errors!', 'errors' =>
$import->failures()], 404);
}
return response()->json(['response' => 'File send to queue! Worker will import it.'], 200);
}
On ApplicationImport (Using Maatwebsite\Excel)
namespace App\Imports;
use App\Models\Application;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\Importable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Maatwebsite\Excel\Concerns\SkipsFailures;
use Maatwebsite\Excel\Concerns\SkipsOnFailure;
use Maatwebsite\Excel\Concerns\WithHeadingRow;
use Maatwebsite\Excel\Concerns\WithValidation;
use Maatwebsite\Excel\Concerns\WithBatchInserts;
use Maatwebsite\Excel\Concerns\WithChunkReading;
class ApplicationImport implements ToModel, WithHeadingRow, WithValidation, WithBatchInserts, WithChunkReading, ShouldQueue, SkipsOnFailure
{
use Importable, SkipsFailures;
public function rules(): array
{
return [
'*.title' => ['required', 'string', 'max:100', 'unique:applications'],
'*.user_id' => ['required', 'numeric'],
'*.company_id' => ['required', 'numeric'],
'*.course_id' => ['required', 'numeric'],
'*.coursetype_id' => ['required', 'numeric'],
'*.institution_id' => ['required', 'numeric'],
'*.status_id' => ['required', 'numeric'],
'*.internal_ref' => ['required', 'string', 'max:255'],
'*.external_ref' => ['required', 'string', 'max:255'],
'*.intake_month' => ['required', 'string', 'max:255'],
'*.intake_year' => ['required', 'numeric', 'min:4'],
'*.tution_fee' => ['required', 'numeric'],
'*.administration_charge' => ['required', 'numeric'],
'*.created_by' => ['required', 'numeric']
];
}
public function genUID()
{
$app_uid = 'USR-' . mt_rand(10000000, 99999999);
if ($this->uidNumberExists($app_uid)) {
return $this->genUID();
} else {
return $app_uid;
}
}
public function uidNumberExists($app_uid)
{
return Application::Where('uid', $app_uid)->exists();
}
/**
* #param array $row
*
* #return \Illuminate\Database\Eloquent\Model|null
*/
public function model(array $row)
{
return new Application([
'uid' => $this->genUID(),
'title' => $row['title'],
'user_id' => $row['user_id'],
'company_id' => $row['company_id'],
'course_id' => $row['course_id'],
'coursetype_id' => $row['coursetype_id'],
'institution_id' => $row['institution_id'],
'status_id' => $row['status_id'],
'internal_ref' => $row['internal_ref'],
'external_ref' => $row['external_ref'],
'intake_month' => $row['intake_month'],
'intake_year' => $row['intake_year'],
'tution_fee' => $row['tution_fee'],
'administration_charge' => $row['administration_charge'],
'created_by' => $row['created_by'],
]);
}
public function batchSize(): int
{
return 1000;
}
public function chunkSize(): int
{
return 1000;
}
}
You should move your controller code in a queue/job where you can get failures and then you can access through Pusher if you are using. If you don't implement shouldQueue in import then maybe you can get failures.
I have a menu in my app:
<?php
NavBar::begin([
'brandLabel' => Html::img('#web/images/logo-top.png', ['id' => 'logo']),
'brandUrl' => Yii::$app->homeUrl,
'options' => [
'class' => 'navbar-inverse navbar-static-top',
],
]);
if (count($menuItems)) {
echo Nav::widget([
'options' => ['class' => 'navbar-nav'],
'items' => $menuItems,
]);
}
?>
<?php NavBar::end(); ?>
$menuItems is generated within a Controller:
private function constructMenu($categories) {
$menu = [];
if (is_array($categories) && (count($categories) > 0)) {
foreach($categories as $key => $category) {
$menu[$key] = [
'label' => $category['name'],
'url' => Url::to([
'category/view',
'slug' => $category['slug']
]),
];
if (is_array($category['children']) && (count($category['children']) > 0)) {
$menu[$key]['items'] = $this->constructMenu($category['children']);
}
}
}
return $menu;
}
Also I have urlManager config:
'urlManager' => [
'enablePrettyUrl' => true,
'showScriptName' => false,
'rules' => [
'category/<slug:[\w_-]+>' => 'category/view',
'item/<slug:[\w_-]+>' => 'item/view',
'cart/remove/<item_id:\d+>' => 'cart/remove',
'cart/add/<item_id:\d+>' => 'cart/add',
],
],
So, the only problem is that the menu items are always active = false. How should I modify constructMenu method to set proper value for active key? Or maybe I should do it within the template?
Here is content of $menuItems from PhpStrom debug panel right before it will be passed to Nav::widget:
Here is where I am now:
NavBar::begin([
'brandLabel' => Html::img('#web/images/logo-top.png',
['id' => 'logo', 'style' => 'height: 40px; filter: invert(100%);']),
'brandUrl' => Yii::$app->homeUrl,
'options' => [
'class' => 'navbar-inverse navbar-static-top',
],
]);
$controllerAndSlug = $this->context->id . '/' . $this->context->actionParams['slug'];
$menuItems = array_map(
function($item) use ($controllerAndSlug) {
$item['active'] = strpos($item['url'], $controllerAndSlug) !== false;
return $item;
},
$menuItems
);
if (count($menuItems)) {
echo Nav::widget([
'options' => ['class' => 'navbar-nav'],
'items' => $menuItems,
]);
}
NavBar::end();
It works fine, but sets active flag only on top level menu items. Now I wonder about how to pass a param to callback-function.
Although if you provide the full URL with /controller/action format it should work if it still does not, then you can use the active option of the item by checking the current controller, action, and slug
protected function constructMenu($categories) {
$menu = [];
$controller = Yii::$app->controller->id;
$action = Yii::$app->controller->action->id;
$slug = Yii::$app->request->get('slug');
if( is_array($categories) && (count($categories) > 0) ){
foreach( $categories as $key => $category ){
$isActive = ($controller == 'category' && $action == 'view' && $slug == $category['slug']);
$menu[$key] = [
'label' => $category['name'],
'url' => Url::to([
'category/view',
'slug' => $category['slug']
]),
'active' => $isActive
];
if( is_array($category['children']) && (count($category['children']) > 0) ){
$menu[$key]['items'] = $this->constructMenu($category['children']);
}
}
}
return $menu;
}
Try this:
private function constructMenu($categories) {
$menu = [];
if (is_array($categories) && (count($categories) > 0)) {
foreach($categories as $key => $category) {
$menu[$key] = [
'label' => $category['name'],
'url' => Url::to([
'category/view',
'slug' => $category['slug']
]),
'active' => Yii::$app->controller->id == 'category'
&& Yii::$app->controller->action->id == 'view'
&& Yii::$app->request->get('slug') == $category['slug']
];
if (is_array($category['children']) && (count($category['children']) > 0)) {
$menu[$key]['items'] = $this->constructMenu($category['children']);
}
}
}
return $menu;
}
Can anyone help me in the implementation of nested set behavior https://github.com/creocoder/yii2-nested-sets with Yii2 Menu Widget?
Basically I want the hierarchical sidebar navigation menu like this http://www.surtex-instruments.co.uk/surgical/general-surgical-instruments
Thanks.
In your Model class define this functions:
public static function getTree($selected, $search)
{
$categories = Categories::find()->orderBy('lft')->asArray()->all();
$tree = [];
$index = 0;
foreach ($categories as $category) {
if ($category['parent_category_id'] === NULL) {
$tree[$index]['text'] = $category['category_' . Yii::$app->language];
if ($search) {
$tree[$index]['href'] = Url::to(['products', 'category' => $category['category_id'], 'search' => $search, 'string' => $category['category_' . Yii::$app->language]]);
} else {
$tree[$index]['href'] = Url::to(['products', 'category' => $category['category_id'], 'string' => $category['category_' . Yii::$app->language] ]);
}
$tree[$index]['id'] = $category['category_id'];
if ($selected) {
if ($selected['category_id'] == $category['category_id']) {
$tree[$index]['state']['selected'] = true;
}
if ($selected['lft'] >= $category['lft'] && $selected['rgt'] <= $category['rgt']) {
$tree[$index]['state']['expanded'] = true;
}
}
if ($category['lft'] + 1 != $category['rgt']) {
Categories::getNodes($tree[$index], $categories, $selected, $search);
}
$index++;
}
}
return $tree;
}
private static function getNodes(&$tree, $categories, $selected, $search)
{
$index = 0;
foreach ($categories as $category) {
if ($tree['id'] == $category['parent_category_id']) {
$tree['nodes'][$index]['text'] = $category['category_' . Yii::$app->language];
if ($search) {
$tree['nodes'][$index]['href'] = Url::to(['products', 'category' => $category['category_id'], 'search' => $search, 'string' => $category['category_' . Yii::$app->language]]);
} else {
$tree['nodes'][$index]['href'] = Url::to(['products', 'category' => $category['category_id'], 'string' => $category['category_' . Yii::$app->language]]);
}
$tree['nodes'][$index]['id'] = $category['category_id'];
if ($selected) {
if ($selected['category_id'] == $category['category_id']) {
$tree['nodes'][$index]['state']['selected'] = true;
}
if ($selected['lft'] >= $category['lft'] && $selected['rgt'] <= $category['rgt']) {
$tree['nodes'][$index]['state']['expanded'] = true;
}
}
if ($category['lft'] + 1 != $category['rgt']) {
Categories::getNodes($tree['nodes'][$index], $categories, $selected, $search);
}
$index++;
}
}
}
and use this extension execut/yii2-widget-bootstraptreeview
In the controller file get the menu like this:
public function actionProducts($category = false)
{
...
$data = Categories::getTree($category,'');
In your view file
<?php
...
use execut\widget\TreeView;
...
$onSelect = new JsExpression(<<<JS
function (undefined, item) {
window.location.href = item.href;
}
JS
);
?>
<?= TreeView::widget([
'data' => $data,
'template' => TreeView::TEMPLATE_SIMPLE,
'clientOptions' => [
'onNodeSelected' => $onSelect,
'onhoverColor' => "#fff",
'enableLinks' => true,
'borderColor' => '#fff',
'collapseIcon' => 'fa fa-angle-down',
'expandIcon' => 'fa fa-angle-right',
'levels' => 1,
'selectedBackColor' => '#fff',
'selectedColor' => '#2eaadc',
],
]); ?>
Is it possible to create a module that outputs two tabs into the publish screen, or do I have two create another module to to create my second tab or just another tab.file.php file?
CODE
FILE: upd.my_module.php
class My_module_upd {
var $version = '1.0';
public function __construct(){
$this->EE =& get_instance();
}
public function install(){
$this->EE->load->dbforge();
$data = array(
'module_name' => 'My Module',
'module_version' => $this->version,
'has_cp_backend' => 'y',
'has_publish_fields' => 'y'
);
$this->EE->db->insert('modules', $data);
return true;
}
public function tabs(){
$tabs['tab_1'] = array(
'field_1' => array(
'visible' => TRUE,
'collapse' => FALSE,
'htmlbuttons' => TRUE,
'width' => '100%'
),
'field_2' => array(
'visible' => TRUE,
'collapse' => FALSE,
'htmlbuttons' => TRUE,
'width' => '100%'
)
);
$tabs['tab_2'] = array(
'field_1' => array(
'visible' => TRUE,
'collapse' => FALSE,
'htmlbuttons' => TRUE,
'width' => '100%'
),
);
return $tabs;
}
}
FILE: tab.my_module.php
class My_module_tab {
public function __construct(){
$this->EE =& get_instance();
}
public function publish_tabs($channel_id, $entry_id = ''){
$settings = array(
'field_1' => array(
'field_id' => 'field_1',
'field_label' => 'Field 1',
'field_type' => 'text',
'field_required' => 'n',
'field_data' => '',
'field_text_direction' => 'ltr',
'field_maxl' => 100,
'field_instructions' => '',
),
'field_2' => array(
'field_id' => 'field_2',
'field_label' => 'Field 2',
'field_type' => 'text',
'field_required' => 'n',
'field_data' => '',
'field_text_direction' => 'ltr',
'field_maxl' => 100,
'field_instructions' => '',
),
);
return $settings;
}
}
In the My_module_upd->tabs() method it looks like to can declare multiple tabs in the array but the My_module_tab class seems geared to controlling just one tab. Can anyone point me in the right direction?
I am trying to create a simple module in Drupal 6.20 as follows:
<?php
function example_help($section) {
switch ($section) {
case 'admin/modules#description':
return t('This module implements an example form.');
}
}
function example_menu($may_cache) {
$items = array();
if ($may_cache)
{
$items[] = array(
'path' => 'example',
'title' => t('Example'),
'callback' => 'example_page',
'access' => TRUE,
'type' => MENU_NORMAL_ITEM
);
}
return $items;
}
function example_page() {
return drupal_get_form('example_page_form');
}
function example_page_form() {
$form['fullname'] = array(
'#type' => 'textfield',
'#title' => t('Enter your full name'),
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Save'),
);
return $form;
}
function example_page_form_submit($form_id, $form_values) {
...some code
}
But whenever i am typing in http://mysite.com/example, its getting redirected to 404. Please help. I am very new to Drupal technology. Is there ne more files needed for this apart from the .info and .module file?
Thanks.
Ive got the solution. For Drupal 6.X it menu hook should be as follows:
function example_menu() {
$items = array();
$items['example'] = array(
'title' => 'List',
'page callback' => 'example_page',
'access callback' => 'user_access',
'access arguments' => array('access content'),
'weight' => -10,
'type' => MENU_DEFAULT_LOCAL_TASK,
);
return $items;
}