How to retrieve composite column from Cassandra table in PHP - json

I have a CassandraHandler that retrieves the queries in rows
class CassandraHandler
{
private $keyspace = 'blabla'; //default is oyvent
private $cluster = NULL;
private $session = NULL;
function __construct(){
$this->cluster = \Cassandra::cluster()
->build(); // connects to localhost by default
$this->session = $this->cluster->connect($this->keyspace);
}
/**
* #return Rows
*/
public function execute($query){
$statement = new \Cassandra\SimpleStatement($query);
$result = $this->session->execute($statement);
return $result;
}
}
When I use for normal columns it's fine but I can't get my photo column in php
I created the column like this
photos frozen<set<map<text,text>>>
my json example
{{"urllarge": "1.jpg", "urlmedium": "2.jpg"},
{"urllarge": "3.jpg", "urlmedium": "4.jpg"}}
And here how can I use PHP to retrieve the composite columns?
$cassandraHandler = new CassandraHandlerClass();
$rows = $cassandraHandler->fetchLatestPosts($placeids, $limit);
foreach ($rows as $row) {
$tmp = array();
$tmp["userid"] = doubleval($row["userid"]);
$tmp["fullname"] = $row["fullname"];
$tmp["photos"] = $row["photos"] //????????
}
I know there is this documentation of the PHP driver https://github.com/datastax/php-driver
But I am a little confused.. I just need to get the json value like I get in cqlsh

You have two options to convert the composites into useable JSON:
Create a function to convert the deserialized/unmarshalled objects into JSON.
Retrieve the values from Cassandra as JSON.
Here is an example that demonstrates both options:
<?php
$KEYSPACE_NAME = "stackoverflow";
$TABLE_NAME = "retrieve_composites";
function print_rows_as_json($rows) {
foreach ($rows as $row) {
$set_count = 0;
echo "{\"photos\": [";
foreach ($photos = $row["photos"] as $photo) {
$map_count = 0;
echo "{";
foreach ($photo as $key => $value) {
echo "\"{$key}\": \"{$value}\"";
if (++$map_count < count($photo)) {
echo ", ";
}
}
echo "}";
if (++$set_count < count($photos)) {
echo ", ";
}
}
echo "]}" . PHP_EOL;
}
}
// Override default localhost contact point
$contact_points = "127.0.0.1";
if (php_sapi_name() == "cli") {
if (count($_SERVER['argv']) > 1) {
$contact_points = $_SERVER['argv'][1];
}
}
// Connect to the cluster
$cluster = Cassandra::cluster()
->withContactPoints($contact_points)
->build();
$session = $cluster->connect();
// Create the keypspace (drop if exists) and table
$session->execute("DROP KEYSPACE IF EXISTS {$KEYSPACE_NAME}");
$session->execute("CREATE KEYSPACE {$KEYSPACE_NAME} WITH replication = "
. "{ 'class': 'SimpleStrategy', 'replication_factor': 1 }"
);
$session->execute("CREATE TABLE ${KEYSPACE_NAME}.{$TABLE_NAME} ( "
. "id int PRIMARY KEY, "
. "photos frozen<set<map<text, text>>> )"
);
// Create a multiple rows to retrieve
$session->execute("INSERT INTO ${KEYSPACE_NAME}.{$TABLE_NAME} (id, photos) VALUES ( "
. "1, "
. "{{'urllage': '1.jpg', 'urlmedium': '2.jpg'}, "
. "{'urllage': '3.jpg', 'urlmedium': '4.jpg'}}"
. ")");
$session->execute("INSERT INTO ${KEYSPACE_NAME}.{$TABLE_NAME} (id, photos) VALUES ( "
. "2, "
. "{{'urllage': '21.jpg', 'urlmedium': '22.jpg'}, "
. "{'urllage': '23.jpg', 'urlmedium': '24.jpg'}}"
. ")");
// Select and print the unmarshalled data as JSON
$rows = $session->execute("SELECT photos FROM ${KEYSPACE_NAME}.{$TABLE_NAME}");
print_rows_as_json($rows);
// Select the data as JSON and print the string
$rows = $session->execute("SELECT JSON photos FROM ${KEYSPACE_NAME}.{$TABLE_NAME}");
foreach ($rows as $row) {
echo $row["[json]"] . PHP_EOL;
}
From the above example you can see that selecting the data as JSON involves less code for your application while also moving the processing onto the server. This probably the preferred choice for your application needs.
NOTE: This example is using v1.3.0 of the DataStax PHP driver which added support to pass a query strings directly to Session::execute() and Session::executeAsync(). If you are using an earlier version you will need to convert all query strings to Cassandra\Statement objects before passing to $session->execute(...).

Related

Find how many times every word is repeated in db

Am using drupal to manage my content. I want to search all my contents title and body and find how many times each word is repeated in the whole contents.
It may be by an sql query, but I have no experience with sql.
Any ideas?
This code searches the body field and ALL fields of ANY Content Types for a specific string. You can run it via command line. Say you save it as "fieldsearch.php", you can then run it as:
php fieldsearch.php "myStringForWhichToSearch"
You need to fill in your connection data and database name. It outputs the array of matching nodes but you can format that output into anything you'd like (I recommend csv).
<?php
//Set Parameters here
$env = "dev"; // Options [dev|prod] - Defaults to dev
$prodConnection = array(
"host" => "",
"user" => "",
"pass" => ""
);
$devConnection = array(
"host" => "",
"user" => "",
"pass" => ""
);
//Use the selected env settings
if($env == "prod"){
$connection = $prodConnection;
} else {
$connection = $devConnection;
}
function getTables($con, $database){
//Get the set of field tables
$sql = "SHOW TABLES FROM $database";
$result = mysqli_query($con, $sql);
if (!$result) {
echo "DB Error, could not list tables\n";
echo 'MySQL Error: ' . mysql_error();
exit;
}
$tables = array();
while ($row = mysqli_fetch_row($result)) {
$tables[] = $row[0];
}
mysqli_free_result($result);
return $tables;
}
function getFieldTables($con,$database){
$allTables = getTables($con, $database);
$fieldTables = array();
foreach($allTables as $key => $table){
if( isFieldTable($table) ){
$fieldTables[] = $table;
}
}
//add the common tables
$fieldTables[] = "field_data_body";
$fieldTables[] = "field_data_comment_body";
return $fieldTables;
}
function isFieldTable($table){
//echo $table . "\n";
if( stripos($table, "field_data_field") !== FALSE){
return TRUE;
}
}
//Set the search term here:
if (array_key_exists(1, $argv)) {
$searchString = $argv[1];
}
else {
die('usage: php fieldsearch.php "search string"' . "\n");
}
$databaseName = "myDatabaseName";
$outArray = array();
//Connect
$con=mysqli_connect($connection['host'],$connection['user'],$connection['pass'],$databasePrefix.$databaseNum);
// Check connection
if (mysqli_connect_errno()) {
echo "Failed to connect to MySQL: " . mysqli_connect_error();
}
//getFieldTables
$fieldTables = getFieldTables($con, $databaseName);
//Query each field tables data for the string in question
foreach($fieldTables as $key => $table){
//get Field value column name
$valueCol = str_replace("field_data_field_", '', $table);
$result = mysqli_query($con,"SELECT
entity_id
FROM
$table
WHERE
field_" . $valueCol . "_value
LIKE
'%$searchString%';");
if($result){
while($row = mysqli_fetch_assoc($result)){
$dataArray[$table][$row['entity_id']]['nid'] = $row['entity_id'];
}
}
}
//Add the body table
$result = mysqli_query($con,"SELECT
entity_id
FROM
field_data_body
WHERE
body_value
LIKE
'%$searchString%';");
if($result){
while($row = mysqli_fetch_assoc($result)){
$dataArray['field_data_body'][$row['entity_id']]['nid'] = $row['entity_id'];
}
}
var_dump($dataArray);

Mysql Clone user account from database

I have a database with aproximately 200 tables. I want to clone a certain user-account in this database. Is this possible in mysql?
With cloning I mean to create a new user with the same 'settings' as the user with id 14.
A quick google search reveals that you in fact can do this. There is a utility called " "mysql user clone", that lets you surprisingly clone a user for mysql.
If you check out the manual I'm sure it provides you with great tips about how to use it, for instance, this quote:
EXAMPLES
To clone joe as sam and sally with passwords and logging in as root on the local machine, use this command:
$ mysqluserclone --source=root#localhost \
--destination=root#localhost \
joe#localhost sam:secret1#localhost sally:secret2#localhost
# Source on localhost: ... connected.
# Destination on localhost: ... connected.
# Cloning 2 users...
# Cloning joe#localhost to user sam:secret1#localhost
# Cloning joe#localhost to user sally:secret2#localhost
# ...done.
since it appears #Nanne's approach, mysqluserclone is EOL / not supported by Oracle, i wrote a similar utility in PHP, usage:
<?php
$db = new \PDO("mysql:host={$db_creds->dbhost};dbname={$db_creds->dbname};charset=utf8mb4;port=" . $db_creds->dbport, $db_creds->superuser_user, $db_creds->superuser_pass, array(
\PDO::ATTR_EMULATE_PREPARES => false,
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
\PDO::ATTR_DEFAULT_FETCH_MODE => \PDO::FETCH_ASSOC
));
Mysqluserclone::clone_account($db, "original username", "cloned username");
and this part of the code may be of particular interest:
if (0) {
echo "the following SQLs will clone this account:\n";
echo implode("\n\n", $sqls_for_cloning) . "\n\n";
die();
}
<?php
class Mysqluserclone{
private function __construct(){
// by making this private, we ensure nobody try to instantiate us.
}
public static function clone_account(\PDO $db_connected_as_superuser, string $original_name, string $clone_name): void
{
$db = $db_connected_as_superuser;
$sqls_for_cloning = [];
$sql = "SELECT COUNT(*) FROM mysql.user WHERE User = " . $db->quote($clone_name);
if (0 !== $db->query($sql)->fetch(\PDO::FETCH_NUM)[0]) {
throw new \InvalidArgumentException("clone name already exists!");
}
$sql = "SELECT * FROM mysql.user WHERE User = " . $db->quote($original_name);
$current_user_one_for_each_host = $db->query($sql)->fetchAll(\PDO::FETCH_ASSOC);
foreach ($current_user_one_for_each_host as $user_record) {
$user_record["User"] = $clone_name;
$sql = "INSERT INTO mysql.user SET \n";
foreach ($user_record as $name => $val) {
$sql .= self::mysql_quote_identifier($name) . " = " . self::mysql_quote_better($db, $val) . ",\n";
}
if (! empty($user_record)) {
$sql = substr($sql, 0, - strlen(",\n"));
}
$sql .= ";";
$sqls_for_cloning[] = $sql;
$sqls_for_cloning[] = "FLUSH PRIVILEGES;"; // YES this is required, otherwise you might get "grant not allowed to create accounts" errors
$grants_raw_sql = 'SHOW GRANTS FOR ' . $db->quote($original_name) . '#' . $db->quote($user_record['Host']) . ";";
try {
$grants_raw = $db->query($grants_raw_sql)->fetchAll(\PDO::FETCH_NUM);
} catch (\Throwable $ex) {
// somehow an empty grant table is a mysql error, not an empty rowset.. ignore it.
$grants_raw = [];
}
$grants_raw = array_map(function (array $arr): string {
if (count($arr) !== 1) {
throw new \LogicException("mysql layout for SHOW GRANTS has changed? investigate");
}
return $arr[0];
}, $grants_raw);
$original_name_as_identifier = self::mysql_quote_identifier($original_name);
$clone_name_as_identifier = self::mysql_quote_identifier($clone_name);
foreach ($grants_raw as $grant) {
if (false === strpos($grant, $original_name_as_identifier)) {
throw new \LogicException("original grant without original name as identifier? investigate");
}
$grant = self::str_replace_last($original_name_as_identifier, $clone_name_as_identifier, $grant);
$grant .= ";";
$sqls_for_cloning[] = $grant;
}
}
if (! empty($sqls_for_cloning)) {
$sqls_for_cloning[] = "FLUSH PRIVILEGES;";
}
if (0) {
echo "the following SQLs will clone this account:\n";
echo implode("\n\n", $sqls_for_cloning) . "\n\n";
die();
}
foreach ($sqls_for_cloning as $clone_sql) {
$db->exec($clone_sql);
}
}
private static function mysql_quote_identifier(string $identifier): string
{
return '`' . strtr($identifier, [
'`' => '``'
]) . '`';
}
private static function mysql_quote_better(\PDO $db, $value): string
{
if (is_null($value)) {
return "NULL";
}
if (is_int($value)) {
return (string) $value;
}
if (is_float($value)) {
return number_format($value, 10, '.', '');
}
if (is_bool($value)) {
return ($value ? "1" : "0");
}
return $db->quote($value);
}
private static function str_replace_last(string $search, string $replace, string $subject): string
{
$pos = strrpos($subject, $search);
if ($pos !== false) {
$subject = substr_replace($subject, $replace, $pos, strlen($search));
}
return $subject;
}
}

php mySQL Reliable way to check if a row matches a object class

I'm looking for a reliable way to check to see if a database entry matches an equivalent object class in php.
My current method is unreliable, I was hoping someone could supply a better solution.
My current solution seems to work most of the time, but out of around 600 entries, Ill randomly return about 5 entry's that are false positives.
Here is a simplified object class Im using
class MemberData
{
public $AccountID;
public $AccountName;
public $Website;
}
I then use reflection to loop through each property in the class and build my query string in the form of :
SELECT 1 WHERE `Property1` = value1 AND `Property2` = value2 AND `Property3` = value3
However like i mentioned, my code only works most of the time, and I cant pin down a common link on why Im getting false positives. It appears random.
Below is my full function.
//Pass in a member class and see if there is a matching database entry
function SqlDoRowValuesMatch($memberData)
{
//declare global vars into this scope
global $host, $user, $password, $dbname, $tableName;
//initiate the connection using mysqli
$databaseConnection = new mysqli($host, $user, $password, $dbname);
if($databaseConnection->connect_errno > 0)
{
die('Unable to connect to database [' . $databaseConnection->connect_error . ']');
}
//Get all the properties in the MemberData Class
//Using Reflection
$reflect = new ReflectionClass($memberData);
$props = $reflect->getProperties(ReflectionProperty::IS_PUBLIC);
//Build the query string
$sql = "SELECT 1 FROM `".$tableName."` WHERE ";
foreach($props as $prop)
{
if(!is_null($prop->getValue($memberData)))
{
$sql = $sql.$prop->getName()."=".addSingleQuotes(addslashes($prop->getValue($memberData)))." AND ";
}
}
//Cut Trailing operator
$sql = rtrim($sql, " AND ");
if(!$result = $databaseConnection->query($sql))
{
die('There was an error creating [' . $databaseConnection->error . ']');
}
$databaseConnection->close();
//Check for a value of 1 to indicate that a match was found
$rowsMatch = 0;
while($row = $result->fetch_assoc())
{
foreach($row as $key => $value)
{
if($value == 1)
{
$rowsMatch = 1;
break;
}
}
}
return $rowsMatch; //0 = false, 1 = true
}

query function in cake php

I am writing code in php to basically 'map' data from a mySQL database to another database. I am using the code as follows:
$results = $this->query("select PT_FS_DATA_ID from PATIENT_FLOWSHEET_DATA where
DT_LAST_UPDATED_TIME = (select top 1 DT_LAST_UPDATED_TIME from PATIENT_FLOWSHEET_DATA
order by DT_LAST_UPDATED TIME desc) group by PT_FS_DATA_ID;");
however, I am getting an error:
syntax error, unexpected T_VARIABLE, expecting T_FUNCTION
Everywhere I look this seems to be the correct syntax. Is there something I'm missing here?
I tried putting the controller in there as well $this->controllerName->query, but that didn't work either.
Full Code:
class CaExtraFlowsheetFields extends CaBase {
public $name = 'CaExtraFlowsheetFields';
/*
NOTE: This is to take all the fields in flowsheet and
maps their id's.
*/
//public $useTable = 'ANSWER_ENTRY';
public $useTable = 'PATIENT_FLOWSHEET_DATA';
public $primaryKey = 'PT_FS_DATA_ID';
protected function getPrimaryKeyValue(
$hospital_id,
$patient_id,
$admission_id = null
) {
return $patient_id;
}
//*CHANGE BEGIN*
$results = $this->query("select PT_FS_DATA_ID from PATIENT_FLOWSHEET_DATA where
DT_LAST_UPDATED_TIME = (select top 1 DT_LAST_UPDATED_TIME from PATIENT_FLOWSHEET_DATA
order by DT_LAST_UPDATED TIME desc) group by PT_FS_DATA_ID;");
protected $filedMethodMappings = array(
'Method_GO' => array(
CaBase::KEY_MAPPING_LOGIC_COMPLEXITY => CaBase::LEVEL2_COMPLEXITY,
CaBase::KEY_FIELD_LOGIC_NAME => 'wsMethod_GO',
);
//########################################################################//
//Note[]>Block[] //
//>Method that calls LookUpField for every field in flowsheet // //
//########################################################################//
public function wsMethod_GO ($params) {
foreach($results as $value){
$questionName = ''.$value;
$msg_prefix = $this->name . "::" . __FUNCTION__ . ": ". "arrivez-vouz" ;
$ret = $this->wsLookUpField($params,$questionName,$msg_prefix);
return $ret;
}
unset($value);
}
//########################################################################//
public function wsLookUpField($params,$questionName,$msg_prefix){
$arrayValues=array();
try{
$hospital_id = $params[Constants::KEY_HOSPITAL_ID];
$patient_id = $params[Constants::KEY_PATIENT_ID];
$admission_id = $params[Constants::KEY_ADMISSION_ID];
$msg_prefix = $this->name . "::" . __FUNCTION__ . ": ". "attendez-vouz: l'hopital= ".$hospital_id.
" patient= ".$patient_id." admission= ".$admission_id;
//shows info about given question name
$msg_prefix = "*!*!*!*Show me ---> ".$questionName." : ".$answer_entry_id.
" = aic: " .$answer_id_check;
$ret = array();
//now with needed fields, grab the A_NAME:
$params = array(
'conditions' => array(
$this->name . '.PID' => $patient_id,
$this->name . '.PT_FS_DATA_ID' => $questionName,
),
'order' => array(
$this->name . '.' . $this->primaryKey . ' DESC'
),
'fields' => array(
$this->name . '.FS_VALUE_TEXT',
)
);
$rs = $this->find('first', $params);
/* check to make sure $rs has received an answer from the query
and check to make sure this answer is a part of the most recent
database entries for this note */
if (false != $rs) {
try {
$msg = $msg_prefix . "Data obtained successfully."."<br>".$result;
$result = $rs;
$ret = WsResponse::getResponse_Success($msg, $result);
} catch (Exception $e) {
$msg = $msg_prefix . "Exception occurred.";
$ret = WsResponse::getResponse_Error($msg);
}
/*answer was not part of most recent database entries, meaning no
answer was given for this particular question the last time this
particular note was filled out. Message is given accordingly.*/
} else {
$msg = $msg_prefix . "/No answer given.";
$ret = WsResponse::getResponse_Error($msg);
}
} catch (Exception $e) {
$msg = $msg_prefix . "Exception occurred.";
$ret = WsResponse::getResponse_Error($msg);
}
return $ret;
}
Here is what you are doing:
class ABC {
$result = 'whatever';
}
You can't declare a variable there!
Code needs to be inside a method/function...
class ABC
{
public function wsMethod_GO ($params)
{
$result = 'whatever';
}
}

json formatting string to number

My Json output generates;
[
{
"a1_id":"7847TK10",
"output2":"7847TK10",
"output4":"something",
"output5":"3stars.gif",
"output9": "269000",
...
etc. etc.
The google visualization api asks for a number format for the output9 element e.g.:
"output9": 269000 instead of "output9": "269000". How can I achieve this for this element?
My json.php generates the json output like this:
?>
{
"total": <?php echo $total ?>,
"success": true,
"rows": [
// Iterate over the rows
$nextRow= $result->nextRow();
$r = 1;
$info = array();
while ( $nextRow ) {
$nextColumn = $result->nextColumn();
// Has this column been printed already
if ( $unique )
{
$d = $result->getDataForField($unique);
if ( array_key_exists($d, $already) )
{
$nextRow= $result->nextRow();
continue;
}
$already[$d] = true;
}
echo '{';
// Iterate over the columns in each row
while ( $nextColumn )
{
// Get the variable
$variable = $result->getOutputVariable();
$name = $variable->getName(true);
$data = $result->getDataForField();
if ( !isset($info[$name]) ) {
$info[$name]['translate'] = $variable->shouldTranslate();
$info[$name]['type'] = $variable->getDataType();
$info[$name]['linkable'] = $variable->isLinkable();
}
// Translate the data if requested
if ( $info[$name]['translate'] ) {
$data = LQMTemplate::_($data);
}
$data = $variable->format($data, false);
$type = $info[$name]['type'];
if ( ($type == 'bool') or ($type == 'boolean') )
{
$data = $data ? '1' : '0';
echo "'$name':$data";
} elseif ( $encode ) {
// Can we use json_encode ?
// str_replace because some versions of PHP have a bug that will over escape forward slashes
echo "\"$name\":".str_replace('\\/', '/', json_encode($data));
} else {
$data = LQMUtility::jsonEscape($data, '"');
//echo "'$name':\"$data\"";
echo "\"$name\":\"$data\"";
}
// Conditionally print the next column
$nextColumn = $result->nextColumn();
if ( $nextColumn ) echo ",\n ";
}
// Conditionally print the next column
$nextRow = $result->nextRow();
echo $nextRow ? "},\n" : "}\n";
$r++;
}
unset($result);
echo ']}';
}
}
This depends on how you are generating your JSON.
For example, if you were using a Ruby backend, you could call:
"output9" => output9.to_i
There are various helper methods in different languages (e.g. Java and Javascript have parseInt() functions) to change a string into an integer.
Edit:
If your JSON is being generated by PHP, cast the string to an integer:
$json['output9'] = int($output9_value);
That should get rid of the quotation marks.