I have a problem where I am coding a server status for my game server. It works fine, but there is one problem… The array output is in one line like this:
Array ( [online] => 1 [error] => [hostname] => chromaville.com [port] => 25565 [version] => 1.12 [software] => CraftBukkit on Bukkit 1.12-R0.1-SNAPSHOT [game_type] => SMP [game_name] => MINECRAFT [players] => 0 [max_players] => 1000 [player_list] => )
instead of a list like so:
Array (
[online] => 1
[error] =>
[hostname] => chromaville.com
[port] => 25565 [version] => 1.12
[software] => CraftBukkit on Bukkit 1.12-R0.1-SNAPSHOT
[game_type] => SMP
[game_name] => MINECRAFT
[players] => 0
[max_players] => 1000
[player_list] =>
);
Is it possible to somehow do it like this? Thank you! (Sorry if my spelling is bad, I haven’t slept in a long time and its 5:19 am currently…)
Here’s my code:
index.php:
<?php
require 'MCQuery.php';
$status = new MCQuery();
$array = ($status->GetStatus( 'chromaville.com', 25565 )-Response() );
print_r($array)
?>
mcquery.php:
<?php
class MCQuery
{
const STATISTIC = 0x00;
const HANDSHAKE = 0x09;
private $Socket;
private $error;
private $host;
private $Info;
private $Players;
//public methods
public function __construct()
{
}
public function GetStatus($Host='127.0.0.1', $Port=25565, $Timeout=2)
{
$this->Clear();
$this->host=$Host;
if( !is_int( $Timeout ) || $Timeout < 0 )
{
$this->error="Invalid timeout";
return $this;
}
$this->Socket = #fsockopen( 'udp://' . $Host, (int)$Port, $ErrNo, $ErrStr, $Timeout );
if( $ErrNo || $this->Socket === false )
{
$this->error="Socket error";
return $this;
}
#stream_set_timeout( $this->Socket, $Timeout );
#stream_set_blocking( $this->Socket, true );
$this->Query();
#fclose( $this->Socket );
return $this;
}
public function Response()
{
return array(
'online'=>$this->error==null?true:false,
'error'=>$this->error,
'hostname'=>$this->host,
'port'=>isset($this->Info['HostPort'])?$this->Info['HostPort']:null,
'version'=>isset($this->Info['Version'])?$this->Info['Version']:null,
'software'=>isset($this->Info['Software'])?$this->Info['Software']:null,
'game_type'=>isset($this->Info['GameType'])?$this->Info['GameType']:null,
'game_name'=>isset($this->Info['GameName'])?$this->Info['GameName']:null,
'players'=>isset($this->Info['Players'])?$this->Info['Players']:null,
'max_players'=>isset($this->Info['MaxPlayers'])?$this->Info['MaxPlayers']:null,
'player_list'=>isset($this->Players)?$this->Players:null,
);
}
//private methods
private function Clear()
{
$this->Socket=null;
$this->error=null;
$this->host=null;
$this->Info=null;
$this->Players=null;
}
private function Query()
{
//challenge
$Data = $this->WriteData( self :: HANDSHAKE );
if( $Data === false )
{
$this->error="Failed to receive challenge";
}
$challenge=pack( 'N', $Data );
$Data = $this->WriteData( self :: STATISTIC, $challenge . pack( 'c*', 0x00, 0x00, 0x00, 0x00 ) );
if( !$Data )
{
$this->error="Failed to receive status";
}
$Last = '';
$Info = Array( );
$Data = substr( $Data, 11 ); // splitnum + 2 int
$Data = explode( "\x00\x00\x01player_\x00\x00", $Data );
if( count( $Data ) !== 2 )
{
$this->error="Failed to parse server's response";
}
$Players = #substr( $Data[ 1 ], 0, -2 );
$Data = explode( "\x00", $Data[ 0 ] );
// Array with known keys in order to validate the result
// It can happen that server sends custom strings containing bad things (who can know!)
$Keys = Array(
'hostname' => 'HostName',
'gametype' => 'GameType',
'version' => 'Version',
'plugins' => 'Plugins',
'map' => 'Map',
'numplayers' => 'Players',
'maxplayers' => 'MaxPlayers',
'hostport' => 'HostPort',
'hostip' => 'HostIp',
'game_id' => 'GameName'
);
foreach( $Data as $Key => $Value )
{
if( ~$Key & 1 )
{
if( !array_key_exists( $Value, $Keys ) )
{
$Last = false;
continue;
}
$Last = $Keys[ $Value ];
$Info[ $Last ] = '';
}
else if( $Last != false )
{
$Info[ $Last ] = $Value;
}
}
// Ints
$Info[ 'Players' ] = $this->error==null?#intval( $Info[ 'Players' ] ):null;
$Info[ 'MaxPlayers' ] = $this->error==null?#intval( $Info[ 'MaxPlayers' ] ):null;
$Info[ 'HostPort' ] = $this->error==null?#intval( $Info[ 'HostPort' ] ):null;
// Parse "plugins", if any
if( #$Info[ 'Plugins' ] )
{
$Data = explode( ": ", $Info[ 'Plugins' ], 2 );
$Info[ 'RawPlugins' ] = $Info[ 'Plugins' ];
$Info[ 'Software' ] = $Data[ 0 ];
if( count( $Data ) == 2 )
{
$Info[ 'Plugins' ] = explode( "; ", $Data[ 1 ] );
}
}
else
{
$Info[ 'Software' ] = $this->error==null?'Vanilla':null;
}
$this->Info = $Info;
if( $Players )
{
$this->Players = explode( "\x00", $Players );
}
}
private function WriteData( $Command, $Append = "" )
{
$Command = pack( 'c*', 0xFE, 0xFD, $Command, 0x01, 0x02, 0x03, 0x04 ) . $Append;
$Length = strlen( $Command );
if( $Length !== #fwrite( $this->Socket, $Command, $Length ) )
{
$this->error="Failed to write on socket";
}
$Data = #fread( $this->Socket, 4096 );
if( $Data === false )
{
$this->error="Failed to read from socket";
}
if( strlen( $Data ) < 5 || $Data[ 0 ] != $Command[ 2 ] )
{
$this->error="Strlen error";
}
return substr( $Data, 5 );
}
}
?>
use echo "<pre>"; before your print_r function. Like as below:
<?php
require 'MCQuery.php';
$status = new MCQuery();
$array = ($status->GetStatus( 'chromaville.com', 25565 )->Response() );
echo "<pre>";
print_r($array)
?>
I think you were trying to debug your code, not trying to display production result by print_r
Related
I'm getting "Undefined property: Requests_Exception_Transport_cURL::$status_code" error and failed to solve it.
private function do_bulk_api_call( $endpoint, $data=array(), $version=0 ) {
if( !$this->cmcapi['status'] )
return false;
$final_api_data = $bulk_requests = array();
$options = get_option( 'cmcapi' );
$version = $version ? $version : $this->cmcapi['version'];
$bulk_url = $this->cmcapi['url'] . $version . $endpoint;
if( $data && is_array($data) ):
foreach ($data as $k => $chunk) {
// TEMP condition
// if( $k > 0 )
// continue;
$bulk_requests[] = array(
'type' => 'GET',
'timeout' => 90,
'url' => $bulk_url,
'headers' => array(
'X-CMC_PRO_API_KEY' => $this->cmcapi['key'],
),
'data' => array( 'id' => implode(',',$chunk) )
);
}
endif;
$requests = Requests::request_multiple( $bulk_requests );
foreach ($requests as $key => $response) {
if($response->status_code !== 200) {
continue;
}
$res_decoded = json_decode($response->body);
$this->kte_shipment_api_results[$key] = array();
$final_api_data = array_merge( (array) $final_api_data, (array) $response->data );
if( !$res_decoded->status->error_code && is_object($res_decoded->data) ){
$final_api_data = array_merge( (array) $final_api_data, (array) $res_decoded->data );
}
}
return $final_api_data;
}
By the way, this code is from other teammate and he is gone now so I cannot ask to him.
In this code filter, search and pagination not functioning i have tried myself but it didn't work so please check the code give me any solution or any reference regarding to this query. Even any related to this code files or docs it will be helpful for me to pursue the concept
<?php
mb_internal_encoding('UTF-8');
$database = 'test';
$collection = 'user';
/**
* MongoDB connection
*/
try{
// Connecting to server
$m = new MongoClient( );
}catch(MongoConnectionException $connectionException){
print $connectionException;
exit;
}
$m_collection = $m->$database->$collection;
$input = $fields = $totalRecords = $data = array();
$input = & $_REQUEST;
$fields = array('id', 'name', 'email', 'gender,');
// Input method (use $_GET, $_POST or $_REQUEST)
/**
* Handle requested DataProps
*/
// Number of columns being displayed (useful for getting individual column search info)
$iColumns = & $input['iColumns'];
// Get mDataProp values assigned for each table column
$dataProps = array();
for ($i = 0; $i < $iColumns; $i++) {
$var = 'mDataProp_'.$i;
if (!empty($input[$var]) && $input[$var] != 'null') {
$dataProps[$i] = $input[$var];
}
}
$searchTermsAny = array();
$searchTermsAll = array();
if ( !empty($input['sSearch']) ) {
$sSearch = $input['sSearch'];
for ( $i=0 ; $i < $iColumns ; $i++ ) {
if ($input['bSearchable_'.$i] == 'true') {
if ($input['bRegex'] == 'true') {
$sRegex = str_replace('/', '\/', $sSearch);
} else {
$sRegex = preg_quote($sSearch, '/');
}
$searchTermsAny[] = array(
$dataProps[$i] => new MongoRegex( '/'.$sRegex.'/i' )
);
}
}
}
// Individual column filtering
for ( $i=0 ; $i < $iColumns ; $i++ ) {
if ( $input['bSearchable_'.$i] == 'true' && $input['sSearch_'.$i] != '' ) {
if ($input['bRegex_'.$i] == 'true') {
$sRegex = str_replace('/', '\/', $input['sSearch_'.$i]);
} else {
$sRegex = preg_quote($input['sSearch_'.$i], '/');
}
$searchTermsAll[ $dataProps[$i] ] = new MongoRegex( '/'.$sRegex.'/i' );
}
}
$searchTerms = $searchTermsAll;
if (!empty($searchTermsAny)) {
$searchTerms['$or'] = $searchTermsAny;
}
$totalRecords =$m_collection->count();
$cursor = $m_collection->find($searchTerms, $fields);
/**
* Paging
*/
if ( isset( $input['iDisplayStart'] ) && $input['iDisplayLength'] != '-1' ) {
$cursor->limit( $input['iDisplayLength'] )->skip( $input['iDisplayStart'] );
}
/**
* Ordering
*/
if ( isset($input['iSortCol_0']) ) {
$sort_fields = array();
for ( $i=0 ; $i<intval( $input['iSortingCols'] ) ; $i++ ) {
if ( $input[ 'bSortable_'.intval($input['iSortCol_'.$i]) ] == 'true' ) {
$field = $dataProps[ intval( $input['iSortCol_'.$i] ) ];
$order = ( $input['sSortDir_'.$i]=='desc' ? -1 : 1 );
$sort_fields[$field] = $order;
}
}
$cursor->sort($sort_fields);
}
foreach ( $cursor as $doc )
{ $name = ''.$doc['name'].'';
$data[] = array($name, $doc['email'], $doc['gender]);
}
/**
* Output
*/
$json_data = array(
"draw"=> intval( $input['draw'] ),
"recordsTotal" =>intval ($totalRecords),
"recordsFiltered" => intval($totalRecords),
"data" => $data
);
echo json_encode( $json_data );
And also i need to Join two tables as given below.
Table 1
Table 2
I am doing it like:
$('#datatable_emp_details').dataTable({
"sServerMethod": "POST",
"bProcessing": true,
"bServerSide": true,
"sAjaxSource": "get_data.php"
});
get_data.php:
<?php
$mongo = new MongoClient();
$database = $mongo->selectDb('dbtest');
$collection = $database->selectCollection('empDetails');
$skip = (int)$_REQUEST['iDisplayStart'];
$limit = (int)$_REQUEST['iDisplayLength'];
$search = $_REQUEST['sSearch'];
$sortIndex = $_REQUEST['iSortCol_0'];
$sortArray = array('emp_id', 'first_name', 'last_name', 'position', 'email', 'office', 'start_date', 'age', 'salary', 'projects'
);
$sortByCol = $sortArray[$sortIndex];
$sortTypeTxt= $_REQUEST['sSortDir_0']; // asc/desc
$sortType = -1;
if( $sortTypeTxt == 'asc' )
{
$sortType = 1;
}
if( $search != '' )
{
$condtion = array(
'$or' => array(
array('emp_id' => $search),
array('first_name'=> new MongoRegex('/'. $search .'/i')), // i for case insensitive
array('last_name' => new MongoRegex('/'. $search .'/i')),
array('position' => new MongoRegex('/'. $search .'/i')),
array('email' => new MongoRegex('/'. $search .'/i')),
array('office' => new MongoRegex('/'. $search .'/i')),
array('start_date'=> new MongoRegex('/'. $search .'/i')),
array('age' => new MongoRegex('/'. $search .'/i')),
array('salary' => new MongoRegex('/'. $search .'/i')),
array('projects' => new MongoRegex('/'. $search .'/i'))
)
);
$resultSet = $collection->find($condtion)->limit($limit)->skip($skip)->sort(array($sortByCol => $sortType));
}
else
{
$resultSet = $collection->find()->limit($limit)->skip($skip)->sort(array($sortByCol => $sortType))->sort(array($sortByCol => $sortType));
}
$data = array();
if( count( $resultSet ) > 0 )
{
foreach ($resultSet as $document)
{
$data[] = $document;
}
}
$resultSet = $collection->find();
$iTotal = count($resultSet);
$rec = array(
'iTotalRecords' => $iTotal,
'iTotalDisplayRecords' => $iTotal,
'aaData' => array()
);
$k=0;
if (isset($data) && is_array($data)) {
foreach ($data as $item) {
$rec['aaData'][$k] = array(
0 => $item['emp_id'],
1 => $item['first_name'],
2 => $item['last_name'],
3 => $item['position'],
4 => $item['email'],
5 => $item['office'],
6 => $item['start_date'],
7 => $item['age'],
8 => $item['salary'],
9 => $item['projects'],
10 => 'Edit | Delete'
);
$k++;
}
}
echo json_encode($rec);
exit;
?>
Github repository link
Fatal error: Call to a member function prepare() on a non-object in
/home/addictiv/public_html/AddictiveRP/Online/lib/katniss/mod.DB.php on line 95
This is mod.DB.php
class DB
{
static $db = null;
static $queries = 0;
static $ms = 0;
//
// Connect to a PDO database
//
static function Connect( $connectstr, $username, $password, $persistant = false, $throwerror = true, $debug = false )
{
DEBUG::Msg( "Connecting to database", 'db' );
$time = microtime( true );
$options = array(
PDO::ATTR_PERSISTENT => $persistant
);
try
{
DB::$db = #new PDO( $connectstr, $username, $password, $options );
if( $debug )
DB::$db->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
}
catch ( exception $e )
{
DEBUG::Msg( "Connection Failed!", 'db' );
if ( $throwerror )
DEBUG::Error( array( 'error' => "Failed to connect", 'message' => $e->getMessage() ), 'DB' );
return false;
}
DB::$ms += microtime( true ) - $time;
DEBUG::Msg( "Connected!", 'db' );
return true;
}
//
// Throws an error if the database isn't ready
//
static function Check()
{
if ( !DB::$db )
DEBUG::Error( array( 'error' => "No Connection" ), 'DB' );
}
//
// Prepared statement wrapper
//
static function Query( $str, $arry = null )
{
DB::Check();
DB::$queries++;
DEBUG::Msg( "Query Start:", 'db' );
DEBUG::Msg( $str, 'db' );
$time = microtime( true );
$st = DB::$db->prepare( $str ); // Line 95 error
if ( !$st )
DEBUG::Error( array( 'error' => "Create Query Failed", 'query' => $str, 'array' => $arry, 'message' => DB::$db->errorInfo() ), 'DB' );
if ( !$st->execute( $arry ) )
DEBUG::Error( array( 'error' => "Query Failed", 'query' => $str, 'array' => $arry, 'message' => $st->errorInfo()), 'DB' );
$result = $st->fetchAll( PDO::FETCH_ASSOC );
DEBUG::Msg( "Done", 'db' );
DB::$ms += microtime( true ) - $time;
return $result;
}
static function QueryRow( $str, $arry = null ) { $ret = DB::Query( $str, $arry ); if ( $ret ) return reset( $ret ); }
static function QueryValue( $str, $arry = null ) { $ret = DB::QueryRow( $str, $arry ); if ( $ret ) return reset( $ret ); }
static function QueryUpdateCheck($str, $arry = null){
DB::Check();
DB::$queries++;
DEBUG::Msg( "Query Start:", 'db' );
DEBUG::Msg( $str, 'db' );
$time = microtime( true );
$st = DB::$db->prepare( $str );
if ( !$st )
DEBUG::Error( array( 'error' => "Create Query Failed", 'query' => $str, 'array' => $arry, 'message' => DB::$db->errorInfo() ), 'DB' );
if ( !$st->execute( $arry ) )
DEBUG::Error( array( 'error' => "Query Failed", 'query' => $str, 'array' => $arry, 'message' => $st->errorInfo()), 'DB' );
$st;
DEBUG::Msg( "Done", 'db' );
DB::$ms += microtime( true ) - $time;
return $st->rowCount();
}
//
// Insert an array into the database. Returns the insert id
//
static function Insert( $table, $arry, $insert = "INSERT" )
{
$keys = array();
$keys_val = array();
$values = array();
foreach ( $arry as $k => $v )
{
$keys[] = $k;
$keys_val[] = ':'.$k;
$values[':'.$k] = $v;
}
$query = $insert . " INTO " . $table . " (".implode( ',', $keys ).") VALUES ( ".implode( ',', $keys_val )." )";
DB::Check();
DB::$queries++;
DEBUG::Msg( "Insert Start: [".$query."]", 'db' );
$time = microtime( true );
$st = DB::$db->prepare( $query );
if ( !$st )
DEBUG::Error( array( 'error' => "Create Insert Failed", 'query' => $query, 'array' => $values, 'message' => DB::$db->errorInfo() ), 'DB' );
if ( !$st->execute( $arry ) )
DEBUG::Error( array( 'error' => "Insert Failed", 'query' => $query, 'array' => $values, 'message' => $st->errorInfo()), 'DB' );
DEBUG::Msg( "Done", 'db' );
DB::$ms += microtime( true ) - $time;
return DB::$db->lastInsertId();
}
//
// Like insert, but replaces the entry if it exists.
//
static function Replace( $table, $arry )
{
return DB::Insert( $table, $arry, 'REPLACE' );
}
//
// Called when shutting down
//
static function OnShutdown()
{
DEBUG::Msg( "Database: ". DB::$queries . " queries (". round( DB::$ms, 3 ) . " seconds)", 'db' );
}
}
What it calls for:
<?php
define('MySQLSet', true); // Change this to true once you've entered your MySQL settings below
define('MySQLHost', ''); // The host of your MySQL database.
define('MySQLDBName', ''); // The name of your MySQL database.
define('MySQLDBUName', ''); // The username of your MySQL database;
define('MySQLDBPassword', ''); // The password of the user.
define('PAGEID', '2003'); // Your VXDonation page id.
define('APIKEY', ''); // Your Steam API Key (For avatars and such)
define('BaseURL', '/Online/'); // Where the system is installed relative to your root.
define('CURSYMBOL', '$'); // The symbol of your real world currency. £ or $ or whatever.
// For example, if you accessed the system by going to yoursite.com/donation/mydonation,
I'm not an expert at this at all so i have no idea what's wrong
Broadly speaking, I have a 2-dimensional array of the following format:
$elements = array( 0 => array('typeA', 'desc'),
1 => array('typeB', 'desc'),
2 => array('typeA', 'desc'),
n => array('typeC', 'desc'));
Where typeX can be 1 of 5 possibilities, and desc can be anything. The end goal is $elements sorted such that no two elements who share a typeX are ever adjacent. Here's my function:
function fixDbls($elems) {
$final = array();
$singles = array();
$doubles = array();
$lastelem = null;
foreach($elems as $elem) {
if(!$lastelem) { // set this the first time through
$lastelem = $elem[0];
$singles[] = $elem;
} else { //otherwise, sort!
if($lastelem == $elem[0]) {
$doubles[] = $elem;
} else {
$singles[] = $elem;
}
}
}
if ($doubles) {
// I suspect this is where it all goes wrong, I am awful at recursion!
$final = fixDbls(array_merge($singles, $doubles));
} else {
$final = $singles;
}
return $final;
}
If anyone can help me understand why this doesn't work (not just the code, but, where I've made a false assumption or where my thinking about this problem betrayed me—helps makes this more generally useful to the public!) I'd be ever, ever so appreciative.
I've been thinking your problem over and I think I came up with a solution. Here's the
code:
<?php
function print_array( $s, $a )
{
echo $s.': { ';
foreach ( $a as $k => $aa ) {
echo $k.' => ';
if ( is_array($aa) ) {
echo '{ '.implode( ', ', $aa ).' }, ';
} else {
echo $aa.', ';
}
}
echo '}'.PHP_EOL;
}
function search_array( array $a, $k )
{
$found = false;
foreach ( $a as $kk => $aa ) {
if ( $aa[0] == $k ) {
$found = $kk;
break;
}
}
return $found;
}
$input = array(
array('typeA', 'desc'),
array('typeB', 'desc'),
array('typeA', 'desc'),
array('typeC', 'desc')
);
print_array( 'Initial input', $input );
$frequencies = array();
foreach ( $input as $e ) {
$frequencies[ $e[0] ] = array_key_exists( $e[0], $frequencies ) ? $frequencies[ $e[0] ] + 1 : 1;
}
arsort($frequencies);
print_array( 'Frequencies', $frequencies );
$tail = array_slice( $frequencies, 1 );
$maxFreq = current( $frequencies );
$orderedElems = array_keys( $frequencies );
$mostFreq = current( $orderedElems );
echo 'The most frecuent element is "'.$mostFreq.'"'.PHP_EOL;
if ( array_sum( $tail ) < $maxFreq - 1 ) {
die ('There\'s No possible solution'.PHP_EOL);
}
$ouput = array();
for ( $i = 0; $i < $maxFreq; $i++ ) {
$k = search_array( $input, $mostFreq);
$output[] = $input[ $k ];
unset( $input[ $k ] );
}
print_array( 'Input after removing "'.$mostFreq.'"', $input );
echo '-----'.PHP_EOL;
print_array( 'Before process, output', $output );
foreach ( $tail as $e => $f ) {
$i = 1;
echo 'Elem to place: "'.$e.'" ('.$f.' times)'.PHP_EOL;
while ( ( $k = search_array( $input, $e ) ) !== false ) {
echo '$i: '.$i.PHP_EOL;
$begin = array_slice( $output, 0, $i );
print_array( 'Begin', $begin );
$end = array_slice( $output, $i );
print_array( 'End', $end );
$output = array_merge( $begin, array( $input[$k] ), $end );
print_array( 'Output', $output );
$i+=2;
unset( $input[$k] );
echo PHP_EOL;
}
}
print_array( 'Final output', $output );
This time I just tried the example you put in the question. The end result was:
Final output: { 0 => { typeA, desc }, 1 => { typeB, desc }, 2 => { typeC, desc }, 3 => { typeA, desc }, }
I hope this version suits your needs.
I made it a function now. This should work, the best.
$elements = array(0 => array('typeA', 'desc'), 1 => array('typeA', 'desc'), 2 => array('typeB', 'desc'), 3 => array('typeC', 'desc'), 4 => array('typeC', 'desc'), 5 => array('typeB', 'desc'), 6 => array('typeB', 'desc'), 7 => array('typeD', 'desc'), 8 => array('typeD', 'desc'), 9 => array('typeA', 'desc'), 10 => array('typeA', 'desc'));
function sortDeep($ary){
foreach($ary as $a){
foreach($a as $i => $v){
if($i === 0)$typesArray[] = $v;
}
}
function notNextTo($a, $b){
if($a === $b){
return 1;
}
else{
return 0;
}
}
uasort($typesArray, 'notNextTo'); $ak = array_keys($typesArray);
foreach($ary as $i => $v){
$sorted[$i] = $ary[$ak[$i]];
}
return $sorted;
}
print_r(sortDeep($elements));
Given an array in the following structure (although obviously with many more items in it):
Array
(
[0] => stdClass Object
(
[currency] => 1
[role] => 3
[client_company] =>
[client_group] =>
[hourly_rate] => 115.00
)
[1] => stdClass Object
(
[currency] => 1
[role] => 1
[client_company] =>
[client_group] =>
[hourly_rate] => 115.00
)
[2] => stdClass Object
(
[currency] => 1
[role] => 3
[client_company] => 58
[client_group] =>
[hourly_rate] => 110.00
)
)
I'm trying to create a function that will take four parameters:
$role
$currency
$company [optional]
$group [optional]
("groups" are children of "companies": if a group is specified, a parent company will always also be specified)
...and that will return the "hourly rate" value from the item that best fits those parameters, on the basis that:
if $row, $currency, $company and $group are specified:
find a rate that matches the role, currency, company and group.
if there isn't one, find one that matches the role, currency and company
if there isn't one, find one that matches the role and currency
if there isn't one, return FALSE
if just $row, $currency and $company are specified:
find a rate that matches the role, currency and company
if there isn't one, find one that matches the role and currency
if there isn't one, return FALSE
if just $row and $currency are specified:
find a rate that matches the role and currency
if there isn't one, return FALSE
What I've got is below, and it works. However, it's ugly as sin. There must be a more elegant way than just bashing a load of if/else and loops together. However, it's Friday and I've had too much pizza for lunch and my brain has become ensludged with cheese.
Can you help?
$hourly_rate = FALSE;
if ( !empty($group) && !empty($company) ) {
foreach ( $rates_cache as $rate ) {
if ( $rate->currency == $currency && $rate->role == $role && (int) $rate->client_company === (int) $company && (int) $rate->client_group === (int) $group ) {
$hourly_rate = $rate->hourly_rate;
}
}
if ( empty($hourly_rate) ) {
foreach ( $rates_cache as $rate ) {
if ( $rate->currency == $currency && $rate->role == $role && (int) $rate->client_company === (int) $company ) {
$hourly_rate = $rate->hourly_rate;
}
}
}
if ( empty($hourly_rate) ) {
foreach ( $rates_cache as $rate ) {
if ( $rate->currency == $currency && $rate->role == $role ) {
$hourly_rate = $rate->hourly_rate;
}
}
}
}else if ( !empty($company) ) {
foreach ( $rates_cache as $rate ) {
if ( $rate->currency == $currency && $rate->role == $role && (int) $rate->client_company === (int) $company ) {
$hourly_rate = $rate->hourly_rate;
}
}
if ( empty($hourly_rate) ) {
foreach ( $rates_cache as $rate ) {
if ( $rate->currency == $currency && $rate->role == $role ) {
$hourly_rate = $rate->hourly_rate;
}
}
}
}else{
foreach ( $rates_cache as $rate ) {
if ( $rate->currency == $currency && $rate->role == $role ) {
$hourly_rate = $rate->hourly_rate;
}
}
}
return $hourly_rate;
Assumption
I believe your cache is always in the format below
Cache Format:
$cache = array(
0 => (object) (array(
'currency' => 1,
'role' => 3,
'client_company' => '',
'client_group' => '',
'hourly_rate' => '115.00'
)),
1 => (object) (array(
'currency' => 1,
'role' => 1,
'client_company' => '',
'client_group' => '',
'hourly_rate' => '115.00'
)),
2 => (object) (array(
'currency' => 1,
'role' => 3,
'client_company' => 58,
'client_group' => '',
'hourly_rate' => '110.00'
))
);
Your Revised Function
$param = array(
"role" => 1,
"currency" => 1
);
echo find($cache, $param)->hourly_rate;
Function Used
function find($cache, $param) {
$mx = array();
if (! isset($param['role']) || ! isset($param['currency']))
throw new Exception("Missing Role Or Currency");
foreach ( $cache as $k => $r ) {
foreach ( array_keys(array_intersect($param, (array) $r)) as $key ) {
if ($r->{$key} == $param[$key]) {
isset($mx[$k]) ? $mx[$k] ++ : $mx[$k] = 1;
}
}
}
arsort($mx);
return $cache[key($mx)];
}
More Complex: Another Approach
Usage
$param = array(
"role" => 1,
"currency" => 1
);
$process = new Process($cache);
echo $process->find($param)->best()->hourly_rate; // Outputs 115.00
Multiple Results
When find best fit .. there is possibility you would get more than one result
$param = array(
"role" => 3,
"currency" => 1
);
$process = new Process($cache);
var_dump($process->find($param)->results());
Output
array (size=2)
0 =>
object(stdClass)[1]
public 'currency' => int 1
public 'role' => int 3
public 'client_company' => string '' (length=0)
public 'client_group' => string '' (length=0)
public 'hourly_rate' => string '115.00' (length=6)
2 =>
object(stdClass)[3]
public 'currency' => int 1
public 'role' => int 3
public 'client_company' => int 58
public 'client_group' => string '' (length=0)
public 'hourly_rate' => string '110.00' (length=6)
Not getting best result
You can see based on your parameters you are getting 2 if you are looking for cheapest prize and you call
$param = array(
"role" => 3,
"currency" => 1
);
echo Process::quick($cache, $param)->best()->hourly_rate; // returns 115.00 but that is not the cheapest
Resolution
The solution is you can add filter and sort
$param = array(
"role" => 3,
"currency" => 1
);
$sort = function ($a, $b) {
return $a->hourly_rate < $b->hourly_rate ? - 1 : 1;
};
echo Process::quick($cache, $param)->sort($sort)->best()->hourly_rate; // 110
Getting all Related
You can also just loop through all the result and select the columns you want insted of just getting best result
foreach ( Process::quick($cache, $param)->sort($sort)->getColoum("client_company", "hourly_rate") as $result ) {
print_r($result);
}
Output
stdClass Object
(
[client_company] => 58
[hourly_rate] => 110.00
)
stdClass Object
(
[client_company] =>
[hourly_rate] => 115.00
)
Updated Class
To add all this additional functions you need to upgrade your class to
class Process implements JsonSerializable, IteratorAggregate {
private $cache;
private $matrix = array();
private $final = array();
function __construct($cache) {
$this->cache = $cache;
}
function find($param) {
if (! isset($param['role']) || ! isset($param['currency']))
throw new Exception("Missing Role Or Currency");
foreach ( $this->cache as $k => $rate ) {
$keys = array_intersect($param, (array) $rate);
foreach ( array_keys($keys) as $key ) {
if ($rate->{$key} == $param[$key]) {
isset($this->matrix[$k]) ? $this->matrix[$k] ++ : $this->matrix[$k] = 1;
}
}
}
arsort($this->matrix);
$this->matrix = array_keys(array_filter($this->matrix, function ($v) {
return $v >= 2;
}));
$this->final = $this->sortArray($this->cache, $this->matrix);
return $this;
}
public static function quick($cache, $param) {
$process = new Process($cache);
return $process->find($param);
}
public function best() {
reset($this->final);
return empty($this->final) ? : current($this->final);
}
public function results() {
return $this->final;
}
public function limit($length = 0) {
$this->final = array_slice($this->final, 0, $length);
return $this;
}
public function sort(Callable $function) {
usort($this->final, $function);
return $this;
}
public function getColoum() {
$arg = array_flip(func_get_args());
foreach ( $this->final as &$s ) {
foreach ( $s as $k => $v ) {
if (! isset($arg[$k]))
unset($s->{$k});
}
}
return $this;
}
public function getIterator() {
return new ArrayIterator($this->final);
}
public function jsonSerialize() {
return json_encode($this->final);
}
public function __toString() {
return $this->jsonSerialize();
}
private function sortArray(array $array, array $orderArray) {
$ordered = array();
foreach ( $orderArray as $key => $value ) {
array_key_exists($value, $array) and $ordered[$value] = $array[$value];
}
return $ordered;
}
}