PHP SimpleHTMLDom & Php PThreads - Find not finding? - php

Hopefully someone can shed some light on this,
This is launched within a 'worker' thread of php pthreads package.
I load a page using $html = file_get_html("http://www.google.com/");
If I print_r($html) at this point I get :
simple_html_dom Object
(
[root:simple_html_dom:private] => simple_html_dom_node Object
(
[nodetype] => 5
[tag:simple_html_dom_node:private] => text
[attr:simple_html_dom_node:private] => Array
(
[tag] => root
)
[children:simple_html_dom_node:private] => simple_html_dom_node Object
(
[nodetype] => 1
[tag:simple_html_dom_node:private] => html
[attr:simple_html_dom_node:private] => Array
(
)
[children:simple_html_dom_node:private] => simple_html_dom_node Object
(
[nodetype] => 1
[tag:simple_html_dom_node:private] => head
[attr:simple_html_dom_node:private] => Array
(
)...
Then if I try $html->find('a',0), $html->find('a') or even something like $html->find('head'), and print the result, I always get an empty Array.
class Product extends Stackable{
function __construct($prod_id,$link)
{
$this->prod_id=$prod_id;
$this->link=$link;
}
public function get_data($country)
{
//AMAZON API XML REQUEST
return $xml; //XML file
}
public function parse_data($xml)
{
$product = array();
//PARSE PRODUCT XML INTO ARRAY
return $product;
}
public function update_price($product)
{
$html = file_get_html($this->link);
print_r ($html->find('a'));
}
public function run()
{
$xml = $this->get_data('US');
$product = $this->parse_data($xml);
$this->update_price($product);
}
}
$product = new Product(ID,URL);
$worker = new Worker();
$worker->start();
$worker->stack($product);
What could be the issue?
Thanks in advance for any help.

Related

Accessing the properties of an object of an object dynamically in PHP

Given that I'm getting different object results depending of the API I query, here are two examples out of 35 I have to implement:
stdClass Object
(
[mid] => 7127.75
[bid] => 7126.6
[ask] => 7128.9
[last_price] => 7128.8
[low] => 7000.0
[high] => 7492.1
[volume] => 53255.4195502
[timestamp] => 1510265647.9803913
)
stdClass Object
(
[Success] => 1
[Message] =>
[Data] => stdClass Object
(
[AskPrice] => 7095
[BidPrice] => 7070
[Low] => 7001
[High] => 7540
[Volume] => 17.38943459
[LastPrice] => 7090
[Change] => -1.02
[Open] => 7163
[Close] => 7090
)
[Error] =>
)
I want to build mapping variable array to access the object easily.
$xmap["a"]["bid"] = "bid";
$xmap["b"]["bid"] = "Data->BidPrice";
Let's assume $content has the first example object, this will work:
print $content->{$xmap["a"]["bid"]}; // the result is 7128.9
As for the second example object, it does not:
print $content->{$xmap["b"]["bid"]}; // the result is PHP Notice: Undefined property: stdClass::$Data->BidPrice in ...
Can this be done or am I stuck with if statements!
First, convert all the objects into assoc. arrays by using json_encode/decode. You'll find this code multiple times here in stackoverflow
$arr = json_decode(json_encode($obj), true);
Second, I recommend a dot-notation for the key-path, plus a tiny function to find the value in a multidimensional array.
Example:
function fromArray($key, $arr) {
$keys = explode('.', $key);
foreach($keys as $k) {
if (!isset($arr[$k]))
return array(); // return empty array
$arr = $arr[$k];
}
return $arr; // can be a scalar value or array
}
$key = 'my.super.array.content';
$array = ['my' => [
'super' => [
'array' =>[
'content'=>4711
]
]
]
];
var_dump($array, fromArray($key, $array));
/*
array(1) {
["my"]=>
array(1) {
["super"]=>
array(1) {
["array"]=>
array(1) {
["content"]=>
int(4711)
}
}
}
}
int(4711)
*/
I found the dot-notation very useful when dealing with complex structures.
You can convert your objects to arrays and build a large mapping array that needs to be maintained and then explode it and loop through it to access the other arrays; or you can try using patterns. I'm thinking Adapter, but maybe another is a better fit. This is using your second object as an example, but just add as many as needed:
class ContentAdapter {
public function __get($name) {
return $this->obj->{$xmap[$name]};
}
}
class ContentAdapter_API_B extends ContentAdapter {
public $xmap = ['bid' => 'BidPrice', 'ask' => 'AskPrice'];
public function __construct($obj) {
$this->obj = $obj->data;
}
}
Now it is consistant regardless of the object since each has an adapter:
$content = new ContentAdapter_API_B($content);
echo $content->bid;
Using your first object you can either create a child as well (ContentAdapter_API_A in case the structure ever changes) or instantiate directly:
$content = new ContentAdapter($content);
echo $content->bid;
Or obviously just use it as is:
echo $content->bid;
An alternate way without inheritance is to use getters:
class ContentAdapter_API_B {
public function __construct($obj) {
$this->obj = $obj->data;
}
public function getBid() { return $this->obj->BidPrice; }
}
So long as the methods are consistent then it will always work:
$content = new ContentAdapter_API_B($content);
echo $content->getBid;

Update method custom data source not called in cakephp

I am trying to update data using custom datasource. But when i call save after setting the id, it is calling the create method. I have also logged the $Model and in this the id is coming null. As id field is null, create method is called instead of update.
Below is the value of id when i log $Model in Model beforesave
[useTable] => applications
[id] => 191124
[data] => Array
(
[Application] => Array
(
[id] => 191124
[Field] => Array
(
[0] => Array
(
[#id] => 13312
[#type] => 1
[#value] => 10317
)
)
)
)
and when i log the $Model in create id field is null as
[useTable] => applications
[id] =>
[data] => Array
(
[Application] => Array
(
[id] => 191124
[Field] => Array
(
[0] => Array
(
[#id] => 13312
[#type] => 1
[#value] => 10317
)
)
)
)
I am calling save using below code
$data = array(
'id' => $archer_id,
'Field' => array(
array(
'#id' => 13312,
'#type' => 1,
'#value' => 10317
)
)
);
$this->Application->id = $archer_id;
$this->Application->save($data,false);
Model which i am using is
class Application extends ArcherAppModel {
public $hasMany = array('Archer.Assessment');
public $_schema = array(
'Field' => array('type' => 'array')
);
public function beforeSave( $options = array() ) {
$this->log(array("message" => "Data in application before save ","data" => $this->data),'debug');
return true;
}
}
Read function in datasource code is
public function read ( Model &$Model, $queryData = array(), $recursive = null ) {
$this->Model = $Model;
try {
$mid = $this->get_module_id();
$key = $Model->alias . ".id";
if ( array_key_exists( $key, $queryData['conditions'] ) ) $rid = $queryData['conditions'][$key];
elseif ( $Model->id ) $rid = $Model->id;
else $params = $queryData['conditions'];
$params = $this->_params(array(
"moduleId" => $mid,
"contentId"=>$rid
));
$results = $this->_getSoap('records')->__soapCall('GetRecordById', array('GetRecordById' => $params));
if ( property_exists( $results, 'GetRecordByIdResult' ) ) return Xml::build($results->GetRecordByIdResult);
return array();
} catch ( Exception $e ) {
$this->log("OH No...");
$this->log($e->getMessage());
return array();
}
}
Thanks.
Passing an id does not automatically mean it will be an update. Consider the case of saving with mysql where the primary key field is not autoincrement - This (extremely common) case is also supported by the model layer of CakePHP, where inserting and updating with a fixed primary key value both work.
The way the save method works is to check if the id exists, and if it does not the save method clears the model id:
if (!$exists && $count > 0) {
$this->id = false;
}
The consequence of that being an insert, not an update.
if (!empty($this->id)) {
... update ...
} else {
... insert ...
}
The custom datasource mentioned in the question is not shown, but it would appear it does not implement "does this id exist?". That or the model's exists method (which is just a count, if it issues a query to the datasource) is returning false for a different reason.
Forcing an update
To determine yourself whether it is an insert of update, either check why the find-by-primary-key call in Model::exists doesn't work and fix the datasource, or override ModelName::exists to implement whatever logic is necessary i.e.:
// Application Model
public function exists($id = null) {
if (should be an update) {
return true;
}
return false;
}

getting warning when use in_array and multidimensional-array

I make a array and fill it by variables(index and value) by code in php(yii framework). but my program don't work good.I cannot use my array after fill.
in model Lookup.php
private static $row_flags= array();
private static $table_flags= array();
public static function checkStatus($value,$row,$column) {
$thresholds= hreshold::model()->findAll(array('select'=>$row.','.$column));
self::$row_flags['browsing'][$row][$column]=($value < $thresholds[0]->$row) ?"green":(($value > $thresholds[0]->$column)?"red":"yellow");
return self::$row_flags['browsing'][$row][$column];
}
public static function getRowFlag() {
return self::$row_flags;
}
public static function row_color($table,$row){
return in_array("yellow",self::$row_flags['browsing'][$row]);
}
view.php
<?php
lookup::checkStatus(3001,'http','access');
lookup::checkStatus(3001,'http','access');
lookup::checkStatus(3001,'http','core');
lookup::checkStatus(3001,'http','blackbox');
lookup::checkStatus(3001,'http','gateway');
lookup::checkStatus(3001,'http','internet');
print_r(lookup::getRowFlag());
?>
Array
(
[browsing] => Array
(
[http] => Array
(
[access] => yellow
[core] => yellow
[blackbox] => yellow
[gateway] => yellow
[internet] => yellow
)
)
)
if I call Lookup::row_color('browsing','http') in view I have
warning: in_array() expects parameter 2 to be array, null given
Maybe column is the troublemaker:
Instead of l(array('select'=>$row.','.$column));
Use l(array('select'=>$row.','.'select'=>$column));
Use this:
public static function row_color($table,$row){
if (is_array(self::$row_flags['browsing'][$row])) {
return in_array("yellow",self::$row_flags['browsing'][$row]);
}
return FALSE;
}

Check all function arguments

I've been wondering how I could check all my parameters efficiently in any function in a clean and concise way.
I've come up with :
function fooBar($myArg, $mySecondArg, $myOptionnalArg = "defaultValue"){
if(!isset($myArg, $mySecondArg, $myOptionnalArg){
die(__FUNCTION__ . ":missing parameter");
}
if(empty($myArg, $mySecondArg, $myOptionnalArg){
die(__FUNCTION__ . ":empty parameter");
}
//Do stuff
}
What I'm looking for is more like:
function fooBar($myArg, $mySecondArg, $myOptionnalArg = "defaultValue"){
$argArray = func_get_args();
foreach($argArray as $a){
if(empty($a)){
die(__FUNCTION__.":".get_arg_name($a)."is empty");
}
if(!isset($a)){
die(__FUNCTION__.":".get_arg_name($a)."is unset");
}
}
//Do stuff
}
Wich doesn't work since get_arg_name(); is pure fiction, and func_get_args(); returns the actual parameters, rather than the ones defined in the prototype.
Could someone give me a hint about it? Any other good/clean way to achieve that is also welcome.
Thanks
With reflection only. Some example:
function test($a, $b, $c) {
$function = new ReflectionFunction(__FUNCTION__);
$parameters = $function->getParameters();
print_r($parameters);
}
test(0, 1, 2);
You will see something like this:
Array
(
[0] => ReflectionParameter Object
(
[name] => a
)
[1] => ReflectionParameter Object
(
[name] => b
)
[2] => ReflectionParameter Object
(
[name] => c
)
)
Its possible to get what you need with using php reflection:
http://php.net/manual/en/book.reflection.php
Please, read more about how to use it.

Get a PHPActiveRecord result as simple array, not array of objects

I would like to have a simple a method, that can give back PHP Activerecord results as simple/associative arrays, not an array of ActiveRecord Objects.
In Ruby I believe this is done perhaps with .map() method. (I am not a Ruby guy...)
What I want is a simple method call, like toArray() in Zend_DB_Table, not a foreach, or something like that, but I can't seem to find it in their docs.
In PHP ActiveRecord getting a result is really easy:
$settings = SystemSettings::all();
But it gives back something like this:
[0] => SystemSettings Object
(
[errors] =>
[attributes:ActiveRecord\Model:private] => Array
(
[param] => author
[value] => Hawle
)
[__dirty:ActiveRecord\Model:private] => Array
(
)
[__readonly:ActiveRecord\Model:private] =>
[__relationships:ActiveRecord\Model:private] => Array
(
)
[__new_record:ActiveRecord\Model:private] =>
)
[1] => SystemSettings Object
(
[errors] =>
[attributes:ActiveRecord\Model:private] => Array
(
[param] => base_url
[value] => example.com
)
[__dirty:ActiveRecord\Model:private] => Array
(
)
[__readonly:ActiveRecord\Model:private] =>
[__relationships:ActiveRecord\Model:private] => Array
(
)
[__new_record:ActiveRecord\Model:private] =>
)
While this is really great in many cases, here, I would just like to have a simple array, like this:
Array
(
[author] => Hawle
[base_url] => example.com
)
I had a similar issue hopefully this can help someone else who stumbles on it. Obviously, this is specific to phpactiverecord.org.
In /lib/Model.php I added the following function:
public function to_array(array $options=array())
{
return $this->serialize('array', $options);
}
In /lib/Serialization.php I added the following class
class arraySerializer extends Serialization
{
public static $include_root = false;
public function to_s()
{
return self::$include_root ? array(strtolower(get_class($this->model)) => $this->to_a()) : $this->to_a();
}
}
I can then call ->to_array() and get an array back.
Hope this helps!
I was searching for the answer to this question in order to produce an array of results that could be easily json-encoded and sent as the response to an ajax call. I wanted only the attributes of each object in the array of results.
Unfortunately, you can't just call to_json() on each result and then json-encode the entire thing; you end up with double-encoding. Fortunately, though, the function and class posted by #willwashburn to solve this problem have now been included in php-activerecord, though they don't seem to have made it into the online documentation.
To return an array of results, do the following:
$data = MyModel::find('all');
foreach ($data as &$result) {
$result = $result->to_array();
}
Your entire result set will now be an array of arrays, containing only the attributes of each object. You can then do something like
echo(json_encode($data));
if you want to send it as the response to an ajax call.
This is my solution:
$posts = Post::find('all');
$arrayResult = array_map(function($res){
return $res->attributes();
}, $posts);
printf('<pre>%s</pre>', print_r($arrayResult, true));
class MyPHPActiveRecord extends PHPActiveRecord {
public function toJSON() {
return json_encode(get_object_vars($this));
}
}
You could do it like this:
funciton ar2array($settings){
$arr = array();
foreach($settings as $fieldObj){
$fieldName = $fieldObj->attributes["param"];
$fieldValue = $fieldObj->attributes["value"];
$arr[$fieldName] = $fieldValue;
}
return $arr;
}
$resultAsYouWant = ar2array($settings);
Hope this helps. Cheers
PS: If ->attributes is private use its accesor method (there must be one) as ->getAttributes() or equivalent.
I found this looking for solution of the same problem that I encountered using Yii framework - there is simplier way to do this in Yii.
$posts = Posts::model()->findAll();
foreach($posts as $result)
{
print_r($result->attributes);
}
It prints simple array as requested:
Array
(
[id] => 1
[title] => Title
[text] => Text
)
Hope it helps somebody.
My solution:
Added the following method to the utils class found in lib\Utils.php
public static function results_to_json($data)
{
$arr = array();
if(count($data)>0){
foreach($data as $row){
array_push($arr, $row->to_array());
}
}
return json_encode($arr);
}
Call by:
echo \ActiveRecord\Utils::results_to_json($dataobject);
Obviously this is no longer relevant to the OP; however, considering that it still took me over an hour to find a solution for this (no thanks to php-activerecords docs), this may help someone else.
$r = Model::find('$id')->attributes();
$a = [];
foreach ($r as $k => $v)
{
$a[$k] = $v;
}
Perhaps not the most elegant, but works perfectly.

Categories