Cakephp Validation on API input data - api

I have an API that receives data in JSON, XML and FORM data. The API needs to do a bit of validation that depending on the data provided, depends on the data to be validated. I have a "sendmode" field that is required for each API call. If the sendmode = 1 then mobile,firstname and lastname are required fields, however, if sendmode is 2 then group is a required field.
My question is, how can I validate my data in my model according to data provided in the API call without having to do a bunch of If statements at the beginning of my controller?
Thanks
public function api_send() {
//Get Params
$data = $this->request->input('json_decode', TRUE);
//validate here -> first required
$data['sendmode'] //need to validate
$data['subject'] //need to validate
$data['message'] //need to validate
if($validate == false){
return;
break;
}
switch($data['sendmode']){
case 1:
$data['mobile'] //need to validate
$data['firstname'] //need to validate
$data['lastname'] //need to validate
if($validate == TRUE){
//save data
}
//etc
}
}
So I want all my validation done in my model, but first, I need to validate 3 fields, if thats true I need to continue, then if sendmode is 1, I need to validate other fields, as these fields will not exist if sendmode is 2 or 4 etc

First you pass that json (?) data to a model method. Inside your model have a method that switches the validation rules based on the type.
// Controller
$this->Model->validateApiCall($this->request->input('json_decode', TRUE));
// Model
public function setValidationRules($type = 'someDefault') {
switch($type){
case SendMode::GROUP_FIELDS:
$this->validate = array(/* your rules for that type here */);
// ...
}
public function validateApiCall($data) {
$this->setValidationRules($data['type']);
// return or do something else with the data depending on it if its validated or not
return $this->validate($data);
}
Oh, and if you really want to use integers for the types I would recommend to use constants like SendMode::GROUP_FIELDS. I usually create a tableless model for that. Constants are a lot better because if you do a typo it brings up a syntax error and while using plain integers nobody never ever is going to remember what the meaning of a random 3 or 4 or 1 is.

Related

Yii2 REST API relational data return

I've set up Yii2 REST API with custom actions and everything is working just fine. However, what I'm trying to do is return some data from the API which would include database relations set by foreign keys. The relations are there and they are actually working correctly. Here's an example query in one of the controllers:
$result = \app\models\Person::find()->joinWith('fKCountry', true)
->where(..some condition..)->one();
Still in the controller, I can, for example, call something like this:
$result->fKCountry->name
and it would display the appropriate name as the relation is working. So far so good, but as soon as I return the result return $result; which is received from the API clients, the fkCountry is gone and I have no way to access the name mentioned above. The only thing that remains is the value of the foreign key that points to the country table.
I can provide more code and information but I think that's enough to describe the issue. How can I encode the information from the joined data in the return so that the API clients have access to it as well?
Set it up like this
public function actionYourAction() {
return new ActiveDataProvider([
'query' => Person::find()->with('fKCountry'), // and the where() part, etc.
]);
}
Make sure that in your Person model the extraFields function includes fKCountry. If you haven't implemented the extraFields function yet, add it:
public function extraFields() {
return ['fKCountry'];
}
and then when you call the url make sure you add the expand param to tell the action you want to include the fkCountry data. So something like:
/yourcontroller/your-action?expand=fKCountry
I managed to solve the above problem.
Using ActiveDataProvider, I have 3 changes in my code to make it work.
This goes to the controller:
Model::find()
->leftJoin('table_to_join', 'table1.id = table_to_join.table1_id')
->select('table1.*, table_to_join.field_name as field_alias');
In the model, I introduced a new property with the same name as the above alias:
public $field_alias;
Still in the model class, I modified the fields() method:
public function fields()
{
$fields = array_merge(parent::fields(), ['field_alias']);
return $fields;
}
This way my API provides me the data from the joined field.
use with for Eager loading
$result = \app\models\Person::find()->with('fKCountry')
->where(..some condition..)->all();
and then add the attribute 'fkCountry' to fields array
public function fields()
{
$fields= parent::fields();
$fields[]='fkCountry';
return $fields;
}
So $result now will return a json array of person, and each person will have attribute fkCountry:{...}

adfs 3.0 custom attribute store dynamic claim types

In our ADFS 3.0 we have a custom attribute-store that communicates with a rest-service to retrieve specific attributes based on the userid. These attributes comes with an urn and a value. My goal was to have the urn retrieved from the rest-service set to the claim-type but this type seems to be set in the so called template you create from the gui of ADFS. See below code:
c:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname"]
=> issue(store = "Custom_AttributeStore", types = ("my:custom:urn"), query = "dummyString", param = c.Value);
Is it possible with adfs claim rule language to set the claim types programmatically in my custom attributestore?
There is a way to dynamically emit any pair of claim type and value from a custom attribute store. This article helped me to figure it out.
Your custom attribute store needs to return a single column of string values, where each value represents a single claim type and its corresponding value, separated by a special character (a semicolon in this example):
public string[][] EndExecuteQuery(IAsyncResult result)
{
...
return new[]
{
new[] { "http://example/custom-type-1;Value 1" },
new[] { "http://example/custom-type-2;Value 2" },
...
};
}
Next, use a custom claim rule to retrieve values from your custom attribute store and create input claims of an arbitrary type from them. Use the add command (which creates input claims) instead of the issue command (which creates output claims).
c:[Type == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"] => add(store = "YourCustomAttributeStore", types = ("custom-type-value-pair"), query = "YourQuery", param = c.Value);
Finally, use another custom claim rule to pick up each of the input claims created in the previous step and use their values to issue the proper output claims. The RegexReplace function can be used to separate type and value.
c:[Type == "custom-type-value-pair"] => issue(Type = RegexReplace(c.Value, ";.*$", ""), Value = RegexReplace(c.Value, "^.*?;", ""));
It may be a little convoluted, but it works.

CakePHP Accessing Passed Form Data in table afterSave()

SOLVED! I created a $password property in my Entity class thinking I needed to. The password field is added to the Entity through the entire request. None of the code posted below had to be changed.
I am using friendsofcake/Crud to build a REST api. When I save my User models, I have an afterSave() event that does the password salting and hashing. The POST data sent to my UsersController:add() method includes a ['password'] parameter, but my UsersTable has ['hash','salt'] fields.
Basically, I need to know if and where the POST['password'] parameter is, and if it is available in the UsersTable afterSave() method. Otherwise, my system is hashing and salting empty password strings!
I am new to CakePHP and having trouble finding straightforward answers for 3.*.
Here is the afterSave() method in my UsersTable class.
/**
* Updates Meta information after being created.
*/
public function afterSave(Event $event, Entity $entity, ArrayObject $options)
{
if($entity->returnAfterSave) return;
// update the public id
if(empty($entity->public_id))
{
$hashids = new Hashids(static::HASH_SALT, static::HASH_LENGTH);
$entity->public_id = $hashids->encode($entity->id);
}
// generate a password salt
if(empty($entity->salt))
{
$entity->generateSalt();
}
// salt and hash the password
if(empty($entity->hash))
{
// NOTE: I figured since the form data
// is loaded into the entity, I created a $password property
// in my User Entity class. This assumption may be the problem??
// Update: It was a bad assumption. Removing said property solved issue.
$entity->hashPassword();
}
// save the changes
$entity->returnAfterSave = true;
$this->save($entity);
}
Also, I understand that this code will not properly save any new passwords, I will update the code for password changes after my creates are working properly.

Domain class auto validation in grails

I am fetching list of results from database but the list doesn't validates the constraints until i call "validate()" method for each objects.
def temp = ConfigInfo.where { projectId == project }.findAll()
//at this stage domain class is not validated
temp.each {
println "validate" + it.validate()
println "has error" + it.hasErrors()
}
//in the above code block validate() is called, I don't want to do this.
// is it possible to configure it happen automatically and i get the validated objects.
I don't want to invoke validate method.
is there any way or configuration in grails such that domain class get validated automatically.
Please help me in this.
Grails domain class objects get validated before save.
Use the following in your domain model to set the validation rules:
static constraints = {
// whatever you want to validate
}
Whenever you save an object it will be validated by the constraints you set. When the object is persistent in the database it has always been validated.
All you need to do is that just define all your validation in constraints closure.
e.g.
static constraints = {
id maxLength: 5
//etc...
}
at the time of saving object you just need to check object is validate or not!, it will return true/false.
look this: click here

How to validate >1 field at a time, in a Zend sub-form?

I've created a 3 screen "wizard" using the Zend_Form_SubForm example from the online reference documentation.
The requirement I'm having trouble meeting is this:
If fields 1, 2, & 3 of the first screen are already in the database, notify the user that they are trying to add a duplicate record. Each of those fields has their own validators. Somehow I need to add this "group validator".
So, at its most basic level, I'm trying to do:
if($field_1_not_in_db && $field_2_not_in_db && $field_3_not_in_db){
return true;//validation OK
} else {
return false;//invalid data
}
I am coming up against several issues, though:
1) Because it applies to multiple fields, I don't know which field to attach it to. Error messages appear beside the field they are attached to, so this is important... unless I can get these "multi-field validator" errors to appear at the top of the screen, which would be ideal.
2) My validator is only receiving a single value (the value of the field I attach it to, not the values of the multiple fields it is supposed to validate).
3) I provide a link to the original (non-duplicate) record in the error message, but it escapes the link, and I can't figure out how to get around that.
The setup I'm currently using (below) actually executes fine, but NewPlace validator receives $_POST['city_fk'] as $fields, instead of the desired group of posted values.
$city_fk = new Zend_Form_Element_Select('city_fk');
$cities = array();
$city_fk->setMultiOptions($cities)
->setLabel('City')
->setDescription('The city this place is in')
->setRequired(true);
$v = array(
'place_is_unique' => array(
'NewPlace',
'fields' => array('place_name','phone_number','phone_extension','street','post_code_name'),
)
);
$city_fk->addValidators($v);
$addressSubForm->addElement($city_fk);
class My_Validate_NewPlace extends Zend_Validate_Abstract
{
public function isValid($fields)
{
$result = false;
if(!$result)
{
$this->_error('sorry, this is duplicate data. see it here');
return false;
}
return true;
}
}
This won't help you decide which field to attach the validation to, but...
There is a thing called a "validation context" that helps.
When you create your custom validator or form IF you specify a second optional parameter ($context = null), then Zend will auto-populate this with the entire array of posted data, which you can use to incorporate other fields values into your validation. Here's a very basic example:
$city_name = new Zend_Form_Element_Text('city_name');
$place_name = new Zend_Form_Element_Text('place_name');
$place_name->addValidator('NewPlace');
class My_Validate_NewPlace extends Zend_Validate_Abstract
{
public function isValid($value, **$context = null**)
{
if(trim($value)!='' && trim($context['city_name']) != '')
{
return true;
}
return false;
}
}