Drupal 8 Custom module - how to create a field in the admin area, and then pull that input in my module to use? - drupal-modules

New to Drupal 8, I'm coming from the WP world so it's been very confusing getting the hang of things. I created a custom module and have a page outputting text. Where I'm stuck is the ability to make a field in the admin area, pull that saved info, and then use it in my content that's being output.
Been following along with tutorial but am very stuck. Can anyone provide a road map for me or helpful articles to accomplish this?

Suppose your module name is "custom" then follow these steps to create a admin form and pull the saved info on admin page.
Create a folder name "custom".
Create "custom.info.yml" file within "custom" folder.
name: custom
description: Show admin saved data through custom module.
type: module
# core: 8.x
configure: admin/config/services/custom
Create a Permission for who access admin form.
For Permission create "custom.permissions.yml" file within "custom" folder.
'administer custom':
'title': 'Administer Customform'
'description': 'Configure how Custom Form is used on the site.'
restrict access: true
Then create a route for custom admin form path & it's content.
Create "custom.routing.yml" file within "custom" folder.
custom.config:
path: '/admin/config/custom/config'
defaults:
_form: '\Drupal\custom\Form\CustomConfigForm'
_title: 'Custom Configuration'
requirements:
_permission: 'administer custom'
Now create a menu and assign this route ("custom.config") in menu path & create a form within custom folder and the form location is
src/Form/CustomConfigForm.php
For menu create a "custom.links.menu.yml" file within "custom" folder.
custom.config:
title: 'Custom '
description: 'Custom Admin Configuration'
parent: system.admin_config
route_name: custom.config
weight: 100
For admin form create CustomConfigForm.php file within custom folder and the file location is src/Form/CustomConfigForm.php
<?php
namespace Drupal\custom\Form;
use Drupal\Core\Form\ConfigFormBase;
use Drupal\Core\Form\FormStateInterface;
class CustomConfigForm extends ConfigFormBase {
public function getFormId() {
return 'custom_config_form';
}
public function buildForm(array $form, FormStateInterface $form_state) {
$config = $this->config('custom.settings'); // store data in custom.settings
$form = parent::buildForm($form, $form_state);
$form['custom_types'] = array(
'#type' => 'checkboxes',
'#title' => t('Content Types'),
'#description' => t('Configure where the custom button should appear.'),
'#options' => node_type_get_names(),
'#default_value' => $config->get('custom_types', array()),
);
return $form;
}
public function submitForm(array &$form, FormStateInterface $form_state) {
$config = $this->config('custom.settings');
$config->set('custom_types', $form_state->getValue('custom_types'));
$config->save(); // save data in custom.settings
return parent::submitForm($form, $form_state);
}
public function getEditableConfigNames() {
return ['custom.settings'];
}
}
Now when you save admin form then after you fetch the saved data in "custom.module" file to use this code.
Create "custom.module" file within custom folder.
$config = \Drupal::config('custom.settings'); // get saved settings
$types = $config->get('custom_types', array()); // fetch particular saved data "custom_types"
print $types;
Now enable this module.
Your admin form path is YOUR_SITE_NAME/admin/config/custom/config
Also in Drupal 8 sometimes cache problem occurs, so if any problem comes then clear the cache after form save.

Related

create setup form for custom module

I have a custom module getting executed right after the PDFGenerator finished. I followed this guide on how to create a custom module
https://stackoverflow.com/a/55799101/9945420
When processing a batch document I want to manipulate the generated PDF file and add a footer to that file. The content of that footer needs to get configured in the Administration module.
So within my project called "StampOnScanProcess" I added a Folder called "Setup" with two files. A Form called "FrmSetup"
public partial class FrmSetup : Form
{
private IBatchClass batchClass;
public FrmSetup()
{
InitializeComponent();
}
public DialogResult ShowDialog(IBatchClass batchClass)
{
this.batchClass = batchClass;
// Load previous Settings ...
return this.ShowDialog();
}
private void btnCancel_Click(object sender, EventArgs e)
{
this.Close();
}
private void btnSave_Click(object sender, EventArgs e)
{
// Save ...
this.Close();
}
}
and a UserControl called "UserCtrlSetup"
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface ISetupForm
{
[DispId(1)]
AdminApplication Application { set; }
[DispId(2)]
void ActionEvent(int EventNumber, object Argument, out int Cancel);
}
[ClassInterface(ClassInterfaceType.None)]
[ProgId(CUSTOM_MODULE_NAME_SETUP)]
public partial class UserCtrlSetup : UserControl, ISetupForm
{
private const string CUSTOM_MODULE_NAME_SETUP = "StampOnScanProcess.Setup";
private AdminApplication adminApplication;
public AdminApplication Application
{
set
{
value.AddMenu(CUSTOM_MODULE_NAME_SETUP, CUSTOM_MODULE_NAME_SETUP, "BatchClass");
adminApplication = value;
}
}
public void ActionEvent(int EventNumber, object Argument, out int Cancel)
{
Cancel = 0;
if ((KfxOcxEvent)EventNumber == KfxOcxEvent.KfxOcxEventMenuClicked && (string)Argument == CUSTOM_MODULE_NAME_SETUP)
{
FrmSetup form = new FrmSetup();
form.ShowDialog(adminApplication.ActiveBatchClass);
}
}
}
I modified my registration file and added the setup form to it
[Modules]
StampOnScanProcess
[StampOnScanProcess]
RuntimeProgram=StampOnScanProcess.exe
ModuleID=StampOnScanProcess.exe
Description=...
Version=10.2
SupportsNonImageFiles=True
SupportsTableFields=True
SetupProgram=StampOnScanProcess.Setup
[Setup Programs]
StampOnScanProcess.Setup
[StampOnScanProcess.Setup]
Visible=0
OCXFile=StampOnScanProcess.exe
ProgID=StampOnScanProcess.Setup
When launching the Administration module I head over to the Batch Class Properties => Queues and want to call this setup form by clicking the Properties button in the middle.
Unfortunately the properties button is disabled so I can't open the setup form. This form gets added to the context menu of the batch class
How can I bind this form to the properties button instead? And what is the best way to store configured data and access it when the runtime application gets executed?
I need to think about how to store data because some users have user profiles
and the runtime application currently logs in with no credentials.
public void LoginToRuntimeSession()
{
login = new Login();
login.EnableSecurityBoost = true;
login.Login();
login.ApplicationName = CUSTOM_MODULE_ID;
login.Version = "1.0";
login.ValidateUser($"{CUSTOM_MODULE_ID}.exe", false, "", "");
session = login.RuntimeSession;
}
So it might happen that I have to store the credentials on setup too.
How can I bind this form to the properties button instead?
All interactions with menu entries are handled by ISetupForm.ActionEvent. New entries are added with the AddMenu method of the AdminApplication object. Kofax differentiates between multiple entries by name - imagine that you could have multiple menu entries at the same time, one on batch class level, another one on document class level, and another one in the ribbon - just to name a few examples. Kofax uses the same approach in any component that integrates into Administration (e.g. Custom Modules or Workflow Agents).
This is an example from one of our components. Note that three entries are added on BatchClass level and two more on DocumentClass level.
value.AddMenu("BatchClass.GeneralConfig", "Field Panel - General Configuration", "BatchClass");
value.AddMenu("BatchClass.FieldEditor", "Field Panel - Configure Batch Fields", "BatchClass");
value.AddMenu("DocumentClass.FieldEditor", "Field Panel - Configure Index Fields", "DocumentClass");
value.AddMenu("CopyBatchFieldConfig", "Field Panel - Copy Batch Field Configuration", "BatchClass");
value.AddMenu("PasteBatchFieldConfig", "Field Panel - Paste Batch Field Configuration", "BatchClass");
value.AddMenu("CopyIndexFieldConfig", "Field Panel - Copy Index Field Configuration", "DocumentClass");
value.AddMenu("PasteIndexFieldConfig", "Field Panel - Paste Index Field Configuration", "DocumentClass");
Each entry is no identified by its event text, the first parameter. For example, BatchClass.GeneralConfig is intended to open up a generic configuration dialog - on batch class level.
Now, back to our ActionEvent - this is how I distinguish between the entry selected by the user:
if ((KfxOcxEvent)EventNumber == KfxOcxEvent.KfxOcxEventMenuClicked)
{
AdminForm form = new AdminForm();
switch ((string)Argument)
{
case "BatchClass.GeneralConfig":
ConfigureGeneral(kcApp.ActiveBatchClass);
break;
[I] want to call this setup form by clicking the Properties button in
the middle.
I don't know if you can use this button - I would assume yes - yet personally I tend to put settings either on batch or document class level. For example - your PDF annotation settings may different from document class to class - having an entry on this level seems more natural.
And what is the best way to store configured data and access it when
the runtime application gets executed?
Custom Storage Strings, and you can let your imagination run wild here. The most simplistic approach is to store key-value pairs during setup, and retrieve them in runtime. Here's a generic call (BatchClass is an IBatchClass object, i.e. a pointer to the ActiveBatchClass property of the AdminApplication object):
// set a CSS
BatchClass.set_CustomStorageString(name, value);
// get a CSS
BatchClass.get_CustomStorageString(name)
I usually use a single custom storage string only and store custom object - the object is a base64-encoded serialized XML using XmlSerializer - but again, that's up to you. The only recommendation is to rely on CSS only - don't use external files to store configuration parameters. A CSS is an integral part of your batch class - so, when exporting said class and importing it on a different system, your entire configuration will be there.
I need to think about how to store data because some users have user
profiles
Usually, you don't need to worry about that. The properties for user and password in ValidateUser are entirely optional - and since you're planning to write an unattended module - ideally a Windows Service, credentials should be maintained there. Kofax and Windows would automatically make sure the credentials are passed on, and your module will run under this user's context. Just make sure the user has permissions for the module and all associated batch classes. It's different if you're planning to write an attended module, for example an enhanced Validation module.

Orchard CMS custom field admin settings

I have a custom field in Orchard, I want it to have its own admin view to set the fields default value so that when it is used with other parts - it will always use this default display value.
I have the part, and the admin menu, currently the admin menu goes to the fields settings controller, but how do I create the fields shape for display?
I imagine something like this, but can't figure out what is the correct way to create the fields editor shape:
[Admin]
public class FieldAdminController : Controller
{
public ActionResult TimezoneSettings()
{
// var timezoneShape = Shape.Create("?");
// var model = new TimezoneViewModel(timezoneShape);
// return View(model);
// Or:
// TimezonePart part = Services.ContentManager.New<ITimezoneField>("TimezoneField");
//var model = Services.ContentManager.BuildEditor(part);
// return View(model);
}
}
The field does already work (i.e. the driver is working) when you attach the field to a content part via the admin UI, but I will only be using it with other code created custom parts in my modules.

Cannot save all of the property settings for this Web Part - Sharepoint

"Cannot save all of the property settings for this Web Part. The
default namespace "http://schemas.microsoft.com/WebPart/v2" is a
reserved namespace for base Web Part properties. Custom Web Part
properties require a unique namespace (specified through an
XmlElementAttribute on the property, or an XmlRootAttribute on the
class)."
No where do I get help regarding this error.
This is when adding custom properties to my webpart, why cant I save the properties when I edit my webpart and click on save/apply? (then I get that error)
Code--
[DefaultProperty("Text"), ToolboxData("<{0}:CustomPropertyWebPart runat=server></{0}:CustomPropertyWebPart>"),
XmlRoot(Namespace = "ExecuteStoreProc")]
public class CustomPropertyWebPart : Microsoft.SharePoint.WebPartPages.WebPart
{
const string c_MyStringDefault = "Sample String";
}
// Create a custom category in the property sheet.
[Category("Custom Properties")]
// Assign the default value.
[DefaultValue(c_MyStringDefault)]
// Property is available in both Personalization
// and Customization mode.
[WebPartStorage(Storage.Personal)]
// The caption that appears in the property sheet.
[FriendlyNameAttribute("Custom String")]
// The tool tip that appears when pausing the mouse pointer over
// the friendly name in the property pane.
[Description("Type a string value.")]
// Display the property in the property pane.
[Browsable(true)]
[XmlElement(ElementName = "MyString")]
// The accessor for this property.
public string MyString
{
get
{
return _myString;
}
set
{
_myString = value;
}
}
Can you try going to Site Settings > Galleries > Web Part > New
In that window, put a checkbox next to the webpart you are trying to add, then click Populate
If its populate correctly then it is working otherwise there is some error in the webpart.
Return to your webpage where you want to add the webpart, try to add the webpart by selecting it in the gallery.
If this works (you were able to add it to your page), you can open the webpart added in your webpart gallery (Site Settings > Galleries > Web Part) and compare it to your own .dwp file to see what you did wrong.
Hope this helps

How to set new Orchard module to be Home Page via code

I'm very new with orchard.
To learn orchard module development, I followed the documentation and tried to create a commerce module.
The module consists of product part and product type which has product part.
During enable module, it will create admin and home menu for this module, "Commerce" and "Shop" respectively.
My questions are
How do I make this module to be home page during enable module. In other word, I want Index method of
the module's HomeController handle home url?
How do I get Shop menu in front end to be after home menu or register this module to home menu?
I am attaching source code, please download it from the following link
download source code
To take over the home page the standard Orchard way is to implement IHomePageProvider.
You can, when creating a page as part of migrations.cs in a module, tell the Autoroute part to set your created page's alias as the homepage:
//create a page page
var homepage = _contentManager.Create("Page");
homepage.As<TitlePart>().Title = "My Home";
_contentManager.Publish(homepage);
var homePageArp = homepage.As<AutoroutePart>();
homePageArp.DisplayAlias = String.Empty;
_autorouteService.PublishAlias(homePageArp);
This assumes you're going from a clean instance of Orchard without any prior homepages; if you have an existing homepage, you'll have to regenerate those pages' Aliases as part of your module too. This is how it's done as part of the AutoroutePartHandler in the Orchard.Autoroute project (inside the Publish Alias method):
// regenerate the alias for the previous home page
var currentHomePages = _orchardServices.ContentManager.Query<AutoroutePart, AutoroutePartRecord>().Where(x => x.DisplayAlias == "").List();
foreach (var current in currentHomePages) {
if (current != null) {
current.CustomPattern = String.Empty; // force the regeneration
current.DisplayAlias = _autorouteService.Value.GenerateAlias(current);
}
_autorouteService.Value.PublishAlias(current);
}
_autorouteService.Value.PublishAlias(part);
If you dig through the driver and handler for the autoroute project, you'll learn a lot about the internals; when you tick that "set as homepage" box in the Admin UI, it sets the Path to "/" and then that gets picked up, triggers the old homepage re-wire, clears the "/" path to String.Empty and then publishes that blank alias, giving you a new homepage.
(this is valid as of Orchard 1.6)
If your module is to be used by others, then it is better to make a widget which can be added to any layer (the homepage layer for example). That way each user can decide where your module comes into play.
If you are using this module for yourself only, then you can just override the default routes (standard mvc functionallity).
Look at my ExtendedRegistration module (Routes.cs) to see how it's done.
Here I am overriding the standard Account/Register URL. There should be nothing preventing you from overriding the default HomeController.
public class Routes : IRouteProvider
{
public void GetRoutes(ICollection<RouteDescriptor> routes)
{
foreach (var routeDescriptor in GetRoutes())
{
routes.Add(routeDescriptor);
}
}
public IEnumerable<RouteDescriptor> GetRoutes()
{
return new[] {
new RouteDescriptor {
Priority = 19,
Route = new Route(
"Users/Account/Register",
new RouteValueDictionary {
{"area", "itWORKS.ExtendedRegistration"},
{"controller", "Account"},
{"action", "Register"}
},
new RouteValueDictionary(),
new RouteValueDictionary {
{"area", "itWORKS.ExtendedRegistration"}
},
new MvcRouteHandler())
}
};
}
}

how do i make diffrent registration form in drupal?

Is there a module that can make different registration forms for different roles during sign up? (ex. each Editor,Main User,Sub User role have different form)
Here's what you should do
start with install profile2-7.x-1.2.tar.gz.
entity-7.x-1.0-rc3.tar.gz once you have profile2 installed -->
enable --> click on configure - (Here you see your profile types
-add as many as you want).
when you add a new one or modify the existing one "Main" make sure you check "Provide a separate page for editing profiles."
4. Now to have different registration, login and password change pages
install and enable profile2_regpath-7.x-1.9.tar.gz
Now visit the profile Types Page again here you should see "UNIQUE REGISTRATION PATH" .. rest is easy ..
There is :)
http://drupal.org/project/autoassignrole
to assign by path you will also need Content Profile:
http://drupal.org/project/content_profile
check out this tutorial on how to pull it off:
http://www.web-a-team.com/blog-post/user-registration-more-one-role
Here is some idea how to solve your question in drupal 7(I think it should work in drupal 6 also). However its not safe since anyone can just change the role they have:
function my_module_form_user_register_form_alter(&$form, &$form_state, $form_id) {
$company_role = $form_state['build_info']['args'][0];
$form['account']['company_role'] = array(
'#type' => 'select',
'#title' => t('Company role'),
'#options' => drupal_map_assoc(array('editor','main user','Sub User')),
'#description' => t('Please select your company role'),
"#empty_option" =>t('- Select -'),
'#weight' => -11, // Add the select box above username that have weight -10
);
switch (strtolower($company_role)) {
case 'editor':
// add extra fields for editor
$form['account']['company_role']['#default_value'] = $company_role;
break;
case 'main user':
// add extra fields for main
$form['account']['company_role']['#default_value'] = $company_role;
case 'sub user';
// add extra fields for 'Sub User'
$form['account']['company_role']['#default_value'] = $company_role;
break;
default:
$form['account']['company_role']['#empty_option'] = t('- Select -');
$company_role = null;// error handling or default case
}
}
If you for example have LDAP in your company you could instead get this information from LDAP(https://www.drupal.org/node/1053748). Then you can be more sure about the role is chosen correctly.

Resources