laravel 4.1 unique validation on update fails - php

Laravel 4.1. I want to update a city, check the rules and it fails on unique check.
Rules:
public static $rules = [
'name' => 'required|alpha_dash|unique:cities',
'slug' => 'alpha_dash|unique:cities',
'seo_title' => 'required|max:60|unique:cities',
'seo_description' => 'required|max:160|unique:cities',
'rank' => 'integer',
'visible' => 'integer'
];
I know, I can smth like:
'name' => 'required|alpha_dash|unique:cities, name, ##',
where ## - id, but I cant dynamically set id to updated one.
'name' => "required|alpha_dash|unique:cities, name, $id", // doesnt work
'name' => "required|alpha_dash|unique:cities, name, $this->id", // doesnt work
Is there any way to do it normally ?

You can do it in separate ways.
An easy way is to use different rules based on different actions . When you will create the model, you will use the rules that you currently have.
When you will update the model, you will change the unique:cities to exists:cities
I usually do this with a validation service.
You create a base abstract Validator in services/ , which has a passes() function.
For each model, you create a ModelValidator , in your case CityValidator. Where you put your rules like :
public static $rules = [
'new'=>[
'name' => 'required|alpha_dash|unique:cities',
'slug' => 'alpha_dash|unique:cities',
'seo_title' => 'required|max:60|unique:cities',
'seo_description' => 'required|max:160|unique:cities',
'rank' => 'integer',
'visible' => 'integer'],
'edit'=>[
'name' => 'required|alpha_dash|exists:cities',
'slug' => 'alpha_dash|unique:cities',
'seo_title' => 'required|max:60|exists:cities',
'seo_description' => 'required|max:160|exists:cities',
'rank' => 'integer',
'visible' => 'integer'
]
];

The 3rd argument accepts a value to be ignored... If you want to do a WHERE clause, do it like:
'name' => array("required", "alpha_dash", "unique:cities,name,null,id,id,$this->id"...
The docs says:
Adding Additional Where Clauses
You may also specify more conditions that will be added as "where"
clauses to the query:
'email' => 'unique:users,email_address,NULL,id,account_id,1'
In the rule above, only rows with an account_id of 1 would be included in the unique check.
Learn by example:
email => unique:users,email_address,id,NULL,field_1,value_1,field_2,value_2,field_x,value_x
Generates the query:
SELECT
count(*) AS AGGREGATE
FROM
`entries`
WHERE
`email_address` = ?
AND `id` <> NULL
AND `field_1` = `value_1`
AND `field_2` = `value_2`
AND `field_x` = `value_x`

I found an elegant-ish way to do this using fadion/ValidatorAssistant:
<?php
use Fadion\ValidatorAssistant\ValidatorAssistant;
class CityValidator extends ValidatorAssistant {
// standard rules
public static $rules = [
'name' => 'required|alpha_dash',
'slug' => 'alpha_dash',
'seo_title' => 'required|max:60',
'seo_description' => 'required|max:160',
];
// some preparation before validation
protected function before()
{
// Inject the given city id into the unique rules
$this->rules['name'] .= 'unique:cities,name,' . $this->inputs['id'];
$this->rules['slug'] .= 'unique:cities,slug,' . $this->inputs['id'];
$this->rules['seo_title'] .= 'unique:cities,seo_title,' . $this->inputs['id'];
$this->rules['seo_description'] .= 'unique:cities,seo_description,' . $this->inputs['id'];
}
There's almost certainly a more elegant way to do this when you need several fields to be unique database-wide, but the above works very well for times when you only need one part to be unique.

Related

Update/Insert parent with child based on validation rules Laravel

I want to update/insert my parent directly with my child instead of separated them. After my validation rule has passed.
my code:
$validatedData = $request->validate([
'id' => 'bail|integer',
'code' => 'bail|integer',
'name' => 'bail|required|string|max:255',
'child' => 'bail|array',
'child.something' => 'bail|integer',
]);
$parent = Parent::updateOrCreate(['id' => $request->id, 'code' => $request->code], $validatedData);
You can't. You need to update the child after the parent is successfully updated.

View Referencing it's self - Laravel 5.5

So I am new to laravel. I am trying to use a view but it keeps referencing its self with links.
See below what I mean
So I have a route "customers"
Route::get('customers/{cid?}', [
'uses' => 'customers#getCustomerView'
])->name('customers');
In this route as you can see I reference a controller getCustomerView. With an optional CID as someone might just want to see a list of customers. Then choose their customer. So here is the controller function
public function getCustomerView($cid = null){
$activeCustomer = array();
if(!empty($cid)){
// do middleware to get customer active detail
$activeCustomer = array(
'company' => 'Company '.$cid,
'fname' => 'Test',
'lname' => 'test'
);
}
return view('customers.view', [
'title' => 'Customer List',
'cid' => $cid,
'activeCustomer' => $activeCustomer,
'clist' => [
['company'=>'Company 1', 'fname' => 'Bob', 'lname' => 'Smith'],
['company'=>'Company 2', 'fname' => 'Julie', 'lname' => 'Reid'],
['company'=>'Company 3', 'fname' => 'Tony', 'lname' => 'Tima']
]
]);
}
When I load http://domain/customers - Everything works fine.
In my customers.view I have the following that loops and put's the array into a table. Later I will be using some middle ware or self function to get data from database. For now I am just using a harden array.
#foreach($clist as $key=>$customer)
<tr>
<td>{{$key+1}}</td>
<td>{{$customer['company']}}</td>
<td>{{$customer['fname']}}</td>
<td>{{$customer['lname']}}</td>
</tr>
#endforeach
The problem lies. Once I click on a customer. Page loads fine. http://domain/customers/1 - But if I go to click on another customer it does this
http://domain/customers/1/customers/2 - obviously this would cause an error. So why is it doing this?
How can I prevent it?
use this :
<td>{{$customer['company']}}</td>
it will generate a full url like http://domain/customers/1
but you can simply do that :
<td>{{$customer['company']}}</td>

How can I specify multiple columns to be searched with PHP?

I recently built a website for work because our techs need an easy way to find out what keys go to which properties we provide service to. I've gotten the site working with live search (Ajaxlivesearch.com) and it's linked to my MySQL database. Everything works great except it only searches one column currently, the Address column. I'd like to be able to search two columns, Address and Property_Name at the same time.
Here's the current code, or at least the part that deals with searching the db.
<?php
namespace AjaxLiveSearch\core;
if (count(get_included_files()) === 1) {
exit('Direct access not permitted.');
}
/**
* Class Config
*/
class Config
{
/**
* #var array
*/
private static $configs = array(
// ***** Database ***** //
'dataSources' => array(
'ls_query' => array(
'host' => '',
'database' => '',
'username' => '',
'pass' => '',
'table' => '',
// specify the name of search columns
'searchColumns' => array('Address'),
// specify order by column. This is optional
'orderBy' => '',
// specify order direction e.g. ASC or DESC. This is optional
'orderDirection' => '',
// filter the result by entering table column names
// to get all the columns, remove filterResult or make it an empty array
'filterResult' => array(),
// specify search query comparison operator. possible values for comparison operators are: 'LIKE' and '='. this is required.
'comparisonOperator' => 'LIKE',
// searchPattern is used to specify how the query is searched. possible values are: 'q', '*q', 'q*', '*q*'. this is required.
'searchPattern' => 'q*',
// specify search query case sensitivity
'caseSensitive' => false,
// to limit the maximum number of result uncomment this:
'maxResult' => 10,
// to display column header, change 'active' value to true
'displayHeader' => array(
'active' => true,
'mapper' => array(
'Property_Name' => 'Property Name',
'Address' => 'Address',
'Key' => 'Key',
'Property_Manager' => 'Property Manager',
'Door_Code' => 'Door Code'
)
),
// add custom class to <td> and <th>
// To hide a column use class 'ls_hide'
'columnClass' => array(
'Count' => 'ls_hide',
'Reserve' => 'ls_hide'
),
'type' => 'mysql',
),
I've taken the connection info out for obvious reasons.
I tried 'searchColumns' => array('Address' AND 'Property_Name'), thinking that would search both columns but that didn't work at all.
I'm not familiar with Ajaxlivesearch, but it looks like searchColumns takes an array, so:
'searchColumns' => array('Address', 'Property_Name'),
will probably work.
(array('Address' AND 'Property_Name') is a syntax error.)
And of course as soon as I post the question I figure it out, maybe it will help someone else though. To look at multiple columns in one array you need to separate them with a comma (,) the working code is:
<?php
namespace AjaxLiveSearch\core;
if (count(get_included_files()) === 1) {
exit('Direct access not permitted.');
}
/**
* Class Config
*/
class Config
{
/**
* #var array
*/
private static $configs = array(
// ***** Database ***** //
'dataSources' => array(
'ls_query' => array(
'host' => '',
'database' => '',
'username' => '',
'pass' => '',
'table' => '',
// specify the name of search columns
'searchColumns' => array('Address', 'Property_Name'),
// specify order by column. This is optional
'orderBy' => '',
// specify order direction e.g. ASC or DESC. This is optional
'orderDirection' => '',
// filter the result by entering table column names
// to get all the columns, remove filterResult or make it an empty array
'filterResult' => array(),
// specify search query comparison operator. possible values for comparison operators are: 'LIKE' and '='. this is required.
'comparisonOperator' => 'LIKE',
// searchPattern is used to specify how the query is searched. possible values are: 'q', '*q', 'q*', '*q*'. this is required.
'searchPattern' => 'q*',
// specify search query case sensitivity
'caseSensitive' => false,
// to limit the maximum number of result uncomment this:
'maxResult' => 10,
// to display column header, change 'active' value to true
'displayHeader' => array(
'active' => true,
'mapper' => array(
'Property_Name' => 'Property Name',
'Address' => 'Address',
'Key' => 'Key',
'Property_Manager' => 'Property Manager',
'Door_Code' => 'Door Code'
)
),
// add custom class to <td> and <th>
// To hide a column use class 'ls_hide'
'columnClass' => array(
'Count' => 'ls_hide',
'Reserve' => 'ls_hide'
),
'type' => 'mysql',
),
Run code snippetCopy snippet to answer

Converting undefined indexes to null in PHP

I'm not sure if the title of this question is necessarily the accurate description of what I need to do, but I'll go ahead and ask my question and see what everyone thinks...
Basically, I am receiving data from a source that I have no control over, and I need to transpose it into a suitable format for inserting into my database using CakePHP. So, here's how I'm doing it:
public function submitApp($data) {
$array = array(
'Student' => array(
'name' => $data['name'],
'email' => $data['email'],
'phone' => $data['phone'],
'address' => $data['address'],
'dob' => $data['dob'],
'gender' => $data['gender']
),
'Application' => array(
'course_id' => $data['course_id'],
'question1' => $data['question1'],
'question2' => $data['question2'],
'question3' => $data['question3'],
'question4' => $data['question4'],
),
'ApplicationQualification' => $data['Qualifications']
);
// Logic to save $array goes here
}
The problem is that sometimes not all of the keys in $data will be submitted to my app but I still want my app to work with what it gets.
I know that I can wrap each key in a conditional like this:
if (!isset($data['name'])) { $data['name'] = null; }
...and then building the array, but this seems like a pretty clumsy way of doing it. Is there a more efficient way to do this?
You could use a simple ternary statement
'name' => array_key_exists('name', $data) ? $data['name'] : null
Alternatively, you can set up a default array and then merge the given values in
$defaults = [
'name' => null,
'email' => null,
// etc
];
$data = array_merge($defaults, $data);

Cakephp - saveAll and beforeSave

Since CakePHP is updated to 2.3.5, I have problem to save data.
I don't want to save datas who contains no price.
My method beforeSave in my model looks like this :
public function beforeSave($options = array()){
if(empty($this->data['MyModel']['price'])){
unset($this->data['MyModel']);
}
return true;
}
Since my update, i've found this in /lib/Model/Model.php (l. 1751)
if ($success && $count === 0) {
$success = false;
}
If i comment this 3 lines my problem is solved. Do you know a method in my beforeSave who don't block my saving ?
If i use data validation, all my datas are not saved with my saveAll.
Exemple model "Option" validator:
public $validate = array(
'prix' => array(
'rule' => 'notEmpty'
)
);
Exemple datas to save :
array(
'Commande' => array(
'nature_commande' => '0',
'base_id' => '1',
'nom' => 'Test',
'chef_id' => '531',
),
'Option' => array(
(int) 0 => array(
'prix' => '5456'
),
(int) 1 => array(
'prix' => '45645'
),
(int) 3 => array(
'prix' => ''
)
)
saveAll in my Controller "Commande" (return false):
debug($this->Commande->saveAll($this->request->data, array('validate' => 'first')));
I would like my datas be saved out of the last row in my Model "Options" => 3.
I can use foreach in my controler to delete the blank row but can i make it better ?
Have you thought about using CakePHP's built-in data validation? This would allow you to specify that you don't want to save unless the 'price' is a certain amount, greater than zero, between a range...etc etc etc.
Basically, you set up rules for your fields, and any time you try to save a row, it makes sure each field passes whatever validation you set up.
It has a ton of validation types including valid email, number ranges, phone numbers, regex and more.

Categories