I have a problem using the usort function. My array has the following model :
Fusion
|
| Array_1
| |
| | Array_1_1
| | | clock => "08:08"
| | | //Other fields
| | |
| |
| | Array_1_2
| | | clock => "04:51"
| | | //Other fields
| | |
|
| Array_2
| ...
I want to sort the arrays in Array_X basing on the 'clock' field. I made this code, basing on the PHP documentation of usort (4th example) :
foreach ($fusion as $fus){
usort($fus,function ($key = 'clock'){
return function ($a,$b) use ($key){
return strnatcmp($a[$key],$b[$key]);
};
});
}
... but it returns the following exception :
Object of class Closure could not be converted to int
Do you have any idea ? Thanks for your help.
You're trying to pass the following as a callback (2nd argument of usort)
function ($key = 'clock'){
return function ($a,$b) use ($key){
return strnatcmp($a[$key],$b[$key]);
};
}
But the documentation clearly specifies that
The comparison function must return an integer [...]
However, your callback returns another closure. This is why you get a Closure to int convertion Exception.
I believe what you're trying to do is to execute the inner-closure to get the final callback using the right values. I'd say this is useless because, unlike in Javascript, php closures are opt-in, not all-in, which means their context must be included with use the way you did for $key in the outer-closure.
You could simply do:
$key = 'clock';
foreach ($fusion as $fus){
usort($fus,function ($a,$b) use ($key){
return strnatcmp($a[$key],$b[$key]);
});
}
And if $key comes from some other kind of context you may just have to adjust the variable assignment.
Convert your object into an array using get_object_vars($object) first.
If the object that you are getting is generated by a different function, then read documentation for that function and find a way for it to return an array instead of object.
Examples and documentation can be found here http://php.net/manual/en/function.get-object-vars.php
Related
When I use get_field('repeater_name') it returns a string that contains the a number which is the count of the repeater while it should return array of sub-fields, this issue have been reported repeatedly before but none of them provided a stable fix to this, the only way is to edit the post and hit the update button and it will re-generate the repeater fields, but in my case, I have 19k posts and it's not possible to edit each post.
Also have_rows('repeater_name') returns false as expected and the real field data (get_post_meta($post_id, "field_{$field_key}", true) returns NULL
I would appreciate any help or any automated script that regenerates the repeater field keys and populate the values of all posts.
This issue is reported previously in here, here and here and none came with a real fix.
EDIT:
I spotted the problem, the problem is in wp_postmeta table, the wrong field keys are stored:
wp_postmeta table
| meta_key | meta_value |
| ------------- |:-------------:|
| _repeater_name | field_XXXXXXX |
| _repeater_0_subfield | field_ABCDEFG |
| _repeater_0_subfield2 | field_HIJKLMN |
The same field keys should match in wp_posts table, but they don't (maybe due to data migration or whatever reason):
| post_excerpt | post_name | post_type |
| ---------------| ------------- |-----------|
| repeater_name | field_YYYYYYY | acf-field |
| subfield | field_BBBBBBB | acf-field |
| subfield2 | field_CCCCCCC | acf-field |
I think if there's a way to sync field keys in the database, that will fix the problem
I made a solution for this, might not be the exact solution for this problem but it worked out for me, I wrote this fix to rebuild faulty fields, it will rebuild only fields that have this problem:
/**
* #param string $name
* #param string[] $keys
* #param int|null|\WP_Post $post
*/
function dw_build_repeater($name, $keys = [], $post = null) {
$post = get_post($post);
$repeater = get_field($name, $post->ID);
$arr = [];
if (is_array($repeater)) {
return $repeater;
}
if (!$repeater || !is_numeric($repeater)) {
return $arr;
}
for ($i = 0; $i < intval($repeater); $i++) {
foreach ($keys as $key) {
$arr[$i][$key] = get_post_meta($post->ID, $name . "_" . $i . "_{$key}");
}
}
update_field($name, $arr, $post->ID);
return $arr;
}
so whenever i want to call a repeater i simply do this:
if (
have_rows('repeater_name')
|| dw_build_repeater('repeater_name', ['subfield1', 'subfield2', 'subfield3'])
) {
while (have_rows('repeater_name')) {
the_row();
// And the rest
}
}
// OR simply with a foreach loop
foereach (dw_build_repeater('repeater_name', ['subfield1', 'subfield2', 'subfield3']) as $row) {
echo $row['subfield1'] ?? '';
}
I haven't tested it with nested repeaters but i suppose it might not be working with nested repeaters.
I've been having this issue when trying to access repeaters added to options pages through the PHP API. Specifically, in my case I was trying to get the repeater data during the acf/load_field filter. It didn't matter whether the hook was registered during init or acf_init.
I discovered that, at least in this case, you always have to call acf_enable_filter( 'local' ) before get_field() to get the data array instead of the item count.
Consider the following scenario for API testing
Given I am using the API Service
When I send the <request> as <method> to <endpoint> endpoint with <key> having value <value>
Then The response status code is 200
Examples:
| request | method | endpoint | key | value |
| "All Keys" | "POST" | "endpointName" | "numericField" | 15 |
| "All Keys" | "POST" | "endpointName" | "numericField" | 15.12345 |
The above example creates a request with the specified parameters.
My problem is that while the integer (15) value is passed to the function accordingly, the float (15.12345) is converted into a string ("15.12345"). This happens straight as the function is called; it is not modified later on during another step.
Is there a way to keep the float value from turning into a string?
As requested, the send request step method is:
$data = $this->fulfilmentOptions->getDataValue($request);
$uri = $this->getMinkParameter('base_url') . $this->setEndpoint($endpoint);
array_walk_recursive($data, function(&$item, $originalKey) use ($key, $value) {
if ($originalKey === $key) {
$item = $value;
}
});
try {
$this->response = $this->client->request($method, $uri, [
'headers' => $this->fulfilmentOptions->getDataValue('CreateOrder API Headers'),
'body' => json_encode($data)
]);
} catch (\GuzzleHttp\Exception\RequestException $e) {
$this->response = $e->getResponse();
}
$this->responseContent = $this->response->getBody()->getContents();
One way of fixing the issue is to use floatval method for 'value' key to make sure you get the right type.
I'm trying to extract the value of a JSON, without a key that gives me a reference.
This is my JSON code:
{"StatTrak™ Dual Berettas | Dualing Dragons (Battle-Scarred)":0.37,"★ StatTrak™ Huntsman Knife | Scorched (Well-Worn)":101.65,"Sticker | iBUYPOWER | DreamHack 2014":11.34,"MP9 | Sand Dashed (Well-Worn)":0.03,"★ Flip Knife | Urban Masked (Field-Tested)":61.74}
The first value is the name and the second one the price. I've got a very long JSON with a lot of name's and prices.
name="StatTrak™ Dual Berettas | Dualing Dragons (Battle-Scarred)"<br>
price="0.37"
Actually don't know how to access the name to extract the other value.
I have the name of the weapons saved on my site from another API. I have to extract the value of this JSON and compare that name with the name the API gave me previously.
The name is the key:
$array = json_decode($json, true);
foreach($array as $name => $price) {
echo "$name<br>$price<br>";
}
You see it with a print_r($array):
Array
(
[StatTrakΓäó Dual Berettas | Dualing Dragons (Battle-Scarred)] => 0.37
[Γÿà StatTrakΓäó Huntsman Knife | Scorched (Well-Worn)] => 101.65
[Sticker | iBUYPOWER | DreamHack 2014] => 11.34
[MP9 | Sand Dashed (Well-Worn)] => 0.03
[Γÿà Flip Knife | Urban Masked (Field-Tested)] => 61.74
)
Assuming I understood you correctly and you want to access values by keys:
First of all, I'd axtually recommend using Javascript for this. It doesn't seem like you're parsing any personal or important data that should remain private, so why not let the client do the work instead of giving your server more work to do?
Anyhow, as for PHP:
First you'll need to decode the json string using the json_decode() function, giving it 2 parameters - the first will be the json string, and the second a simple true boolean, so that it will return an array instead of a json object. The function returns an array, in which each key and value correspond to the name and price in the json list, with the name being the key. Than, to access the value, simply use the array value by key functionality ($arr['weaponname'] would return the price of 'weaponnane', assuming it exists [otherwise you'll get an exception], so you'll need to check that using isset() or array_key_exists()).
Put together, you'll have something along the lines of the following (you'll obviously need to modify this to fit your needs), assuming $weaponname contains the weapon name and $jsonstring the json string:
$price = NULL;
$jsonarr = json_decode($jsonstring, true);
if (isset($jsonarr[$weaponname]))
{
$price = $jsonarr[$weaponname];
}
If the weapon doesn't exist or it's price is NULL in the array, the $price variable will be NULL.
I have a Document Model which represents a Document (name, description etc). I then have a DocumentData Model which represents the data of a Document. A Document has One to Many DocumentData,
So to create a Document I have a form. Lets say that my form has a text input for Document Owner. Within my DocumentData table, the label documentOwner is set as the key and the inputted data is set as the value. So with multiple form elements, my DocumentData table might look like this
document_data
id | documentId | key | value |
----------------------------------------------
1 | 1 | clientName | Google |
----------------------------------------------
2 | 1 | projectName | Analytics |
----------------------------------------------
3 | 1 | Contact | Mr Sharp |
----------------------------------------------
4 | 1 | startDate | 29/12/2016 |
----------------------------------------------
The Document name and description for the Document table is created using hidden fields within the view of the Document.
So I can create Documents without a problem. I am having a problem with my update function though. So far I have the following
public function update(Request $request, Project $project, $id)
{
$document = $project->document()->where('id', '=', $id)->first();
$docData = $document->documentData()->get();
$input = $request->all();
foreach($docData as $orgData) {
foreach($input as $key => $value) {
if($key !== "filePath" && $key !== "documentType" && $key !== "documentTypeDesc") {
if($key == $orgData->key) {
$orgData->value = $value;
$orgData->update();
}
}
}
}
return View::make($document->name.'Doc.edit', compact('project', 'document'));
}
So firstly I get the Document I am working on and store it in $document. I then get the DocumentData for this Document and store it in $docData. $docData is a collection containing my key-value pairings for a Document.
I then loop both the $docData and the inputted data and where the keys match, I reset its updated value.
However, at the moment, it updates everything to the last inputted data field. I am not sure where else I can perform the update operation, but I only need it to update the row it is referring too, not the whole thing.
How could I go about doing this?
Thanks
I've cleaned up the code a little, and made a few implementation changes. This code should work, so let us know if it doesn't, and if not, what failed.
public function update(Request $request, Project $project, $id)
{
// you can use eager loading and find on the relationship query
$document = $project->document()->with('documentData')->find($id);
// you can just access the relationship attribute, no need for the query
$docData = $document->documentData;
// gets all input, except the keys specified
$input = $request->except(['filePath', 'documentType', 'documentTypeDesc']);
foreach($docData as $orgData) {
// check if the input has a key that matches the docdata key
if (array_key_exists($orgData->key, $input)) {
// update the value
$orgData->value = $input[$orgData->key];
// use save, not update
$orgData->save();
}
}
return View::make($document->name.'Doc.edit', compact('project', 'document'));
}
I have two very similar classes. Lets say Class A and Class B.
+---------------+ +---------------+
| Class A | | Class B |
|---------------| |---------------|
| Name | | Name |
| ZIP | | ZIP |
| TelPhone | | TelPhone |
| | | MobilePhone |
+---------------+ +---------------+
I want to compare them in the values for all common attributes.
Here's a way I tried it, but doing it for all attributes (got more than only 3 attributes) looks like a overkill for me:
$differences = array();
if($classA->getName() != $classB->getName()) {
array_push(
$differences,
array('name' => array(
'classA' => $classA->getName(),
'classB' => $classB->getName()
)
));
}
// and the same code for every attribute....
What's the best approach here?
Additional to the handiwork, it is also not automatically updated if the classes are getting altered. For example if Class A gets also a MobilePhone attribute.
Please don't tell me, that I should do some Polymorphism, it's just an example to clarify.
I'm interested in the difference, so not only the attributes, also the values itself inside the attributes.
thanks
It's not the sexiest thing (because of the substring to getters.., but I can't go with properties, I think sym, but I got it:
// getting an array with all getter methods of a class
private function getGettersOf($object) {
$methodArray = array();
$reflection = new ReflectionClass($object);
$methods = $reflection->getMethods();
foreach ($methods as $method) {
// nur getter
if(strtolower(substr($method->getName(), 0, 3)) == "get") {
array_push($methodArray, $method->getName());
}
}
return $methodArray;
}
// getting an array with all differences
public function getDifferences($classA, $classB) {
// get list of attributes (getter methods) in commond
$classAMethods = $this->getGettersOf($classA);
$classBMethods = $this->getGettersOf($classB);
$intersection = array_intersect($classAMethods, $classBMethods);
$differences = array();
// iterate over all methods and check for the values of the reflected methods
foreach($intersection as $method) {
$refMethodClassB = new ReflectionMethod($classB, $method);
$refMethodClassA = new ReflectionMethod($classA, $method);
if($refMethodClassB->invoke($classB) != $refMethodClassA->invoke($classA)) {
array_push(
$differences,
array($method => array(
'classA' => $refMethodClassA->invoke($classA),
'classB' => $refMethodClassB->invoke($classB)
)
));
}
}
return $differences;
}
Special thanks to George Marques's comment.