Google Cloud Datastore: Working with Keys - php

I haven't found any documentation on this, although it must exist somewhere, being as it's rather simple.
I can query using PHP for all of the tasklists (for example) as follows:
$query = $datastore->query();
$query->kind('tasklist')
->filter('date_approved', '<', 0)
->order("date_approved")
->order("date_updated", $query::ORDER_DESCENDING)
->limit(50);
$res = $datastore->runQuery($query);
And to see the key (for example, for updates), I've been using:
foreach($res as $r) {
$parentkey = $r->key()->pathEnd()['name'];
echo $parentkey; //"default"
}
I noticed if i "JOIN" child records, that were created as follows:
$childkey = $datastore->key('tasklist', $parentkey)
->pathElement('task', 'task001');
$entity = $datastore->entity($childkey, $myTaskArray);
$datastore->upsert($entity);
When I later query for those by "parent" key:
$subquery = $datastore->query();
$subquery->kind('task')
->filter('date_approved','<',0)
->hasAncestor( $datastore->key('tasklist', $parentkey) )
->order("date_approved")
->order("date_updated", $subquery::ORDER_DESCENDING);
$subres = $datastore->runQuery($subquery);
Then printing the key for the child will work the same:
foreach($subres as $sr){
$childkey = $sr->key()->pathEnd()['name'];
echo $childkey; //"task001"
}
Is there a method for working with keys and keys of ancestors that's less goofball than: $entity->key()->pathEnd()['name'];
For example, in MongoDB
$myobj = array();
$db->Insert($myobj);
echo (string) $myobj['_id']; //key
Also, shouldn't i be able to update a document by providing the key alone, and not having to specify the ancestor key?
$childkey = $datastore->key('tasklist', $parentkey)
->pathElement('task', "task001");
$entity = $datastore->lookup($childkey);
$entity = $datastore->entity($childkey, $myUpdatedTaskArray);
$datastore->update($entity, array("allowOverwrite"=>true));
versus:
$childkey = $datastore->key('task', "task001");
$entity = $datastore->lookup($childkey);
$entity = $datastore->entity($childkey, $myUpdatedTaskArray);
$datastore->update($entity, array("allowOverwrite"=>true));
Lastly, can i query for entities AND their descendants without having to do a join (as i'm doing above), while still filtering (date_approved<0 for example) and sorting (date_updated DESC also for example).
NOTE: goofball being a non-technical term

Is there a method for working with keys and keys of ancestors that's less goofball than: $entity->key()->pathEnd()['name'];
Keys in datastore are a rather complex concept, so they're not able to be used quite in the same way you suggest from your work with Mongo. However, there are some helpers on the Google\Cloud\Datastore\Key class which would simplify your code a little bit. You could use pathEndIdentitifer in place of pathEnd()['name']. For instance, $key->pathEndIdentifier(). This is quite useful especially in cases where you may not know whether the key uses an ID or a Name.
Also, shouldn't i be able to update a document by providing the key alone, and not having to specify the ancestor key?
Unfortunately not. A key of form [Parent: john, Child: junior] refers to an entirely different entity than a key of form [Child: junior]. To use parent entities, you must supply the full key path. If however you can think of ways to make this easier on you, please let me know, preferably by filing an issue. I'd love to figure out how to make this easier -- I know it is a bit complex currently.
Lastly, can i query for entities AND their descendants without having to do a join (as i'm doing above), while still filtering (date_approved<0 for example) and sorting (date_updated DESC also for example).
Unfortunately not. You can query for either one kind or none (i.e. a kindless query). This latter type can query multiple kinds, but you cannot do filtering on entities properties or values.

Related

How to replace collection in query result Mongo

I queried to get info from a table with a manytomany relationship like this
$userList = UserListing::where('user_id', $user->id)->with("objects")->paginate(10);
Now, i want to limit the amount of results in the "Objects" table, but at the same time i want to know how many objects are in total.
$userList = UserListing::where('user_id', $user->id)->with(["objects"=> function($query) {
$query->take(2);
}])->paginate(10);
But by doing this, i can't get the total of objects since i limited it to 2, then i tried to process the info like this
$userList = UserListing::where('user_id', $user->id)->with("objects")->paginate(10);
foreach ($userList as $key => $value) {
$l = count($value["objects"]);
$value["objects"] = $value["objects"]->take(2);
$value["number_objects"] = $l;
}
But apparently this did not replace the collection value["objects"], since it still returned 3 objects, despite supposedly being reduced with $value["objects"] = $value["objects"]->take(2);. How can i replace the collection with the reduced one?
So, i kept investigating, and noted that userList was a LengthAwarePaginator object, which by property apparently is inmutable in its original fields(Meaning you can add new ones, but not delete/modify the already existent). Knowing this, i searched a little more and found this answer:
https://stackoverflow.com/a/49133519/7228093
Which basically creates a new LenghtAwarePaginator from the original one, allowing you to modify the fields. If someone finds in this situation, this may be a good option(The transform method of collections did not work by the way, only this one).

Why does Symfony provide an OrderedHashMap

Symfony provides an OrderedHashMap. Its documentation states
Unlike associative arrays, the map keeps track of the order in which keys were added and removed. This order is reflected during iteration.
I'm confused by this statement, because I thought PHP associative arrays are actually already ordered maps. I found this question on SO, which confirms my previous assumption: Are PHP Associative Arrays ordered?
I wonder, if the Symfony devs didn't know PHP arrays are already ordered maps or if I don't understand the role of Symfony's OrderedHashMap
Of course PHP's array is an ordered-map.
But Symfony's OrderedHashMap has some different behaviors (say, features) from PHP's array.
OrderedHashMap supports concurrent modification during iteration. That means that you can insert and remove elements from within a foreach loop and the iterator will reflect those changes accordingly. But array in the iteration is a copied one (Copy-On-Write), any modification is not reflected in the loop.
$map = new OrderedHashMap();
$map[1] = 1;
$map[2] = 2;
$map[3] = 3;
foreach ($map as $index => $value) {
echo "$index: $value\n"
if (1 === $index) {
$map[1] = 4;
$map[] = 5;
}
}
You will get different output if you are using array. In the iteration of an array the loop won't see the number 5.
About "Why?": Search it in Symfony's codebase. There is only one place to use the OrderedHashMap, which is used to store a form's children. It's used by new InheritDataAwareIterator($this->children) to iterate. So I think the answer is to help to process the form's children.
And thanks to #fishbone:
So the benefit is not the ordering but the ability to modify it in loops.
In general, not only in Symfony's context, beside additional implemented features, object oriented structures are preferred over primitive types such as int, string or array as they can be injected into the class for unit testing.
Object oriented structures can enforce invariants as well whereas primitive types can only hold data without any behaviors.

indexed array foreach shorthand

Data:
$players = array(
new Player('psycketom'),
new Player('stackexchanger'),
new Player('max')
);
Usually, in order to get something out of every object within array, we have to use for / foreach.
foreach ($players as $player)
{
var_dump( $player->score );
}
But, since it's a repetitive task, is there a way to shortcut it to something along these imaginary lines(?):
var_dump( every( $players )->score );
every( $players )->score += 40;
Since I have not seen such a feature for php, is there a way to implement it?
I have asked the question using php as main language, but the language-agnostic and programming-languages stand for the second part of the question: what languages support such or at least similar shorthand?
So, you are correct that PHP does not support this "out of the box" (except kinda, see below). The first language I know of that does is Objective-C (well, at least the CoreFoundation library). NSArrays and other sets have methods to (in one line) instruct that a given method should be executed on all members; and even more cool (to me, at least) is the concept of "keypaths" and the support that NSArray and others has for them. An example; lets say you have an array of "people" who each have a parent, who in turn have a "name":
arrayOfNames = [peopleArray valueForKeyPath:"parent.name"];
arrayOfNames is now an array of all the parents' names.
The closest thing PHP has is array_map, which you can use together with anonymous functions to very quickly whip something together.
edit anecdotal as it may be, one should remember that loop structures don't need their curly-braces if there is only one statement to execute; so any fancier solutions need to compete with this:
foreach($players as $p) $p->score += 40;
And I'll mention a deeper solution for those OOP fans out there... If you work with collection objects instead of arrays, the world is your oyster with stuff like this. The simplest concept that comes to mind is php's magic __call() method. How simple to iterate over your members and make that call for your users? For more controll, you can implement a few different strategies for iteration (one for transforms, one for filters, etc. Difference being what gets returned, essentially). So in theory you could create a few different iterator classes, and in your "main" collection class implement a couple methods to get one of them, which will be pre-initialized with the contents:
$players->transform()->addScore(40);
where transform() returns an instance of your "don't return the array" iterator, which uses the __call() technique.
The sky starts to open up at this point, and you can start to build filter iterators which take predicates and return another collection of a subset of the objects, and syntax like this is possible:
// send flyer to all parents with valid email address
$parentsPredicate = new Predicate('email');
$players->filteredByPredicate($parentsPredicate)->each()->email($fyler_email_body);
You could do:
var_dump(array_map(function($el){return $el->score;}, $players));
array_walk($players, function($el) {$el->score += 40;});

What is the best way to store and search through class objects (in PHP)?

I've around 80 instances of this class called Items and would like to efficiently search the objects by their ID or NAME.
<?php
class Item
{
public $id;
public $name;
//methods
}
?>
I'm using PHP5.
Assuming no duplicate names or IDs:
$ids = array();
$names = array();
foreach ($items as $item) {
$ids[$item->id] = $item;
$names[$item->name] = $item;
}
If you have duplicates (of names; I imagine there are no duplicate IDs by definition) then you need to work out how to handle that. You could store all the duplicates under one key (so the value becomes an array of matches).
Or do you mean a more sophisticated search? If so, a simple variant might be to break up the item name into words and/or phrases and then index them accordingly into an array.
I would think about making an ItemIndex class;
this would allow you to maintain an arbitrary number of
independent indexes, overloading the comparison and
search functions as appropriate.
If you have 80 instances, it really doesn't matter which option you use. Even if your search is N squared, I don't think it's worth it to invest time into a performance optimization here. Do the simplest thing and then profile; if it's horrible, only then consider increasing the complexity of the implementation to make it faster.

How do I create a list or an array of objects in PHP?

I'm a .net programmer vb & c#, but I can't seem to figure out how to get my objects into a list or array in PHP.
var mylist = new List<myobject>();
mylist.add(myobject1);
mylist.add(myobject2);
What I have tried.
Products being a property for a collection of orderitems:
$this->Products = getOrderItems();
public function getOrderItems()
{
$items = array();
$count = 0;
// connect to db, query.....
while($row = mysql_fetch_array($result, MYSQL_BOTH)){
$count++;
$items[$count] = ($row);
}
echo 'Count of Order Items...' . $count;
return $items;
}
Am I even close?
$items = array();
while($row = mysql_fetch_array($result, MYSQL_BOTH)) {
$items[] = $row;
}
echo 'Count of Order Items...', count($items);
$this->Products = getOrderItems(); is legal in PHP, but it refers to the (global) function getOrderItems() instead of the class method. class methods and variables always have to be prefixed with $this-> (or self::, if they're static vars) when called from inside the class.
in your sample-code, you have that wrong. getOrderItems is defined as class method, but your call is not $this->-scoped, thus php assumes a function. it should throw an function not found-error.
the [] notation adds an element to the end of an array.
the index of the first element in your sample code is 1 (isn't that the standard case for VB?). php normally starts at 0 - though it's possible (because php-arrays are not real arrays) to start at arbitrary indices i'd recommend to stick with zero.
mysql_fetch_array is an ancient way of working with mysql. nowadays you're better of with mysqli or (even better) PDO.
(...) a list or array in php.
lists, arrays, stacks, whatever: in php everthing is an ordered map (misleadingly called array):
PHP: Arrays: An array in PHP is actually an ordered map. A map is a type that associates values to keys. This type is optimized for several different uses; it can be treated as an array, list (vector), hash table (an implementation of a map), dictionary, collection, stack, queue, and probably more. As array values can be other arrays, trees and multidimensional arrays are also possible.
update:
sorry, i haven't got enough time right now to explain the finer nuances of pdo/mysqli over mysql.
so here are just the basics:
oop: pdo and mysqli are object oriented (tough mysqli got functional aliases)
prep statements: most important: pdo/mysqli got prepared statements. that means, you first prepare the query with placeholders once, then fill in the values later (without the need to prepare the query a second time). this approach has 3 obvious advantages:
performance: it's faster, because the database only has to analyze, compile and optimize the query once (at least with complex queries)
security: no need for quoted strings (happens automatically!), making sql-injection attacks harder
maintainability: the logic and data part of the query are separated, thus easier to read and you don't have to do a lot of string concenation
driver driven: pdo is not database specific. there are several supported db-systems, making it easier to port your code to other db-backends (but it's not an db-abstraction layer like ODBC, so the SQL still has to be compatible) and increasing reusability
of course, there's a lot more to it
What orlandu63 posted is correct - using $items[] = $row means that $row is appended numerically as the next element of $items.
Another option is that if there's an id field in $row, you can do $items[$row->id] = $row;, which has the advantage of indexing your array and making it easier to find a given item.
I really suggest reading through http://www.php.net/manual/en/language.types.array.php, which will explain to you some of the cool things PHP allows with arrays.

Categories