Recently, I was working on a Silverstripe project where the client requested that they have a contact form, and based on the state/region that was chosen in a select box, an email would be sent to that regions email. Another example of this would be to send an email to a certain department such as sales, technical support, advertising, general inquiries etc.
I could have assigned the values with the contact form itself, but when the client informed me that each state did their own email campaigns, it became apparent that a newsletter sign up form would require the same email information based on state/region.
This example will allow your administrator to update these email addresses down the track, by using the CMS, and not require modifying any PHP code.
Ok, so the first thing we want to do is is make sure that the DataObjectManager plugin is installed. This is a favourite of mine because it extends the ComplexTableField class and adds new features such as datepickers and just looks and works better.
Once installed we need to log in to the CMS admin, and from there we need to make sure the main website config item is selected in the Page tree (it’s the one with the Earth icon). Our end result in the administration panel is to create a new tab titled Email Locations as per the image below.
Next step is to create our LocationEmail class in /mysite/code/LocationEmail.php
<php // This class will create a table in the database titled LocationEmail class LocationEmail extends DataObject { // Create two fields to be added to the database table to be used for reference static $db = array( 'LocationName' => 'Text', 'LocationEmailAddress' => 'Text' ); // Set up the join that 1 Location can join to one SiteConfig object static $has_one = array( 'MyLocation' => 'SiteConfig' ); // Add input fields to be used in the admin panel, and link the fieldnames for which to store the values to function getCMSFields_forPopup() { $fields = new FieldSet(); $fields->push( new TextField('LocationName', 'Location name' ) ); $fields->push( new EmailField('LocationEmailAddress', 'Email' ) ); return $fields; } }
You will have to add a line in your _config.php in the root folder to inform Silverstripe of the extra configuration file to load
// Place this near the bottom of your _config.php file // Read a new configuration file in /mysite/code/CustomSiteConfig.php DataObject::add_extension('SiteConfig', 'CustomSiteConfig');
Now we have to modify (or add) our extended config file to allow us to add a new tab to the global site configuration in admin. /mysite/code/CustomSiteConfig.php
<?php class CustomSiteConfig extends DataObjectDecorator { function extraStatics() { return array( 'has_many' => array( 'MyLocation' => 'LocationEmail' ) ); } }
We create an extraStatics function which will allow us to add new global settings. In this function are defining that we would like many LocationEmail(‘s) to display in our one objectManager. Next we will then add the function to display the content within the tab.
public function updateCMSFields(FieldSet &$fields) { $manager = new DataObjectManager( $this->owner, 'MyLocation', 'LocationEmail', array( 'LocationName' => 'Location name', 'LocationEmailAddress' => 'Email' ), 'getCMSFields_forPopup' ); $manager->setSourceID($this->owner->ID); $manager->setAddTitle( 'a new location' ); $fields->addFieldToTab('Root.EmailLocations', $manager ); return $fields; }
You should now have a workable tab item in your site configuration that you can Create, read, update, delete multiple Email Locations all communicating to the database.
Now how to we display this information in the form displayed at the beginning?
That’s where the fun begins.
I’m assuming you know how to create a new page titled contact. Create and edit the /mysite/ContactPage.php.
class ContactPage_Controller extends Page_Controller { /** * ContactForm the * @return Form */ function ContactForm() { Requirements::customScript(' jQuery(document).ready(function() { jQuery("#Form_ContactForm").validate({ rules: { FirstName: "required", Surname: "required", Location: "required", EmailAddress: { required: true, email: true } }, messages: { FirstName: "Please enter a valid first name", Surname: "Please enter a valid last name", Location: "Please enter a valid location", EmailAddress: "Please enter a valid email address" } }); }); '); $locations = DataObject::get("LocationEmail", '', 'LocationName')->map("ID", "LocationName", "Please Select"); // Create fields $fields = new FieldSet( new TextField('FirstName', 'First name'), new TextField('Surname', 'Surname'), new EmailField('EmailAddress', 'Email address'), new DropdownField('Location', 'Location', $locations), new TextareaField('Message', 'Message', 3) ); // Create action $actions = new FieldSet( new FormAction('SendContactForm', 'Submit') ); // Create Validators $validator = new RequiredFields('FirstName', 'Surname', 'Location', 'EmailAddress', 'Captcha'); $validator->setJavascriptValidationHandler('none'); $form = new Form($this, 'ContactForm', $fields, $actions, $validator); $form->setTemplate('Forms/ContactrForm'); return $form; }
There is nothing really new to the code above, it follows a standard way that forms are written and validated using the bassistance jquery validation techniques.
The main thing to note is line 30 where we declare the $locations array. This line will retrieve all the fields from the EmailLocations table and will map the LocationName field to the ID. This will be used as the key->value pair in our select box.
Line 37 declares our select box called location, and populates it with the $locations array.
In themes folder themeName/templates/Forms/ContactEmail.ss, the locations field can now be accessed (note that below is a snippet from the entire form template)
<li id="Location" class="field text"> <label for="{$FormName}_Location">Location:</label> $dataFieldByName(Location) </li>
By now you can display the contact form, and submit it – but nothing happens, the last step is sending the email to the correct Location.
function SendNewsletterForm($data) { // Find the email address of the user $email_destination = DataObject::get_by_id("LocationEmail", $data['Location']); $emailDestinationName = $email_destination->LocationName; //Set data for email to State/Location $From = $data['EmailAddress']; $Name = $data['FirstName'] . ' ' . $data['Surname']; $To = $email_destination->LocationEmailAddress; $Subject = "TESTING NEW WEBSITE:"; $email = new Email($From, $To, $Subject); //set template $email->setTemplate('ContactEmail'); //populate template $email->populateTemplate($data); // Populate the newly found Location name $email->populateTemplate(array('EmailDestinationName' => $emailDestinationName)); //send mail $success = $email->send(); //Set data for email to recipient $From = $email_destination->LocationEmailAddress; $To = $data['EmailAddress']; $email_recipient = new Email($From, $To, $Subject); //set template $email_recipient->setTemplate('ContactEmail'); //populate template $email_recipient->populateTemplate($data); // Populate the newly found Location name $email_recipient->populateTemplate(array('EmailDestinationName' => $emailDestinationName)); $success = $email_recipient->send(); //return to submitted message Director::redirect($this->Link("?contactformsuccess=1")); }
Lines 3, 4, and 17 are the only related location information that I feel needs to be explained. On line 3, we query the LocationEmail table for the row where the id equals the form key that was passed for the Location select box. We then get the LocationName attribute from the object (db row) returned.
On line 17, we make sure to populate our email template file with the destination name. This gives the human friendly name of the location the user originally selected.
Test it out, and everything should work as planned.
Please ask questions if you get stuck, and happy Silverstriping 🙂