I have a function that builds a collection of user objects from the database:
public static function GetUsersByGroup($instanceID, $groupID)
{
$col = null;
if($groupID != null)
{
$col = UserGroup::GetCollection("User" ,_DB_GET_ALL_INSTANCE_USERGROUP_MEMBERS,array ($instanceID, $groupID));
}
else
{
$col = UserGroup::GetCollection("User" ,_DB_GET_ALL_INSTANCE_NOGROUP_MEMBERS,$instanceID);
}
echo "this is the collection I am going to return: <pre>";
print_r($col);
echo "</pre>";
return $col;
}
The method has some debug output at the bottom, but the point is if I call that method with a null groupid param i.e it runs the second condition, it prints out a nice indication of the collection that I expected to receive, which is great.
However ..
Here is my calling method:
echo "<br> Collection passed through is: </br>";
$collection = UserGroup::GetUsersByGroup($this->GetInstance()->id,$grouplist->GetCurrentCommandParam());
print_r($collection);
$userlist->UpdateCollection($collection);
$userlist->DeSelect();
The intresting thing is the output:
this is the collection I am going to return:
Collection Object
(
[_valueType:protected] => User
[_isBasicType:protected] =>
[_validateFunc:protected] =>
[_collection:protected] => Array
(
[0] => User Object
(
[valid] =>
[validationMessage] =>
[id] => 29
[table:private] => user
[fields:private] => Array
(
[title] => mrs
[fname] => Kirsty
[lname] => Howden
[email] => kirsty2#softyolk.com
[password] => xxxxxxxx
[lastlogin] => 2009-07-05 15:20:13
[instanceID] => 2
[deliveryAddress] =>
[invoiceAddress] =>
[tel] => 01752848484
[isAdmin] => 0
[disabled] => 0
[mustAuthorise] =>
[usergroupID] =>
)
[validationRules:private] => Array
(
)
[_profileStartTime:protected] =>
[_profileTag:protected] =>
)
[1] => User Object
(
[valid] =>
[validationMessage] =>
[id] => 31
[table:private] => user
[fields:private] => Array
(
[title] => master
[fname] => Seb
[lname] => Howden
[email] => seb#antithug.co.uk
[password] => xxxxxxxxx
[lastlogin] => 2009-07-09 02:02:24
[instanceID] => 2
[deliveryAddress] => saltash
[invoiceAddress] => saltash
[tel] => 8908908
[isAdmin] => 0
[disabled] => 0
[mustAuthorise] =>
[usergroupID] =>
)
[validationRules:private] => Array
(
)
[_profileStartTime:protected] =>
[_profileTag:protected] =>
)
)
)
Collection passed through is:
this is the collection I am going to return:
Collection Object
(
[_valueType:protected] => User
[_isBasicType:protected] =>
[_validateFunc:protected] =>
[_collection:protected] => Array
(
)
)
Collection Object ( [_valueType:protected] => User [_isBasicType:protected] => [_validateFunc:protected] => [_collection:protected] => Array ( ) )
The object returned has been modified??
If the GetUsersByGroup method is called with a userGroupID i.e the first case, then output is all as expected.
If i remove the conditional from the method and simply return $col = UserGroup::GetCollection("User" ,_DB_GET_ALL_INSTANCE_NOGROUP_MEMBERS,$instanceID); then all output is as expected.
It seems that the else condition executes correctly, and then is corrupted on return, but this only happens if the else condition is present, remove the else condition, and simply return the result of the method call in the else condition, and all is as expected.
Any idea please?
Thanks
ADDED THE UserGroup::GetCollection Method (this is a deep rabbit hole though, could go on)
protected static function GetCollection($class, $sqlID, $params = null)
{
$dal = DAL::GetInstance(); //not to be confused with the Instance object, this is an instance of DAL
$collection = new Collection($class);
$items = $dal->QueryForAssoc($sqlID,$params);
foreach($items as $item)
{
$itemObject = new $class();
$itemObject->LoadFromList($item);
$collection->add($itemObject);
}
return $collection;
}
To further clarify the follwing works fine ::
public static function GetUsersByGroup($instanceID, $groupID)
{
$col = null;
//if($groupID != null)
//{
//$col = UserGroup::GetCollection("User" ,_DB_GET_ALL_INSTANCE_USREGROUP_MEMBERS,array ($instanceID, $groupID));
//}
//else
//{
$col = UserGroup::GetCollection("User" ,_DB_GET_ALL_INSTANCE_NOGROUP_MEMBERS,$instanceID);
// }
return $col;
}
I only see the issue if the line is in the else block.
The likely problem here lies in your UserGroup::GetCollection function. PHP 5 passes all objects by reference, so if you are doing any sort of modification in this routine based on the way you are retrieving these objects, then this modification will persist after UserGroup::GetCollection has finished.
I would examine carefully the differences between these two function calls and make sure there are no object changes happening in UserGroup::GetCollection.
$col = UserGroup::GetCollection("User" ,_DB_GET_ALL_INSTANCE_USERGROUP_MEMBERS,array ($instanceID, $groupID));
vs.
$col = UserGroup::GetCollection("User" ,_DB_GET_ALL_INSTANCE_NOGROUP_MEMBERS,$instanceID);
Turns out the method is being called twice, the second call is using the other condition, and returning a blank collection (the problem result).
By setting an echo in each condition I could see as they are called, and first the null case is called and then the non null.
The actual error is that I had a stateful list calling the method twice in the same postback. Hard to catch.
Thanks for looking
Related
I want to be able to display the multidimensional associative array in a table. The arrays are created by Solarium API which is used for debugging any indexing issues. Each array has different number of arrays and keys.
I want it keep it in a way that it works with any number or arrays and keys. I started with using a foreach loop but I'm stuck at this point. How would I go about doing this?
Code I have so far:
foreach ($metadatas as $metadata) {
foreach($metadata as $type => $data) {
echo '<tr>';
echo '<td>'.$type.'</td>';
echo '<td>'.$data.'</td>';
echo '</tr>';
}
}
This is the array I get using print_r():
Solarium\QueryType\Extract\Query Object
(
[options:protected] => Array
(
[handler] => update/extract
[resultclass] => Solarium\QueryType\Extract\Result
[documentclass] => Solarium\QueryType\Update\Query\Document\Document
[omitheader] =>
[extractonly] =>
[uprefix] => ignored_
[commit] => 1
[file] => http://url.com/branch/files/2015/03/Client-Feedback-Form.doc
[document] => Solarium\QueryType\Update\Query\Document\Document Object
(
[boost:protected] =>
[modifiers:protected] => Array
(
)
[key:protected] =>
[fieldBoosts:protected] => Array
(
[id] =>
[site] =>
[description] =>
[url] =>
[title] =>
)
[version:protected] =>
[helper:protected] => Solarium\Core\Query\Helper Object
(
[placeHolderPattern:protected] => /%(L|P|T|)([0-9]+)%/i
[assembleParts:protected] =>
[derefencedParamsLastKey:protected] => 0
[query:protected] => Solarium\QueryType\Update\Query\Document\Document Object
*RECURSION*
)
[filterControlCharacters:protected] => 1
[fields:protected] => Array
(
[id] => 227-7653
[site] => Branch Name
[description] =>
[url] => http://url.ca/branch/files/2015/03/Client-Feedback-Form.doc
[title] => Client Feedback Form
)
)
)
[fieldMappings:protected] => Array
(
[content_type] => type
[author] => authors
[last_modified] => lastModifiedDate
[creation_date] => creationDate
[content] => content
)
[helper:protected] =>
[params:protected] => Array
(
)
)
I need more fake internet points to comment. So instead you get my poor answer. I'd try some sort of recursive function calling.
function someFunction($table , $array){
foreach($array as $key => $value){
if(is_array($value)){
someFunction(&$table, $value)
}
else {
//Add to your existing $table
}
}
return $table;
}
$table = someFunction("" , array());
obviously this is super simplistic view. But the idea is to keep passing your table deeper and deeper into the array. And eventually it will fall back out as you stop running into new arrays. I did something similar a while back passing around a DOMDocument() to build a super complex XML.
But this is only really useful when you don't know the possible size or depth of an array. If your array has keys, even if it's multidimensional, that you know will or won't exist and how deep they go. It's probably better to follow the answer in your comments and just build a nice HTML page.
Good luck.
As you can see from the first line of your output, it is not an array, but an OBJECT! And as you see in [options:protected] , it is protected variable, so you cannot access it from external foreach loop.
What you can do, is to declare a loop function inside that class:
class Query{
....
....
public function iterate(){
foreach ($this->options as $metadata) {
foreach($metadata as $type => $data) {
echo '<tr>';
echo '<td>'.$type.'</td>';
echo '<td>'.$data.'</td>';
echo '</tr>';
}
}
}
}
And then call it outside the class:
$object->iterate();
You can read more about this here: http://php.net/manual/en/language.oop5.iterations.php
Let's say i have this function that seeks for a value inside a bidimensional array:
function findValueBi($array, $field, $value, $returnfield)
{
foreach($array as $key => $product)
{
if ( $product[$field] === $value )
return $product[$returnfield];
}
return false;
}
And the bidimensional array looks like this:
Array
(
[0] => Array
(
[number] => 2
[type] => unimodal
)
[1] => Array
(
[number] => 6
[type] => unimodal
)
[2] => Array
(
[number] => 8
[type] => multimodal
)
[3] => Array
(
[number] => 27
[type] => multimodal
)
[4] => Array
(
[number] => 29
[type] => multimodal
)
)
What the function does, is to look for a given value inside the 'number' key. If it's found, i retrieve its corresponding 'type' key value. For example, if i am looking for the 'number' 29, then i will get the 'type' value "multimodal" (the last item of the array sample). Otherwise, if the value is not found, the function returns false.
So, the way i retrieve this value is as follows:
if(findValueBi($numbers_patterns,'number',$number,'type')!==false){
$resultado=findValueBi($numbers_patterns,'number',$number,'type');
return $resultado;
}
else{ ... }
Is there a better and/or faster way to do this? Is it possible to retrieve the info right inside the if statement? As you can see, I am calling the function twice, so how can i call it once with the if statement???
You could just elect to use it the first time, then use it inside the if:
$resultado = findValueBi($numbers_patterns,'number',$number,'type'); // call it once
if($resultado !== false){
// use $resultado here
}
I want to chain my class's methods, such as in this way,
$article = New Article();
$article->getRow()->addImages();
Because sometimes I don't need to add images to the article that I request,
$article->getRow();
This is my code,
class Article
{
protected $connection;
public $total;
public $item;
public function __construct()
{
$this->connection = new Database(DSN,DB_USER,DB_PASS);
$this->connection->connect();
}
public function getRow($options = array())
{
// Prepare the SQL.
$sql = "
SELECT*
FROM article AS p
WHERE p.article_id = 'home'
";
$this->total = $this->connection->countRows($sql,array(
$property->type
));
$this->item = $this->connection->fetchRow($sql,array(
$property->type
));
return $this;
}
public function addImages() {
$this->item['images']['items'] = array(
0 => "image 1",
1 => "image 2"
);
$this->item['images']['total'] = 2;
return $this;
}
}
result for $article->getRow()->addImages(),
Article Object
(
[connection:protected] => Database Object
(
[connection:protected] => PDO Object
(
)
[dsn:protected] => mysql:host=localhost;dbname=xxx
[username:protected] => xxx
[password:protected] => xxx
)
[item] => Array
(
[url] => hello
[title] => world
[images] => Array
(
[items] => Array
(
[0] => image 1
[1] => image 2
)
[total] => 2
)
)
[total] => 1
}
As you can see that [connection:protected] is always in the result, and [total] => 1 for the article as well.
But how can I get the result in like this below straight to the requested/ intended data without doing this $article->getRow()->addImages()->item,
Array
(
[url] => hello
[title] => world
[images] => Array
(
[items] => Array
(
[0] => image 1
[1] => image 2
)
[total] => 2
)
)
Is it possible?
I find that $article->getRow()->addImages()->item is 'ugly' for getting a simple data.
When using $this to use method chaining, you inherently pass the whole object in your return. This is how we can use method chaining, but you seem fully aware of that. What you desire seems a bit odd though:
You want to use method chaining (meaning your return value is $this)
You want to receive only your item property (meaning your return value is not $this)
Those seem mutually exclusive as I seriously think a method can not return two different things.
But
you can have your addImages() function return what you desire. Note that this solution prevents any further method chaining...
public function addImages() {
$this->item['images']['items'] = array(
0 => "image 1",
1 => "image 2"
);
$this->item['images']['total'] = 2;
return $this->item; // HERE you return your item instead
}
I'm looking for a way to make it so cake returns all database data in the same format/structure... Currently it returns two different types of format depending on the relationship.
If a model 'B' is associated with the current model 'A' being queried it will then place model associations for 'B' underneath it as you can see in [User] below. I want it so that all queries use that structure.
example:
$this->find('all', ....
returns:
Array
(
[0] => Array
(
[UserGroup] => Array
(
[id] => 53
[user_id] => 100003332014851
[media_id] =>
[name] => john
[description] => qwasdfad
)
[User] => Array
(
[id] => 100003332014851
[session_id] => ssm2qbrotmm13ho1ipm8ii2492
[username] =>
[password] => -1
[Planner] => Array
(
)
[Purchase] => Array
(
)
[Listing] => Array
(
)
)
)
I want this to look like:
Array
(
[0] => Array
(
[UserGroup] => Array
(
[id] => 53
[user_id] => 100003332014851
[media_id] =>
[name] => john
[description] => qwasdfad
[User] => Array
(
[id] => 100003332014851
[session_id] => ssm2qbrotmm13ho1ipm8ii2492
[username] =>
[password] => -1
[Planner] => Array
(
)
[Purchase] => Array
(
)
[Listing] => Array
(
)
)
)
)
)
In CakePHP, the find() method return data like your first format. But If you want to format like second one then you have to process it by hand (try to avoid this if possible)
$data = $this->find('all');
$assocs = Set::extract('/User', $data); // extracting all `User` array
foreach($assocs as $key => $assoc) {
unset($data[$key]['User']); // removing the associate `User` from `$data`
$data[$key]['UserGroup']['User'] = $assoc['User']; // adding associate under `UserGroup`
}
ended up doing this... it changes the output to what we need. The top level item does not have a header which is fine I just adjusted our scripts for that... maybe this will help somebody else if they need a custom idea
also no guarantee this covers all possible results but so far it works with all the queries we have.
class AppModel extends Model {
function afterFind($results, $primary) {
//if this is a primary, structure like a secondary so entire site is same format
if ($primary) {
$class = get_class($this);
//simple fix for primary
foreach ($results as $key => $result) {
$result = $this->formatData($result, $class);
$results[$key] = $result;
}
}
return $results;
}
function formatData($result, $class) {
$array = array();
if (isset($result[$class])) {
$array = $result[$class];
unset($result[$class]);
}
$array += $result;
return $array;
}
You can also use contain in this case along with find as UserGroup.User for your desired result
I have constructed a set of nodes. After running them through node_save(), I get back an nid, and I can navigate to the page for that node, but they are empty. (No data is shown for any of the fields.)
When I go to the edit url for that node, I get this error message:
warning: call_user_func_array()
[function.call-user-func-array]: First
argument is expected to be a valid
callback, 'Bout_node_form' was given
in
/home/odp/public_html/includes/form.inc
on line 367.
Here is the print_r() of one node I am trying to save:
stdClass Object
(
[type] => Bout
[name] => Gary Oak
[title] => Bout - 0
[promote] => 1
[comment] => 2
[revision] =>
[format] => 0
[status] => 0
[field_weapon] => Array
(
[0] => Array
(
[value] => foil
)
)
[field_fencer] => Array
(
[0] => Array
(
[uid] => 3
)
)
[field_touches_scored] => Array
(
[0] => Array
(
[value] => 4
)
)
[field_meet] => Array
(
[0] => Array
(
[nid] => Drew
)
)
[field_round] => Array
(
[0] => Array
(
[value] => 1
)
)
[field_legacy_bout] => Array
(
[0] => Array
(
[value] => no
)
)
[teaser] =>
[uid] => 1
[created] => 1262732370
[validated] => 1
)
These nodes have all been run though node_validate(), and presumably that would have caught some errors. Also, this node is missing required taxonomy, but that isn't causing any error messages, either.
This is how node_validate() was called:
function preview_validate($form, &$form_state) {
$nodes_to_save = construct_nodes();
foreach ($nodes_to_save as $node) {
node_validate($node, $form);
if ($errors = form_get_errors()) {
form_set_error('', t('Validation error. No nodes saved.'));
}
}
$_SESSION[CONSTRUCTED_KEY] = $nodes_to_save;
}
This is where the error is coming from, in the core file includes/form.inc:
// If $callback was returned by a hook_forms() implementation, call it.
// Otherwise, call the function named after the form id.
$form = call_user_func_array(isset($callback) ? $callback : $form_id, $args);
The node shows up in the node table, but not the content_type_bout table.
This is the construct_nodes() function:
function construct_nodes() {
global $user;
$file = unserialize($_SESSION[FILE_KEY]);
$count = 0; // how many nodes have been created?
$success = TRUE; // have all the nodes thus far validated?
foreach ($file->parsed as $node) {
$odp = new StdClass();
$odp->type = $_SESSION[NODE_TYPE_KEY];
if (! in_array('name', $file->matched_keys)) {
$odp->name = $user->name;
}
if (! in_array('title', $file->matched_keys)) {
$odp->title = sprintf("%s - %s", $_SESSION[NODE_TYPE_KEY], $count);
}
$node_type_default = variable_get('node_options_'. $_SESSION[NODE_TYPE_KEY], array('status', 'promote')); //copied from blogapi module
$odp->promote = in_array('promote', $node_type_default);
$odp->comment = variable_get('comment_'. $_SESSION[NODE_TYPE_KEY], 2);
$odp->revision = in_array('revision', $node_type_default);
$odp->format = FILTER_FORMAT_DEFAULT;
$odp->status = CTN_DEFAULT_PUBLISHED;
// this makes the assumption that the field arrays will always have only one item
// doesn't handle taxonomy
foreach ($node as $field => $value) { // $field => value: [Touches scored] => 5
$node_key = $file->matched_keys[$field]; // $node_key will be something like: "field_meet" or "vid:4"
$vid = vidOfTaxKey($node_key);
if ($vid == NULL) {
$valTypes = $_SESSION[SAMPLE_NODE_KEY]->$node_key; // like: [0] => Array ( [uid] => 3 )
$valType = array_keys($valTypes[0]);
$odp->$node_key = array(array($valType[0] => $value));
}
}
$to_save[] = $odp;
$count++;
unset($submitted_odp);
}
return $to_save;
}
bout is a CCK-defined content type. Using the human name "Bout" for the type instead of the internal code name bout was, I believe, a source of error.
where is this custom content type defined? in a custom module, or via Administer > Content > Content types > Add content type? is it defined at all? if not, then no wonder you get this error: how is Drupal supposed to know what this content type is composed of and how to render its view and edit forms? try defining it, either way.
custom content (node) type names ([type] => Bout) must contain only lowercase letters, numbers, and underscores. try changing Bout to bout.
see also How do I create a node from a cron job in drupal? and http://drupal.org/node/178506#comment-895418 (the whole thread).
try this
<?php
$new_blognode = new stdClass();
$new_blognode->type = 'blog';
module_load_include('inc', 'node', 'node.pages');
$output .= drupal_get_form('blog_node_form', $new_blognode);
?>
note that you should change this to your needs
$node['type']='bout'; NOT $node['type']='Bout';
Confirm that you are not struck with simple caps problem.