Thursday, 30 June 2016

Javascript Object (or JSON) attribute removal

Introduction

Here is the small utility function which I wrote it when I fell into the requirement stated below:
"Given a Javascript object having a lot of attributes, I am given a path for a particular attribute which is to be removed."

My Thought process

  • Recursion come up in my mind by noticing that there can be variable length of the path for the particular attribute to be deleted.
  • After searching for sometime I got to know that I cannot (or is very hard) make the deletion happen on the fly (I was thinking of pass by reference) and just return the result. So I came up with the idea of overwrite
  • Someway or the other each recursion level on completion should be able to return 2 things whichever suits the case. Two things are -
    • Whether the path was correct and any attribute was able to get deleted
    • If deletion was successful return the updated object (or array) and traverse it to the parent level and update subsequent attribute (or array elements)

Code Section

Here is the recursive function which fulfils the requirement
function getDeletedObj(obj, attr) {
if (typeof obj === 'undefined') {
// We came across improper attribute while traversing the list of attribute in `attr`
return false;
} else if (attr.length === 0) {
// when we have traversed the complete `attr` path correctly
return true;
} else {
var key = attr[0];
var isArray = false;
if (Object.prototype.toString.call(obj) === '[object Array]') {
isArray = true;
}
var objectFound = getDeletedObj(obj[key], attr.slice(1));
if (objectFound === false) {
// We went to the path of the object which did not existed (see the 'undefined' check above)
return false;
} else if (objectFound === true) {
// the next call was the last call to the attribute which is to be removed
if (isArray) {
// If the object to be removed was a part of array, then splice it
obj.splice(key, 1);
} else {
// Otherwise delete the object
delete obj[key];
}
} else {
// If neither `true` nor `false` is returned that means the returned variable is the updated object
// Update the current object and return it back for higher level updation
obj[key] = objectFound;
}
return obj;
}
}
Here's how you would use it:
exampleObj = {
a: {
b: 1,
c: [1,2,3]
},
d: true
}
result = getDeletedObj(exampleObj, ['a', 'c', 1])
Output:
result = {
a: {
b: 1,
c: [1,3]
},
d: true
}
Wordpress version

Tuesday, 28 June 2016

PHP multi exec made easy

Introduction

This story is for those people for whom network call becomes the bottleneck (I know for sure that there are plenty, so comes the solution). But before we get to the solution, allow me to describe the problem formally. When you have multiple network calls to be made simultaneously in PHP you either end up in reading about Curl Multi exec or end up reading about PHP Threads to have a work around and trying to make those requests simultaneously. So, the solution below will help you if you are facing any/all the issues like:
  • Multiple urls needs to be hit without any dependency on each other.
  • All the responses from the requests need to be handled from a single place.
  • If you are not going to use it directly with client inputs (error handling is not done properly, yet!)

Solution

The solution I am talking about actually uses Curl Multi exec but in a more cleaner way. We can call it a wrapper for ease of use. Now lets make our eyes dirty and go through the code. PS: Please read the comments => Super necessary

Code Section

class MultiCurl
{
//curl handler info storing variables
private $multiCurlHandler;
private $noOfHandlers;
private $handlers;

public function __construct()
{
$this->multiCurlHandler = curl_multi_init();
$this->noOfHandlers = 0;
$this->handlers = [];
}

/**
* @param $ch curl_init() resource variable
* @param $id any unique identification for the handler (default is the number (i-1), for ith handler)
*/
public function addHandler($ch, $id = -1)
{
if ( $id !== -1 ) {
curl_setopt($ch, CURLOPT_PRIVATE, $id);
} else {
curl_setopt($ch, CURLOPT_PRIVATE, $this->noOfHandlers);
}
curl_multi_add_handle($this->multiCurlHandler, $ch);
$this->noOfHandlers++;
}

/**
* @param callable|NULL $callback non-mandatory callback (sort of) function, called with param mentioned next
* @param int $sleep milliseconds to wait in the loops to prevent high CPU usage (defaults to 100 ms)
* @return array associative array containing unique id to response/error mapping.
*/
public function exec(callable $callback = NULL, int $sleep = 100)
{
$active = 0;
do {
//Initialise multi exec resources until all are done
$execResult = curl_multi_exec($this->multiCurlHandler, $active);
usleep($sleep*1000);
} while ( $active > 0 );
while ( $active && $execResult == CURLM_OK ) {
// We have more than one connections awaiting for response and initialisations are done properly

//if the socket has any data
if ( curl_multi_select($this->multiCurlHandler) != -1 ) {
do {
//Fetch more data as long as system tells us to fetch
$execResult = curl_multi_exec($this->multiCurlHandler, $active);
usleep($sleep*500);
} while ( $active );
}
usleep($sleep*500);
}
//Rest below are easily understandable stuff
$response = [];
while ( $done = curl_multi_info_read($this->multiCurlHandler) ) {
$info = curl_getinfo($done['handle']);
$uniqueId = curl_getinfo($done['handle'], CURLINFO_PRIVATE);
if ( $info['http_code'] == 200 ) {
$output = curl_multi_getcontent($done['handle']);
if ( $callback === NULL ) {
$response[$uniqueId] = [
'error' => NULL,
'response' => $output
];
} else {
$callback($uniqueId, NULL, $output);
}
} else {
$error = curl_error($done['handle']);
if ( $callback === NULL ) {
$response[$uniqueId] = [
'error' => $error,
'response' => NULL
];
} else {
$callback($uniqueId, $error);
}
}
}
if ( $callback === NULL ) {
return $response;
}
}

/**
* Closes all the connections
*/
public function close()
{
foreach ( $this->handlers as $handler ) {
curl_multi_remove_handle($this->multiCurlHandler, $handler);
curl_close($handler);
}
curl_multi_close($this->multiCurlHandler);
$this->multiCurlHandler = NULL;
$this->handlers = [];
$this->noOfHandlers = 0;
}

public function __destruct()
{
if ( $this->multiCurlHandler !== NULL && $this->noOfHandlers > 0 ) {
$this->close();
}
}
}
Here's how you would use it
$obj = new MultiCurl();
$url = "http://jsonplaceholder.typicode.com/comments/";
for ( $i = 1; $i < 10; $i++ ) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url . $i);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$obj->addHandler($ch, "handle" . $i);
}
$res = $obj->exec();
/*
* Response can be obtained by using exec in callback form too as shown below:
* $obj->exec(function($uniqueId, $error, $response) {
* //if $error === NULL, $response is obtained
* //otherwise $response is not passed
* });
*/
$obj->close(); //Optional to call as __destruct() makes sure resources are freed at the end
Wordpress version

References

Matt Butcher, TechnoSophos | Example, php.net