Validate that JSON array has one associative array with fixed integer value - php

I am trying to validate some JSON using Opis's package. I am trying to validate that an array has at least one associative array with an id of value 1. Here is the code I've got:
$json = [
[
'id' => 1,
],
[
'id' => 2,
],
[
'id' => 3
]
];
$rules = [
'type' => 'array',
'contains' => [
'type' => 'array',
'properties' => [
'id' => [
'type' => 'integer',
'const' => 1,
],
],
'required' => ['id']
],
'minContains' => 1,
];
$validated = Common::validateJSON($json, json_encode($rules));
and here is the validateJSON method code:
public static function validateJSON($json, $rules)
{
$validator = new Validator();
// Validate
$result = $validator->validate($json, $rules);
if ($result->isValid()) {
return true;
}
$errorMessages = [];
if ($result->hasError()) {
$formatter = new ErrorFormatter();
$errorMessages[] = $formatter->format($result->error());
}
return $errorMessages;
}
so, in this case $validated returns:
array:1 [
0 => array:1 [
"/" => array:1 [
0 => "At least 1 array items must match schema"
]
]
]
changing $rules to this:
$rules = [
'type' => 'array',
'contains' => [
'type' => 'array',
],
'minContains' => 1,
];
returns the same result which is weird for me.
Changing const to any number doesn't change what is returned. So, my guess is that I am doing something wrong but I don't know what.
I've been googling various things nothing helped. I've been looking at the JSON schema site, particularly here but I haven't figured it out.

Before validating, as I am not json decoding the data as it is not coming from an http request, do this:
$json = json_encode($json);
$json = json_decode($json); // this, I think, will turn associative arrays into objects which makes it work
and the second type must be object.

Related

PHP Api Object Query

I'm having a bit of an issue with an API document I'm currently working with. The code I've been testing just doesn't seem to work, and I've been looking at it for that long now, I just cannot see where I'm going wrong.
API Documentation Screenshot here: https://ibb.co/CW4HRR9
// POST /package/{id}/web/ftpusers
$args = [
'update' => [
'ftp' => [
'id' => '12345',
'user' => ['Password' => 'Password123']
],
],
];
$response = $services_api->postWithFields("/package/".$test_domain_id."/web/ftpusers", $args);
echo '<pre>';
print_r($response);
echo '</pre>';
It just doesn't seem to work, and I'm guessing I'm doing something wrong where it states object and object[]
Looks like I was missing an array object as I've now got this working (extra array within 'ftp'
$args = [
'update'=> [
'ftp' => [
[
'id' => $info[0]->Id,
'user' => [
'Enabled' => true,
'Password' => 'Password123'
],
]
],
],
];

Laravel 5.7. Subtract model instances

I have 2 collections of models.
For example
$full = collect([
[
'name' => 'name1', //id was omitted intentionally
],
[
'name' => 'name2', //id was omitted intentionally
],
[
'name' => 'name3', //id was omitted intentionally
],
]);
$diff = collect([
[
'id' => 6,
'name' => 'name1',
],
]);
and I want to receive such a result after something like this
$full->diff($full);
$result = [
[
'name' => 'name2',
],
[
'name' => 'name3',
],
];
How to achieve that without filter() or reject() with contains() in a neater way?
It's hard to say why you don't want to use filter or reject with contains but there is another solution:
$result = $full->pluck('name')->diff($diff->pluck('name'))->map(function($name) {
return [
'name' => $name
];
});
dd($result->toArray());
As result you will get:
array:2 [▼
1 => array:1 [▼
"name" => "name2"
]
2 => array:1 [▼
"name" => "name3"
]
]
The diff method should work as needed with a new collection containing just the name property:
$comparableDiff = $diff->pluck('name');
$result = $full->diff($comparableDiff);
I haven't found a neater approach than
$profiles->reject(function ($profile) use ($existingProfiles) {
return $existingProfiles->pluck('name')->contains($profile->name);
})->values()
But thanks to everyone. I've upvoted your questions ;)

Create Associative Array with Foreach, Insert into existing Associative Array

Hello.
I currently have a problem with the AWS Route-53 API. To create a record you need to call a function, which itself needs an array of inputs.
I want to create a record set here and for that I have some POST values. One of them, $_POST['record_value'], is a textarea and has multiple lines. I loop through them. This is to enable multiple values for one record. The code is as follows when you hardcode it as one value in ResourceRecords;
$result = $this->route53->changeResourceRecordSets([
'ChangeBatch' => [
'Changes' => [
[
'Action' => 'CREATE',
'ResourceRecordSet' => [
'Name' => $recordName,
'ResourceRecords' => [
[
'Value' => $recordValue
],
],
'TTL' => $recordTtl,
'Type' => $recordType,
],
],
],
'Comment' => 'Routing Record Set',
],
'HostedZoneId' => $this->zone,
]);
Hower. I want to make ResourceRecords dynamically. For every line in the textarea I need a new set of the following part of the code;
[
'Value' => $recordValue
],
What I thought is the following;
$newData = [];
foreach(explode("\r\n", $recordValue) as $valLine) {
$newData[] = ["Value" => $valLine];
}
$result = $this->route53->changeResourceRecordSets([
'ChangeBatch' => [
'Changes' => [
[
'Action' => 'CREATE',
'ResourceRecordSet' => [
'Name' => $recordName,
'ResourceRecords' => [
$newData
],
'TTL' => $recordTtl,
'Type' => $recordType,
],
],
],
'Comment' => 'Routing Record Set',
],
'HostedZoneId' => $this->zone,
]);
However, this seems to return an exception: Found 1 error while validating the input provided for the ChangeResourceRecordSets operation:↵[ChangeBatch][Changes][0][ResourceRecordSet][ResourceRecords][0] must be an associative array. Found array(1).
Am I building the array wrong or am I doing this wrong alltogether?
$newData is already an array, you don't need to wrap it in another array.
'ResourceRecords' => $newData,

PHP wont JSON encode multiple Array()'s with same name

I have the structure below which I need to turn into json_encoded. To finally get it decoded and get an object.
This will allow me to have multiple objects with the name message and loop through them and process each message individually.
However when encoded, php will only encode the key and one of the message arrays—the last one.
$setup = [
'key' => 'demo-7hn3fh83un3yhvfjvnjgknfhjnvf',
'message' => [
'number' => [
'+39XXXXXXXX',
'+34XXXXXXXX',
'+49XXXXXXXX'
],
'text' => 'Sample msg 123...',
],
'message' => [
'number' => [
'+50XXXXXXXX',
'+50XXXXXXXX'
],
'text' => 'Something...',
]
];
Is there a way to encode multiple arrays with the same name?
You've overlooked the root issue:
$foo = [
'bar' => 1,
'bar' => 2,
'bar' => 3,
];
var_export($foo);
array (
'bar' => 3,
)
Thanks for the tips everyone. I ended up modifying the structure like below...
The reason why I am going with a structure like this is cause it allows me to submit multiple messages to multiple users with a single request.
$setup = [
'key' => 'demo-7hn3fh83un3yhvfjvnjgknfhjnvf',
'message' => [
[
'number' => [
'+39XXXXXXXX',
'+34XXXXXXXX',
'+49XXXXXXXX'
],
'text' => 'Sample msg 123...'
],
[
'number' => [
'+50XXXXXXXX',
'+50XXXXXXXX'
],
'text' => 'Something...'
]
]
];

How to search elasticsearch case insensitive

I am using php's client library for elasticsearch. I'd like to create an index that indexes a person's id and his name, and allows the user to search for names in a very flexible way (case insensitive, search for partial names, etc.
Here is a code snippet of what I have so far, annotated with comments for convenience
<?php
require_once(__DIR__ . '/../init.php');
$client = new Elasticsearch\Client();
$params = [
'index' => 'person',
'body' => [
'settings' => [
// Simple setings for now, single shard
'number_of_shards' => 1,
'number_of_replicas' => 0,
'analysis' => [
'filter' => [
'shingle' => [
'type' => 'shingle'
]
],
'analyzer' => [
'my_ngram_analyzer' => [
'tokenizer' => 'my_ngram_tokenizer',
]
],
// Allow searching for partial names with nGram
'tokenizer' => [
'my_ngram_tokenizer' => [
'type' => 'nGram',
'min_gram' => 1,
'max_gram' => 15,
'token_chars' => ['letter', 'digit']
]
]
]
],
'mappings' => [
'_default_' => [
'properties' => [
'person_id' => [
'type' => 'string',
'index' => 'not_analyzed',
],
// The name of the person
'value' => [
'type' => 'string',
'analyzer' => 'my_ngram_analyzer',
'term_vector' => 'yes',
'copy_to' => 'combined'
],
]
],
]
]
];
// Create index `person` with ngram indexing
$client->indices()->create($params);
// Index a single person using this indexing scheme
$params = array();
$params['body'] = array('person_id' => '1234', 'value' => 'Johnny Appleseed');
$params['index'] = 'person';
$params['type'] = 'type';
$params['id'] = 'id';
$ret = $client->index($params);
// Get that document (to prove it's in there)
$getParams = array();
$getParams['index'] = 'person';
$getParams['type'] = 'type';
$getParams['id'] = 'id';
$retDoc = $client->get($getParams);
print_r($retDoc); // success
// Search for that document
$searchParams['index'] = 'person';
$searchParams['type'] = 'type';
$searchParams['body']['query']['match']['value'] = 'J';
$queryResponse = $client->search($searchParams);
print_r($queryResponse); // FAILURE
// blow away index so that we can run the script again immediately
$deleteParams = array();
$deleteParams['index'] = 'person';
$retDelete = $client->indices()->delete($deleteParams);
I have had this search feature working at times, but I've been fussing with the script to get the case insensitive feature working as expected, and in the process, the script now fails to find any person with a J or j used as the query value to match.
Any ideas what might be going on here?
To fix the case insensitive bit, I added
'filter' => 'lowercase',
to my ngram analyzer.
Also, the reason why it was failing to begin with is that, while using php's client library, you can't create the index then search it in the same script. My guess is something async is going on here. So create the index in one script and search it in another script, it should work.

Categories