Laravel Validator unique value - laravel

I am trying to validate an email address in my Customer table. There is a column in the Customer table called Brand where effectively the same email address could be registered to multiple brands for example:
Email Brand
me#mywebsite.com firstsite.com
me#mywebsite.com secondsite.com
When validating the email address I need to check the email is unique in the Customer table for the current Brand. Currently my validation rule looks like this
$rules = array('email' => 'required|email|unique:Customer,Email');
however Brand must appear in there someone to say the email must be unique to the customer for the current brand
Any help much appreciated

You can use the column and value parameter of the unique validation rule to add a condition to the rule.
'email' => 'required|email|unique:Customer,Email,null,null,column,value'
The problem is you need your Brand input in order to create your rule like this :
$rules['email'] = 'required|email|unique:Customer,Email,null,null,Brand,' . Input::get('Brand');
This rule will check if the email is unique where the brand has the given value.
More information here :
http://laravel.com/docs/validation#rule-unique
There is also a package that could help you :
https://github.com/felixkiss/uniquewith-validator

$rules = array('email' => 'required|email|unique:Customer,Email'); this will query your model for finding the entered email if the email is already present then an error message is raised. so this will not work with your app design flow. you have to run sql query to find out if the email is present with your current brand if yes return error message if not save the data. something like that

I would go for writing my own custom validation rule. Custom validation rule will be more common solution and you can name it as it suites you best. It can be created using the Validator::extend() and a closure, like this :
Validator::extend('awesome', function($field, $value, $params)
{
return $value == 'awesome';
});
or via validator class. Have a research at this topic, maybe here (scroll to custom rules section) or any other source you find.

Related

MorphTo with conditions

I am working with field MorphTo and I try to make conditions for the resources.
For example I have 4 resources:
Accounts
PaymentMethodCreditCard
PaymentMethodBankAccount
Transactions
Every Account can add as many Payment Methods as he wants.
And in the transaction I work with MorphTo to select the Payment Method that the account selected.
My problem starts when I try to create a transaction from Nova and get a list of all the Payment Methods in the db without any relation to the account.
My ideal idea was like that:
MorphTo::make('Transactions')
->withoutTrashed()
->dependsOn('Account', function (MorphTo $field, NovaRequest $request, FormData $formData) {
if(isset($formData->Account)){
$field->types([
PaymentMethodCreditCard::class => fn($q)=>$q->where('account_id', $formData->Account),
PaymentMethodBankAccount::class => fn($q)=>$q->where('account_id', $formData->Account),
]);
}
}),
But of course it will not work, Someone has any idea how I can add conditions to the resource?
I'll give you two answers. Since the question does not exactly clarify whether the Account value is changable during the edit process or it's predefined.
Account value does not change.
If the account value does not change after the resource is loaded, then the solution you are looking for is Relatable Filtering
public static function relatablePaymentMethods(NovaRequest $request, $query)
{
$resource = $request->findResourceOrFail();
return $query->where('account_id', $resource->Account);
}
Account value can change
If the account value can change, then you'll need to create your own "Morph To" behavior using Select and Hidden fields.
With Select field, you can utilize the dependsOn and options functions, to change the query results when the Account changes.

Validate if another field is empty laravel validation

I want to validate field if present and will fail if another field not present
How to do it ? I have create custom validation to get record based id on storage
I have field product_id and amount and the amount field validate between max and min based on product_id, if i present the amount = 100000 and not fill the product_id field the validating for amount field is passed and display error because i am not fill the product_id i want check before the custom validation execute will check if product_id empty or not..
I have read all validation method on laravel docs still didnt find the solution.
How to do it ?
Finally i found a solution...
on Form Request class i just add sometimes rule on validate instance so when the product_id field not present on amount field will not validate and when present it will validate using validation rules like this:
class StoreRequest extend FormRequest
{
protected function getValidatorInstance()
{
$validator = parent::getValidatorInstance();
$validator->sometimes('amount', 'required|numeric|max_amount:product_id', function ($input) {
return Arr::has($input, 'product_id');
});
return $validator;
}
}

Laravel unique validation must include appended text when validating

I am using the Laravel tenancy package in which there is a domains table in my database and each value in the domain column within this table is appended with .test.co.uk.
When the user enters the URL in the form, they are presented with an input element (shown above) in which they enter a URL/Domain but the .test.co.uk is already appended so the only thing they need to enter is the text that goes before that, e.g. they would enter johnsmith and in the domain column it would store johnsmith.test.co.uk. The problem I have is that I need the validation on this column to be unique but also include the .test.co.uk when performing the validation so that it looks at the value stored in the table because if a user enters johnsmith and there is currently a record in the domains table where the value is johnsmith.test.co.uk then the validation would pass but I need the validation to fail in this scenario. I am currently using a Request class which is extending the FormRequest class and have this:
public function rules()
{
return [
'url' => 'required|string|unique:domains,domain',
];
}
I have also tried a rule object but I don't think a rule object is the correct solution to this problem. Is there a convenient "Laravel" way of doing this?
In your Request class use prepareForValidation()
Docs: https://laravel.com/docs/7.x/validation#prepare-input-for-validation
protected function prepareForValidation()
{
$this->merge([
'url' => $this->url . '.test.co.uk',
]);
}

Laravel(5.3.24+) Validation: Validate 2 columns

Using the new style of laravel validation seen here: https://laravel-news.com/unique-and-exists-validation
I would like the name column to be required & only unique for a competition.
Using the example table below,
id 3: The validation should stop this from happening, because "a name already exist for that competition".
Custom rule
The best solution would be to create a custom rule for this, that accepts the field with the corresponding competition_id as a parameter.
Something like
//Calling the custom rule like this
['name' => 'required|validateName:yourCompetitionIdFormFieldHere'];
Declaring the custom validation function in your service provider like this
Validator::extend('validateName', function ($attribute, $value, $parameters, $validator) {
$competitionId = ($validator->data, $parameters[0]);
//Now check if the $value is already set for the specific competition_id by using normal database queries and comparison
return count(Team::where("comeptition_id", "=", $competitionId)->whereName($value)->get()) == 0
});
What does it
The custom validation rule receives the data of the field you give with the function (in the code above it's yourCompetitionIdFormFieldHere), so it knows which league/competition_id the user chose. With this information, you now can check if there is already a similar ame for the entered id.

Adding a custom field to Magento's subscription module

The newsletter subscription module in Magento has only one field (email) by default. After I add an extra field to the form (say country), how can I get the form data to show up in the Magento back-end and be sent as an email to a preset recipient? Thanks.
If you want to add some custom fields for Magento newsletter subscriber (for example subscriber_name), you should do the following:
Add new column for newsletter_subscriber table
Add text input to newsletter template
Create observer for newsletter_subscriber_save_before event
In the observer you can get your custom field's value from request and assign it to subscriber's object:
public function newsletterSubscriberSave(Varien_Event_Observer $observer)
{
$subscriber = $observer->getEvent()->getSubscriber();
$name = Mage::app()->getRequest()->getParam('subscriber_name');
$subscriber->setSubscriberName($name);
return $this;
}
UPDATE:
Here is the detailed article explaining how to add Country field
Also, I have created a free module, it is available on the GitHub
There are a few things that you need to take care of to make this work:
Add a new column for your data to the appropriate database table
Make sure that Magento saves your new field to the database
Present the data in the admin backend
Record the data when you get a new newsletter subscription
Here's how you can do all those things:
Ad. 1)
Using phpMyAdmin, MySQL command line, or whatever is your preferred DB manipulation method, add a new column "country" as, say, varchar(100) to the newsletter_subscriber table.
Ad. 2)
Magento will automatically give you access to the new field through the getCountry() and setCountry() methods on the Mage_Newsletter_Model_Subscriber object. The only thing it won't do is save your field back to the DB after it has been changed with code somewhere in the system. To get it saved you need to modify _prepareSave(Mage_Newsletter_Model_Subscriber $subscriber) function found in Mage_Newsletter_Model_Mysql4_Subscriber (app/code/core/Mage/Newsletter/Model/Mysql4/Subscriber.php). Be sure to make a local copy of the file first and not modify the core file. Here's what you need to add:
protected function _prepareSave(Mage_Newsletter_Model_Subscriber $subscriber)
{
$data = array();
$data['customer_id'] = $subscriber->getCustomerId();
$data['store_id'] = $subscriber->getStoreId()?$subscriber->getStoreId():0;
$data['subscriber_status'] = $subscriber->getStatus();
$data['subscriber_email'] = $subscriber->getEmail();
$data['subscriber_confirm_code'] = $subscriber->getCode();
//ADD A NEW FIELD START
//note that the string index for the $data array
//must match the name of the column created in step 1
$data['country'] = $subscriber->getCountry();
//ADD A NEW FIELD END
(...)
}
Ad. 3)
You will need to modify (a local copy of) the file app/code/core/Mage/Adminhtml/Block/Newsletter/Subscriber/Grid.php. The method you are looking for is called _prepareColumns(). In there you will see a series of calls to $this->addColumn(). You need to add a corresponding call for your "Country" field with the following code:
$this->addColumn('country', array(
'header' => Mage::helper('newsletter')->__('Country'),
//the index must match the name of the column created in step 1
'index' => 'country',
'default' => '----'
));
If you want the field to appear at the end of the grid (as the last column) add it as the last call, otherwise, squeeze it between the existing calls exactly where you want it to end up in the admin.
Ad. 4)
This is a part I did not have to do in my customization of the Magento newsletter, so it will be mostly theoretical. The subscription occurs in the controller located at app/code/core/Mage/Newsletter/controllers/SubscriberController.php. Here's the code of the newAction method with my proposed changes:
public function newAction()
{
if ($this->getRequest()->isPost() && $this->getRequest()->getPost('email')) {
$session = Mage::getSingleton('core/session');
$email = (string) $this->getRequest()->getPost('email');
try {
if (!Zend_Validate::is($email, 'EmailAddress')) {
Mage::throwException($this->__('Please enter a valid email address'));
}
$status = Mage::getModel('newsletter/subscriber')->subscribe($email);
if ($status == Mage_Newsletter_Model_Subscriber::STATUS_NOT_ACTIVE) {
$session->addSuccess($this->__('Confirmation request has been sent'));
}
else {
$session->addSuccess($this->__('Thank you for your subscription'));
}
//ADD COUNTRY INFO START
//at this point we may safly assume that subscription record was created
//let's retrieve this record and add the additional data to it
$subscriber = Mage::getModel('newsletter/subscriber')->loadByEmail($email);
//assuming that the input's id is "country"
$subscriber->setCountry((string) $this->getRequest()->getPost('country'));
//don't forget to save the subscriber!
$subscriber->save();
//ADD COUNTRY INFO END
}
catch (Mage_Core_Exception $e) {
$session->addException($e, $this->__('There was a problem with the subscription: %s', $e->getMessage()));
}
catch (Exception $e) {
$session->addException($e, $this->__('There was a problem with the subscription'));
}
}
$this->_redirectReferer();
}
Going through the above steps should take care of the most part of your problem. Let me know how that last part worked out, as I did not have a chance to test it.
Once you have your additional field in the Subscriber object you can do whatever you want with it. I did not really get what you mean by
be sent as an email to a preset recipient
If you can explain that I will try to help you out with this part too.
Edit - how to send a mail when someone subscribes
Just add the following code to the controller after the part which adds country to a subscriber object.
$mail = new Zend_Mail();
$mail->setBodyHtml("New subscriber: $email <br /><br />Country: ".$this->getRequest()->getPost('country'));
$mail->setFrom("youremail#email.com")
->addTo("admin#mysite.com")
->setSubject("Your Subject here");
$mail->send();
Adding to the accepted answer, you can also get away with this a little easier if you're adding a date, datetime, or timestamp-type column.
In my case, I wanted to add a "Subscribed at Date" to my grid. To do this, I wrote my upgrade script, column type being TIMESTAMP and the default value being CURRENT_TIMESTAMP. This way, when the row is added, the current date/time is recorded.
Then, all you have to do is add your block customizations. I'd suggest doing it by extending Magento's grid block rather than doing the local codepool override though. This way, you only need to override _prepareColumns();
Old thread but if someone has the same question, there is a free extension, that adds fields for gender, firstname and lastname and makes it available in the backend grid for export via xml/csv: http://www.magentocommerce.com/magento-connect/extended-newsletter-subscription-for-guests.html
Perhaps you can extend the code to fit your needs.
This is a warning for anyone who's installed the Ebizmarts_MailChimp extension.
It's a great extension. But it adds subscriber_firstname and subscriber_lastname to the newsletter_subscriber table.
If you intend to create these fields, you should either "require" the Ebizmarts_MailChimp extension or check the fields don't exist before your extension creates them.
In the opposite, where you've created them and want to install the the Ebizmarts_MailChimp extension after you've created these fields, you will have to comment out the addColumn code for these two fields during installation.

Resources