For my own amusement, I am creating a XML reader class that utilizes PHP's SimpleXMLElement class. Eventually I will port this over to CodeIgniter as a library so I can utilize it in future applications. However, for now I am testing it using vanilla PHP. My end goal is to be able to traverse XML documents. For now, I am looking at this feed: http://rubygems.org/gems/sass/versions.atom.
The issue
I am having difficulties passing information into my own count() method. Here is the method:
public function count($element) {
$this->element = $element;
return $this->xml->element->count();
}
The idea of the method above is to allow anyone to pass in an object and it would return an int that identifies the number of children that particular element has. Normally, this would work:
$xml->title->count(); // returns 1, for example
What has been Tried
echo $xml->count('entry'); // always results in 0
public function count($element) {
return $this->xml->$element->count();
}
echo $xml->count('entry'); // still results in 0
echo $xml->count($xml->entry); // Undefined property
The Question
What is the correct approach to doing this? Any guidance would be appreciated! Here is the class in its entirety: http://pastebin.com/VjhjGcaR
Having the count() method like:
public function count($element) {
return $this->xml->$element->count();
}
And using it like:
echo $xml->count('entry');
Will print 201 with the ATOM file in your example.
Did you really just try it with foo? If so, that explains the zero results.
Related
I have a collection of objects. Every time when I get an element of this collection, I want to be sure that I get next element in this collections, when I get to the end of collection I just simply start to iterate it from very beginning.
For instance:
$listOfObjects = new WrappedCollection(array('Apple','Banana','Pikachu'));
$listOfObjects.getElement(); //I get Apple
$listOfObjects.getElement(); //I get Banana
$listOfObjects.getElement(); //I get Pikachu
$listOfObjects.getElement(); //I get Apple
I already implemented this with SplDoublyLinkedList, but everytime when I need to loop this list, I need to save the position of iterator, I am sure that there is a way to implement this more beautiful.
$this->listOfRunningCampaigns = new \SplDoublyLinkedList();
// Getting element of collection
public function getNextRunningCampaign(): Campaign
{
$this->listOfRunningCampaigns->next();
if ($this->listOfRunningCampaigns->current() !== null)
{
return $this->listOfRunningCampaigns->current();
}
$this->listOfRunningCampaigns->rewind();
return $this->listOfRunningCampaigns->current();
}
Here is example of what I have to do when I loop through collection:
// Saving current iterator position
$currentIteratorPosition = $this->listOfRunningCampaigns->key();
for ($this->listOfRunningCampaigns->rewind(); $this->listOfRunningCampaigns->valid(); $this->listOfRunningCampaigns->next())
{
//... some action
}
$this->moveRunningCampaignsListIterator($currentIteratorPosition);
// Function that moves iterator
private function moveRunningCampaignsListIterator($index): void
{
for ($this->listOfRunningCampaigns->rewind(); $this->listOfRunningCampaigns->valid(); $this->listOfRunningCampaigns->next())
{
if ($this->listOfRunningCampaigns->key() === $index)
{
break;
}
}
}
In my opinion the way I implemented this looks really bad, In near future I am about to make a lot of different actions with the elements of this collection and taking care of iterator every time is not the way I want to see this working. Can you please suggest some ways of implementing this?
Why you don't just use next()? This built-in function will do the rest with the array pointer for you.
In case you want to develop an array wrapper, I think you should take a look at Doctrine\Common\Collections\ArrayCollection, or use it directly, they did a great job and it also is available via Composer
I have a chain call like so:
$object->getUser()->getName();
I know that I can use a string to call a function on an object:
$functionName = 'getUser';
$object->$functionName() or call_user_func(array($object, functionName))
I was wondering if it was possible to do the same for a chain call?
I tried to do:
$functionName = 'getUser()->getName';
$object->functionName();
But I get an error
Method name must be a string
I guess this is because the () and -> cannot be interpreted since they are part of a string? Is there any way I can achieve this without having to do:
$function1 = getUser;
$function2 = getName;
$object->$function1()->$function2();
The aim is to get an array of functions and to chain them, in order to call this chain on the given object, e.g.:
$functions = array('getCoordinates', 'getLongitude'); // or any other chain call
$functionNames = implode('()->',$functions);
$object->$functionNames()
Let's start with a more neutral text format that's easy to handle:
$chain = 'getUser.getName';
And then simply reduce it:
$result = array_reduce(explode('.', $chain), function ($obj, $method) {
return $obj->$method();
}, $object);
Note that you could even inspect the $obj to figure out whether $method is a method or a property or even an array index and return the value appropriately. See Twig for inspiration.
I am trying to create a generic way of filtering objects in and array. Sometimes this filtering requires a chain call to compare specific fields with a given value.
I think that instead of inventing new solution you can use existing one like PropertyAccess Component from Symfony.
This is probably very easy to do, but I can't seem to get my head around it right now. Let's say in a component in a cakephp application, I have a variable my_model, which contains the model of the corresponding controller that is currently using the component like:
function TestComponent extend Object
{
var $my_model; // can be either User, or Person
function test()
{
$myModelTemp = $this->my_model;
$model = $myModelTemp != 'User' ? $myModelTemp.'->User' : 'User';
$this->$model->find('all');
}
}
As you can see above in my function test() what I'm trying to do is call the correct model based on the value of my_model. So based on the condition, my query will be either:
$this->Person->User->find('all');
Or
$this->User->find('all');
When I do it like I did above, I get an error saying Fatal error: Call to a member function find() on a non-object. In order words, that error means Person->User is not an object (so, it is considered as a string).
What you're saying could be true, however, it can refer to any part of the call.
So either Person or User could be invalid, or together they causes the error. Hard to say.
Try dumping the individual objects using var_dump();
So try:
<?php
echo "<pre>";
var_dump(is_object($this->Person));
var_dump(is_object($this->User));
echo "</pre>";
?>
to determine where you're code goes wrong.
To be clear, that return value needs to be true for it to be an object.
The one that returns false is the likely culprit.
Should your question refer to the correct way to reference an object, an object is basically an array. For example:
<?php
$obj = (object) array("this", "my_function");
?>
The above example casts the array as an object. However, using multiple layers might prove to be more difficult than you'd expect.
Generally, it looks like you might be going about this all wrong. Obviously you want the models to be dynamic, but then you're hard-coding things which defeats the whole point of it being dynamic in the first place.
It also seems like you might be violating the principals of CakePHP and MVC by doing all this in a component. I'm not sure this component should really be manipulating models or assuming which models are currently in use.
However, if you want to evaluate a string as an actual object, you can wrap it in { ... } (this is valid standard PHP syntax, not Cake-specific code).
Try this:
$modelName = $this->my_model;
$model = ($modelName != 'User') ? $this->{$modelName}->User : $this->User;
$model->find('all');
Now, if this doesn't work or you get an error saying it can't find the model(s) you need to ensure the models are actually loaded and initialised in the current scope.
I'm trying to develop a Flex Mobile / PHP application, and I'm running into some trouble with the AsyncToken... Does it not just return a basic string?
For example... I'm wanting to just return a simple string result from my request - right now, it's going to return a basic output string from the method that's implemented. The backend part works (PHP), I've done all of that... It's this that's giving me some problems:
import mx.rpc.AsyncResponder;
import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;
protected function button_clickHandler(event:MouseEvent):void
{
loginResult.token = user_service.login();
loginResult.token.addResponder(new AsyncResponder(onResult,onFault));
}
public function onResult(event:ResultEvent, token:Object):void
{
// what would i do here??
}
public function onFault(event:FaultEvent,token:Object):void
{
txtResult.text = event.fault.faultDetail;
}
It's pretty straightforward - any suggestions, or recommendations would surely help! Thank you!
Easy enough. The ResultEvent#result property contains the value returned by the remote service. All you need to do is cast it to the right type (since it is an Object by default).
For instance, handling your service method that returns a String:
public function onResult(event:ResultEvent):void {
var s:String = event.result as String;
}
Same goes for other types:
var a:Array = event.result as Array;
Or even more complex custom classes:
var instance:MyClass = event.result as MyClass;
Note that this last example will only work with AMF remoting; you have to have the same class definition on the client side and on the server side; and you have to let them know of each other's existence by using the [RemoteClass(alias="net.riastar.MyClass")] metadata tag on your AS class definition. How you have to handle this on the server side depends on the language used there.
Ok, so I had this neat little idea the other night to create a helper class for DOMDOCUMENT that mimics, to some extent, jQuery's ability to manipulate the DOM of an HTML or XML-based string. Instead of css selectors, XPath is used. For example:
$Xml->load($source)
->path('//root/items')
->each(function($Context)
{
echo $Context->nodeValue;
});
This would invoke a callback function on every resulting node. Unfortunately, PHP version < 5.3.x doesn't support lambda functions or closures, so I'm forced to do something a bit more like this for the time being:
$Xml->load($source)
->path('//root/items')
->walk('printValue', 'param1', 'param2');
Everything is working great at the moment and I think this project would be useful to a lot of people, but I'm stuck with one of the functions. I am attempting to mimic jQuery's 'replace' method. Using the following code, I can accomplish this quite easily by applying the following method:
$Xml->load($source)
->path('//root/items')
->replace($Xml->createElement('foo', 'bar')); // can be an object, string or XPath pattern
The code behind this method is:
public function replace($Content)
{
foreach($this->results as $Element)
{
$Element->parentNode->appendChild($Content->cloneNode(true));
$Element->parentNode->removeChild($Element);
}
return $this;
}
Now, this works. It replaces every resulting element with a cloned version of $Content. The problem is that it adds them to the bottom of the parent node's list of children. The question is, how do I clone this element to replace other elements, while still retaining the original position in the DOM?
I was thinking about reverse-engineering the node I was to replace. Basically, copying over values, attributes and element name from $Content, but I am unable to change the actual element name of the target element.
Reflection could be a possibility, but there's gotta be an easier way to do this.
Anybody?
Use replaceChild instead of appendChild/removeChild.
Lookup if $element has a nextsibbling prior to removing if so do an insertBefore that next sibling otherwise simply append.
public function replace($Content)
{
foreach($this->results as $Element)
{
if ($Element->nextSibling) {
$NextSiblingReference = $Element->nextSibling;
$Element->parentNode->insertBefore($Content->cloneNode(true),$NextSiblingReference);
}
else {
$Element->parentNode->appendChild($Content->cloneNode(true));
}
$Element->parentNode->removeChild($Element);
}
return $this;
}
Totally untested though.
Or as AnthonyWJones suggested replaceChild , big oomph how did i miss that moment :)