Rules action: add a node - drupal-7

Is there a way of (when I add a user) to create a node with he as author?
And is it possible to write own actions?

Yes, and yes.
For the first one you'll need the Entity API module which will give you a new action called 'Create a new entity'. You can use this along with the event 'After saving a new user account' to create a new node with the newly created user as the author. I won't go into detail as it's pretty self-explanatory when you're going through the UI.
For the second, you need to implement hook_rules_action_info(). This example from the docs page contains all of the required, and some optional, properties to create an action:
function hook_rules_action_info() {
return array(
'mail_user' => array(
'label' => t('Send a mail to a user'),
'parameter' => array(
'user' => array(
'type' => 'user',
'label' => t('Recipient'),
),
),
'group' => t('System'),
'base' => 'rules_action_mail_user',
'callbacks' => array(
'validate' => 'rules_action_custom_validation',
'help' => 'rules_mail_help',
),
),
);
}

Related

drupal form field not loading correct data

I am building my first Drupal 7 module and am having trouble with the screen to edit a fieldable entity. I am using field_attach_form and it is working great for all accept one field which is displaying the field default rather than the current content of that field for that entity.
I have a text field, a number field, a number of Boolean fields and the one list_text field which is failing.
Any ideas what I a doing incorrectly? Code below is what I think is needed but please do let me know if you need more.
Code to create the field in hook_enable:
if (!field_info_field('field_available')) {
$field = array (
'field_name' => 'field_available',
'type' => 'list_text',
'settings' => array(
'allowed_values' => array('No', 'Provisionally', 'Yes'),
),
);
field_create_field($field);
Code to create the instance, also in hook_enable:
if (!field_info_instance('appointments_status', 'field_available', 'appointments_status')) {
$instance = array(
'field_name' => 'field_available',
'entity_type' => 'appointments_status',
'bundle' => 'appointments_status',
'label' => t('Available?'),
'required' => TRUE,
'default_value' => array(array('value' => 'No')),
'description' => t('Set to No if appointments with this status make this slot unavailable, Provisionally means that it will only reserve a space temporarily'),
);
field_create_instance($instance);
This entity has only the one bundle with the same name as the entity.
The code to create the URL in hook_menu:
$items['admin/appointments/appointments_statii/%/edit'] = array(
'title' => 'Edit appointment status',
'description' => 'Edit the parameters of the selected status code',
'page callback' => 'drupal_get_form',
'page arguments' => array('appointments_status_edit_form',3),
'access arguments' => array('access administration pages'),
'type' => MENU_CALLBACK,
);
The form function is:
function appointments_status_edit_form($form, &$form_state) {
// Get the status id from the form_state args
$status_id = $form_state['build_info']['args'][0];
// Load the chosen status entity
$status = entity_load_single('appointments_status', $status_id);
// Set up the fields for the form
field_attach_form('appointments_status', $status, $form, $form_state);
$form['submit'] = array(
'#type' => 'submit',
'#value' => 'Save changes',
'#weight' => 99,
);
return $form;
}
I have used the Devel module's dpm to check that the data is loaded correctly by entity_load_single and it is.
Thanks
Rory
I have answered my own question!
I was also programmatically loading some entities and was not loading this field with the numbers that a list_text field stores, instead I was loading the visual text.
I used a metadata wrapper and the code looked like this:
$w_appointments_status->$appointments_availability= 'Yes';
I changed it to:
$w_appointments_status->$appointments_availability = 2;
In this example 'Yes' was the third allowed value - hence 2.
So the code in my question was in fact correct although I have since added 'widget' and 'formatter' parameters to the instance.
I am sorry if this got some of you scratching your heads thinking ' but that code is correct'!!
Regards
Rory

Duplicate model along with it's associations

I came across this post that gave an answer on how to do this but it's not quite working for me.
I have a model called SitePage which has many SitePageGroup which in turn has many SitePageContent
// SitePage Model
public $hasMany = array(
'SitePageGroup' => array(
'className' => 'FoCMS.SitePageGroup',
'foreignKey' => 'site_page_id',
'dependent' => FALSE,
),
);
// SitePageGroup Model
public $belongsTo = array(
'SitePage' => array(
'className' => 'FoCMS.SitePage',
'foreignKey' => 'site_page_id',
),
);
public $hasMany = array(
'SitePageContent' => array(
'className' => 'FoCMS.SitePageContent',
'foreignKey' => 'site_page_group_id',
'dependent' => FALSE,
),
);
// SitePageContent Model
public $belongsTo = array(
'SitePageGroup' => array(
'className' => 'FoCMS.SitePageGroup',
'foreignKey' => 'site_page_group_id',
),
);
Using the answer in that linked question I am seeing the parent model, SitePage being duplicated, but the associated models are being removed from the original and associated with the new one.
$record = $this->SitePage->find('first', array('condition' => array('SitePage.id' => $id)));
unset($record['SitePage']['id'], $record['SitePageGroup']['id'], $record['SitePageGroup']['SitePageContent']['id'] /* further ids */);
$this->SitePage->create();
$record['SitePage']['name'] = $record['SitePage']['name'].'-copy';
$record['SitePage']['friendly_name'] = $record['SitePage']['friendly_name'].' Copy';
if($this->SitePage->saveAll($record)){
$this->Session->setFlash('The site page has been saved', 'fo_message');
$this->redirect(array('action' => 'index'));
}else{
$this->Session->setFlash('The site page could not be saved. Please, try again.', 'fo_message');
}
Update
Debugging the record that I'm trying to reset I see the following
array(
'SitePage' => array(
'name' => 'test',
'friendly_name' => 'Test',
'order' => '82',
'created' => '2015-09-03 19:16:40',
'modified' => '2015-09-03 19:20:27'
),
'SitePageGroup' => array(
(int) 0 => array(
'id' => '55e88087-a4dc-4c37-89dc-f9c172b40463',
'site_page_id' => '55e88078-16c8-46ce-bf02-fa5372b40463',
'name' => 'group-1',
'friendly_name' => 'Group 1',
'order' => '1',
'created' => '2015-09-03 19:16:55',
'modified' => '2015-09-03 19:16:55'
),
(int) 1 => array(
'id' => '55e8809e-d018-4ebe-a4cf-fbef72b40463',
'site_page_id' => '55e88078-16c8-46ce-bf02-fa5372b40463',
'name' => 'group-2',
'friendly_name' => 'Group 2',
'order' => '2',
'created' => '2015-09-03 19:17:18',
'modified' => '2015-09-03 19:17:18'
)
)
)
The way I am getting this result is by doing this
$sitePage = $this->SitePage->find('first', array(
'conditions' => array(
'SitePage.id' => $id,
),
));
unset($sitePage['SitePage']['id'], $sitePage['SitePageGroup']['id'], $sitePage['SitePageGroup']['SitePageContent']['id'], $sitePage['SitePageGroup']['site_page_id'], $sitePage['SitePageGroup']['SitePageContent']['site_page_group_id'] /* further ids */);
debug($sitePage);
die();
But also also as you can see in the debug output the 3rd level of associated models are not being included, each of the SitePageGroup should also have a SitePageContent
I think a simple loop over the array of SitePageGroup should reset the id's and set the foreign keys to null, but I guess I also need to somehow include the SitePageContent that belongs to the SitePageGroup so I can reset those as well.
You need to ensure that all primary and foreign keys are set to null before saving. You only appear to be resetting the primary keys of your models but Cake needs to know that the foreign keys need generating so that they reference the new records.
Before calling $record it might be worth using debug($record); to check that everything in that array has been set/reset appropriately to ensure the copy will work as expected.
Update
Based on the array contents you've posted in your updated question it appears that you are not removing all the primary and foreign keys from your save data. You need to make sure that these are removed from everything you are about to save including the has many associations.
If you look at your array you should be able to see that unset($sitePage['SitePageGroup']['id']) will not remove the primary IDs of your SitePageGroup data as what you are unsetting doesn't correspond to array paths in your $sitePage array.
You can use CakePHP's Hash utility to remove the primary keys from the array like this:-
$sitePage = Hash::remove($sitePage, 'SitePageGroup.{n}.id');
And similarly for the foreign keys:-
$sitePage = Hash::remove($sitePage, 'SitePageGroup.{n}.site_page_id');

CakePHP save failing with validation errors set but empty

A model that I am using with both TranslateBehavior and TreeBehavior is failing to save. I suspect it is something to do with one of these behaviors. Here's the data going in:
array(
'Category' => array(
'id' => '3252',
'parent_id' => null,
'sort_order' => '0',
'name' => array(
'eng' => 'english name',
'fra' => 'french name',
'deu' => 'german name',
'ita' => 'italian name',
'spa' => 'spanish name'
),
)
)
And $this->Category->validationErrors is:
array(
'parent_id' => array(),
'sort_order' => array()
)
There are no validation rules defined in the model. There is no beforeSave() or beforeValidate() method defined.
I am not getting any validation errors displayed on screen, although all fields have the red "error" outline.
Edit - the save operation is not getting as far as Category::beforeSave(). I created that function and it does not get run. It gets as far as Category::beforeValidate().
$validates = $this->Category->validates($this->request->data);
debug($validates);
$saved = $this->Category->saveAll($this->request->data);
debug($saved);
In the above code, $validates is true, $saved is false. Category beforeSave is not called at any point in the above process. The validation seems to fail on the call to saveAll(). I need to use saveAll rather than save to save all translations at once (I am doing this elsewhere with another model with no problems).
So, after a while debugging I have found the problem:
public $hasMany = array(
'Category' => array('className' => 'Category', 'foreignKey' => 'parent_id', 'counterCache' => true),
...
I have no idea why I wrote this - I should have been aware that it was going to cause problems, I think I meant to write...
public $hasMany = array(
'Children' => array('className' => 'Category', 'foreignKey' => 'parent_id', 'counterCache' => true),
...
Anyway, changed it to the latter and these errors have gone.
Maybe it doesn't like the null and zero value of parent_id and sort_order? Also in the database what are their field types set as? Do they allow null values? etc. I'm guessing that as there are no validation rules in the model or parent/App model, then it must be some default validation with cake's lib linking to the database/mysql table itself. So I would check the Categories table structure for the parent_id and sort_order fields.

Saving data array in AppModel with CakePHP

I have this function in CakePHP's AppModel (This is used to install initial data in CakePHP) However, I can't seem to get it to save my data, and I get no errors.
Here is my function inside App/Model/AppModel.php:
public function importData() {
$initialOptionData = array(
array( 'Option' => array( 'name' => 'version', 'value' => '1.0.0', )),
array( 'Option' => array( 'name' => 'site-name', 'value' => 'Site Title', )),
);
$this->create();
$this->saveMany($initialOptionData);
}
From you posted code it seems you're trying to save you data to options table, and to do that you need to use Option model.
But you're code is within AppModel, so first import Option model and then execute your save statements.
Your code should look like:
public function importData() {
$initialOptionData = array(
array( 'Option' => array( 'name' => 'version', 'value' => '1.0.0', )),
array( 'Option' => array( 'name' => 'site-name', 'value' => 'Site Title', )),
);
App::import('model','Option'); // Import the Option Model
$Option = new Option(); // create instance of Option class
// save statements
$Option->create();
$Option->saveMany($initialOptionData);
}
Note
Code you're trying will work if you write that within app/model/Option.php file.
I suppose it would be enough to store the values as model property. No need to call $this->save...
public $initialOptionData = array(
array( 'Option' => array( 'name' => 'version', 'value' => '1.0.0', )),
array( 'Option' => array( 'name' => 'site-name', 'value' => 'Site Title', )),
);
all models will inherit initialOptionData...

Drupal 7 hook_menu checkboxes issue

I am trying to put together a module which will have it's own configuration page. For that purpose, I am using the following code as my menu page-callback:
function webform_customizations_customize() {
$form = array();
// Text field for the e-mail subject.
$form['webform_customizations']['user_warn_e-mail_subject'] = array(
'#type' => 'textfield',
'#title' => t('Warning e-mail subject'),
'#description' => t('The subject of the e-mail which will be sent
to users.'),
'#size' => 40,
'#maxlength' => 120,
'#required' => TRUE,
);
$options = array('A', 'B', 'C');
$form['test'] = array(
'#type' => 'radios',
'#options' => array(
'one' => t('one'),
'two' => t('two'),
),
'#title' => t('roles that should see a minimal webforms setting area'),
'#title_display' => t('testing'),
);
$form['high_school']['tests_taken'] = array(
'#type' => 'checkboxes',
'#options' => drupal_map_assoc(array(t('SAT'), t('ACT'))),
'#title' => t('What standardized tests did you take?'),
'#states' => array(
'visible' => array(// action to take.
':input[name="student_type"]' => array('value' => 'high_school'),
),
),
);
return $form;
}
My problem is my attempts to display checkboxes are failing. The first field shows a textfield successfully. But the next two are checkboxes which never show on my configuration page - and the tests_taken checkbox code is lifted directly from this drupal doc page without any amendments.
I tried a single checkbox and that works.
You should have read the comments that were along with the code you took:
// This #states rule says that this checkboxes array will be visible only
// when $form['student_type'] is set to t('High School').
// It uses the jQuery selector :input[name=student_type] to choose the
// element which triggers the behavior, and then defines the "High School"
// value as the one that triggers visibility.
Simply remove the #states element, and it should work.
Happy drupaling!

Resources