When someone subscribes to the Magento newsletter I also want them to fill in their first and last name. I have added the two input fields to the form. The field names are 'firstname' and 'lastname'.
I'm going to extend Mage/Newsletter/controllers/SubscriberController.php
In newAction():
I have retrieved the post variables here:
$email = (string) $this->getRequest()->getPost('email');
$firstname = (string) $this->getRequest()->getPost('firstname');
$lastname = (string) $this->getRequest()->getPost('lastname');
I have added the following code after the success message:
$subscriber = Mage::getModel('newsletter/subscriber')->loadByEmail($email);
$subscriber->setEmail("example#email.com");
$subscriber->setFirstname("ADAM");
$subscriber->setLastname("MOSS");
$subscriber->save();
I just want to get the first and last name method working - the setEmail part works perfectly. I looked in Model/Subscriber.php and saw that there's no function for setting subscriber names.
Looking at the grid in the admin I also noticed that it says 'Customer First Name' and 'Customer Last Name' so I assume the names belong to the customer model rather than the subscriber model.
Is there a way around this? I want to be able to assign the customer name to the subscriber when they subscribe to the newsletter. I tried the observer method mentioned on this post, but I think the same issue exists: Adding a custom field to Magento's subscription module
Any help would be much appreciated.
Take a look at newsletter_subscriber table in the database. There is no firstname or lastname. You set these fields only on the newsletter model.
The subscribe() method from subscriber model associate the subscriber to customer id so the grid shows indeed the customer firstname and lastname.
If you want to have these fields also for subscribers that are not associated to cutomers you should modify the newsletter_subscriber database table by adding these two fields.
You must create a local copy of:
app/code/core/Mage/Newsletter/controllers/SubscriberController.php
app/code/core/Mage/Newsletter/Model/Subscriber.php
In app/code/core/Mage/Newsletter/controllers/SubscriberController.php add after line 44:
$firtname = (string) $this->getRequest()->getPost('firstname');
$lastname = (string) $this->getRequest()->getPost('lastname');
Then change from:
$status = Mage::getModel('newsletter/subscriber')->subscribe($email);
to:
$status = Mage::getModel('newsletter/subscriber')->subscribe($email,$firtname,$lastname);
Now in app/code/core/Mage/Newsletter/Model/Subscriber.php edit the subscribe function signature at line 307 from:
public function subscribe($email)
to:
public function subscribe($email,$firstname,$lastname)
Add this after line 338:
$this->setSubscriberFirstname($firstname);
$this->setSubscriberLastname($lastname);
And add the getters and setters for it:
/**
* Alias for getSubscriberFirstname()
*
* #return string
*/
public function getFirstname()
{
return $this->getSubscriberFirstname();
}
/**
* Alias for setSubscriberFirstName()
*
* #param string $value
*/
public function setFirstname($value)
{
return $this->setSubscriberFirstname($value);
}
/**
* Alias for getSubscriberLastname()
*
* #return string
*/
public function getLastname()
{
return $this->getSubscriberLastname();
}
/**
* Alias for setSubscriberLastname()
*
* #param string $value
*/
public function setLastname($value)
{
return $this->setSubscriberLastname($value);
}
You also need to add firstname and lastname columns to newsletter_subscriber as said in the other anwser.
Related
I am working with webhooks for the first time, in which I have to pass some 3 variables defined for later when Laravel takes it again I can update an action of the email sent for some reports.
The problem is that I can't pass data in the header of the email.
This is the structure that commonly sent the email to the users:
public $data;
/**
* Create a new message instance.
*
* #return void
*/
public function __construct($view, $subject, $data)
{
$this->view = $view;
$this->subject = $subject;
$this->data = $data;
}
public function build()
{
$message = $this->data;
// print_r($variables);
// exit;
return $this->from(config('mail.from.address'), config('mail.from.name'))
->view($this->view)
->subject($this->subject); //WORKED
/**NO WORKED*/
->withSwiftMessage(function ($message) use ($v){
$v->getHeaders()
->addTextHeader('Custom-Header', 'HeaderValue1')
->addTextHeader('Custom-Header2', 'HeaderValue2');
});
}
The emails if sent in that there is no problem, with the view and the data that is filled in the mail, but in the header the data is not filled in at least in this case, the 2 variables set ['Custom-Header', 'HeaderValue1', 'Custom-Header', 'HeaderValue2].
I had the same problem too and it took me quite a bit of research and testing. It seems that it needs to be in json format and you need to use 'X-Mailgun-Variables' instead of 'Custom-Header'. It should look like this
->addTextHeader('X-Mailgun-Variables', '{"variable1": "1", "variable2": "2"}')
the webhook should give you this result
"user-variables":{
"variable1":"1",
"variable2":"2"
},
How can we change the position (Sort Order) of admin form element?
TL;DR:
You can specify a caret ^ as an optional fourth argument when defining your field:
$fieldset->addField('my_element','text',array(
'name' => 'my_element',
'label' => Mage::helper('customer')->__('My Element')
),'^');
More Information
See Varien_Data_Form_Abstract::addField:
/**
* Add child element
*
* if $after parameter is false - then element adds to end of collection
* if $after parameter is null - then element adds to befin of collection
* if $after parameter is string - then element adds after of the element with some id
*
* #param string $elementId
* #param string $type
* #param array $config
* #param mixed $after
* #return Varien_Data_Form_Element_Abstract
*/
public function addField($elementId, $type, $config, $after=false)
{
if (isset($this->_types[$type])) {
$className = $this->_types[$type];
}
else {
$className = 'Varien_Data_Form_Element_'.ucfirst(strtolower($type));
}
$element = new $className($config);
$element->setId($elementId);
if ($element->getRequired()) {
$element->addClass('required-entry');
}
$this->addElement($element, $after);
return $element;
}
The comments tell you how to order your elements. So, to position your field, specify a fourth argument $after of somefield or whatever is the ID of the field you wish to place yours after.
This is useful when you are extending the customer account form within your own class. Here's an example that places a new form element above the first in the form:
class Yourcompany_Adminhtml_Block_Customer_Edit_Tab_Account extends Mage_Adminhtml_Block_Customer_Edit_Tab_Account {
...
public function initForm() {
parent::initForm();
$form=$this->getForm();
$fieldset=$form->getElement('base_fieldset');
$fieldset->addField('my_element','text',array(
'name' => 'my_element',
'label' => Mage::helper('customer')->__('My Element')
),'^');
return $this;
}
...
}
You may notice something strange. My fourth argument to the addField call is a caret ('^'). This places the element at the very top of the form, which is what you appear to be asking in your question.
But wait! Why doesn't this match up to the code documentation shown above?! Well, it looks like a disconnect in consistent coding convention during development. If you follow the code, you will find that addField makes it way to the Varien_Data_Form_Element_Collection::add method. It is in here that we see a 2nd argument, $after, which notes in the comments:
/**
* Add element to collection
*
* #todo get it straight with $after
* #param Varien_Data_Form_Element_Abstract $element
* #param boolean|'^'|string $after
* #return Varien_Data_Form_Element_Abstract
*/
public function add(Varien_Data_Form_Element_Abstract $element, $after=false)
Here we find that false appends the element to the fieldset, a ^ character prepends the element, and passing in an element ID will place the element after the one specified.
UPDATE: How to Deal With Existing Fields
What if you want to re-order an existing field? Unfortunately, ordering takes places at the time of adding the field, and cannot conveniently be changed after that. But I can offer 2 approaches to get the job done.
Method 1: Re-Order by Removing and Adding Again
$fieldset->removeField('core_element');
$fieldset->addField('core_element','text',array(
'name' => 'core_element',
'label' => Mage::helper('customer')->__('Core Element')
),'^');
This is a simple solution, but requires you to manually re-define that field. In some cases this will be easy enough. In others, not so. For those scenarios, see next.
Method 2: Re-Order by Cloning
$element=clone $form->getElement('core_element');
$fieldset->removeField('core_element');
$fieldset->addElement($element,'^');
I think this is the best solution, because it preserves the element definition as it was originally written. This is especially important in the case of attributes whose fields are generated in part by their frontend_input_renderer classes. Learn more about that here.
Check the 'attribute_id' & 'sort_order' fields in 'customer_eav_attribute' table.
in Joomla component forms :
is there a way to dynamically change the form field property : "readonly" ?
example :
if( _condition_ )
$this->form->getInput('Name')->readonly = true;
From what I saw in the API, you basically can change it.
I see it like this:
When you call $this->form->getInput('Name') you are inside JFormField object (actually inside an class which interits JFormField, which is abstract - inherited by JFormFieldText for example), calling the method getInput().
This method, getInput(), gets its parameters $element ( SimpleXMLElement object of the XML element that describes the form field.) from what I can see directly from the XML you defined and it returns just a string (actual HTML), so setting and non existing property obviously won't work.
But JForm has a nice method called setFieldAttribute(), see signature below:
/**
* Method to set an attribute value for a field XML element.
*
* #param string $name The name of the form field for which to set the attribute value.
* #param string $attribute The name of the attribute for which to set a value.
* #param mixed $value The value to set for the attribute.
* #param string $group The optional dot-separated form group path on which to find the field.
*
* #return boolean True on success.
*
* #since 11.1
*/
public function setFieldAttribute($name, $attribute, $value, $group = null)
So your code can look like:
if( _condition_ )
{
$this->form->setFieldAttribute('Name', 'readonly', 'true', $group = null);
echo $this->form->getInput('name');
}
Hope this helps.
do anyone know how can I apply rule in Yii model for input must be greater than 0 value, without any custom approach ..
like :
public function rules()
{
return array(
....
....
array('SalePrice', 'required', "on"=>"sale"),
....
....
);
}
many thanks ..
Simpler way
array('SalePrice', 'numerical', 'min'=>1)
with a custom validator method
array('SalePrice', 'greaterThanZero')
public function greaterThanZero($attribute,$params)
{
if ($this->$attribute<=0)
$this->addError($attribute, 'Saleprice has to be greater than 0');
}
I see it is a price so you could use 0.01 (a penny) as a minimum value like so:
array('SalesPrice', 'numerical', 'min'=>0.01),
Note that this solution does not validate that the number entered is a price, just that it is > 0.01
I know I am too late for this . But just for future reference you can use this class also
<?php
class greaterThanZero extends CValidator
{
/**
* Validates the attribute of the object.
* If there is any error, the error message is added to the object.
* #param CModel $object the object being validated
* #param string $attribute the attribute being validated
*/
protected function validateAttribute($object,$attribute)
{
$value=$object->$attribute;
if($value <= 0)
{
$this->addError($object,$attribute,'your password is too weak!');
}
}
/**
* Returns the JavaScript needed for performing client-side validation.
* #param CModel $object the data object being validated
* #param string $attribute the name of the attribute to be validated.
* #return string the client-side validation script.
* #see CActiveForm::enableClientValidation
*/
public function clientValidateAttribute($object,$attribute)
{
$condition="value<=0";
return "
if(".$condition.") { messages.push(".CJSON::encode($object->getAttributeLabel($attribute).' should be greater than 0').");
}";
}
}
?>
Just make sure this class is imported before use.
Did nobody check the docs?
There is a built-in validator CCompareValidator:
['SalePrice', 'compare', 'operator'=>'>', 'compareValue'=>0]
you can use this one too:
array('SalePrice', 'in','range'=>range(0,90))
I handled this by regular expression, may be it will help too ..
array('SalePrice', 'match', 'not' => false, 'pattern' => '/[^a-zA-Z0]/', 'message' => 'Please enter a Leader Name', "on"=>"sale"),
many thanks #sdjuan & #Ors for your help and time ..
I have a user entity and I'm trying to update it from a UserService. The problem comes when I try to update a property which is set as an array collection.
/**
*
* #param \Doctring\Common\Collections\Collection $property
* #OneToMany(targetEntity="Countries",mappedBy="user", cascade={"persist", "remove"})
*/
private $countries;
I'm not sure if I'm supposed to somehow delete all the $countries before I set them back or if there's a way to select which ones to delete and set up the different ones....this is what my updateUser method looks so far:
public function updateUser($user) {
$entity = $this->getUser($user['id']);
if (!$entity)
throw new Exception('Error saving user!');
$countries = $this->getCountriesArray($user); //countries already set in the db
$tempCountries = array();
$delete = array();
foreach ($countries as $country) {
$found = false;
if (in_array($country, $user['countries'])) {
$tempCountries[] = $country;
} else {
$delete[] = $country;
}
}
$tempCountries = array_unique(array_merge( //combine the countries from the db we want to leave
$tempCountries, //with those the user selected
$user['countries']));
...
//here I need something to remove the countries in $delete...right?
...
$entity->setEmail($user['email']);
$entity->setResponsable($user['responsable']);
$entity->setPassword($this->createPass($user['password']));
$entity->setUrl($user['url']);
$entity->setRole($user['role']);
$modelCountries = array();
foreach($tempCountries as $c) {
$p = new Countries();
$p->setCountryName($c);
$p->setUser($entity);
$modelCountries[] = $p;
}
$entity->setCountries($modelCountries);
$this->em->persist($entity);
$this->em->flush();
}
please stackOverflow... give me a hand making sense out of this.
It actually depends on your use case.
As you said, you can either delete all countries before to set the new ones, or compute the delta, and update only the needed ones.
What countries are you providing to your service? The delta? Or full list?
Do you have performance constraints? If yes, what is the cost of a DELETE statements vs SELECT then UPDATE?
Compute delta, then UPDATE can be tricky and difficult, in most case, you better want to just DELETE all and INSERT.
For my current and personal choice I am using DQL to DELETE all owing side rows for the mapped entity and then inserting the new one.
class Rule
{
/**
* #OneToMany(targetEntity="Tier", mappedBy="rule", cascade={"persist", "remove"})
* #JoinColumn(name="ruleId", referencedColumnName="ruleId")
* #var Tier[]
*/
public $tiers;
So when I am passing new Tier in my call I am simply Deleting the all Tiers for that Role from the Rule Mapper
public function resetTiers($ruleId)
{
$modelClass = "Tier";
$q = $this->doctrineEntityManager->createQuery("Delete from $modelClass m where m.rule =" . $ruleId);
$numDeleted = $q->execute();
return $numDeleted;
}
and then calling the usual
$this->doctrineEntityManager->persist($rule);
$this->doctrineEntityManager->flush();
Hope that helps