Zend Framework partialLoop with associative array of models - php

I'm making a web application in Zend Framework. I've reached the stage of cleaning up. As things often go, I have a couple of messy view scripts that have become utterly unreadable (tons of (v)sprintf's and loops).
There's one view that's an absolute nightmare... (no/inaccurate comments, shorthand... all things considered to be mortal sins). Just an example:
$rows[$c] .= '<div>'.sprintf('<select id="%s" name="%1$s">',$t.'['.$ref->getCode().']').str_replace('>'.$ref->getCValue().'<',' selected="selected">'.$ref->getCValue().'<','<option>'.implode('</option><option>',$this->vals['P']).'</option>').'</select></div>';
In this particular case, I have an array of models that looks like this:
$arr = array('FOO'=> $Mylib_Model_Person,'BAR'=> $Mylib_Model_Person2);//1~50 mdls
I would like to use a partial loop, but there's a problem:
$this->partialLoop('controller/_myPartial.phtml',array('model'=>$arr));
//in the partial loop:
Zend_Debug::dump($this->m);
I see all my models correctly, but their keys have all been turned into properties.
$this->FOO->someMethod();//works fine
Bur I want it to be:
<span><?php echo $key; ?></span><span><?php echo $model->someMethod(); ?></span>
I've also tried using $this->partialLoop()->setObjectKey('Mylib_Model_Person');, but that didn't seem to make any difference, other then confuse me.
The only solutions I see is either array_map, but that would defeat the point (I'm trying to end up with a clean view script); or rewrite a part of my service layer, to return the data ready structured, and keep the array_map there.
I can't help thinking that what I want to do, essentially use a partialLoop as an array_map callback, is possible. If it isn't, is there an alternative? Any thoughts?
I've tried get_object_properties($this), and iterate through the object properties, to no avail, the loop simply doesn't get executed(?!)
As it turns out $this->partialLoop()->setObjectKey('Mylib_Model_Person'); should have been $this->partialLoop()->setObjectKey('model');. If I do change this, and start the partial loop by dumping $this->model, I see my model. However:
echo $this->model->someMethod(); //throws error: method on non-object
Zend_Debug::dump(get_class_methods($this->model));//shows all methods, including someMethod()
And to add insult to injury, tears and confusion. The model implements the toArray-thing, so I tried:
echo $this->model['someData'];//Error: cannot use object of type Mylib_Model_Person as array!!
So, it's not an object when I try to use methods, it's an object when trying to access data as an array, and when using the magic getter method ($this->model->some_Data) it doesn't do anything. No errors, but no output either. The view is rendered as is.
I'm thinking I ran into a bug. I'll rapport it. Consider this:
$methods = get_class_methods($this->model);
while($m = array_shift($methods))
{
if (substr($m,0,3) === 'get')
{
Zend_Debug::dump($m);//e.g getName
Zend_Debug::dump($this->model->{$m}());//'Foobar'
$m = 'someMethod';//copy-paste, so typo's aren't to blame
Zend_Debug::dump($this->model->{$m}());//'the data I was after'
}
}
So that works, but the, if I try:
$this->model->{'someMethod'}();//Error again
//or even:
$m = 'someMethod';
echo $this->model->{$m}();//Error...
That can't be right

I found out what the problem was. Our development server used to be set up better in terms of error reporting:
I assumed E_ALL | E_STRICT, but I had a look only to find it changed to a cruddy E_COMPILE_ERROR | E_ERROR | E_CORE_ERROR. Seeing as some values in the array can be false rather then an object, at some point in the partialLoop script, a notice should have been raised - with the correct ini settings, of course.
That was the cause of the unexpected behaviour; that, and a silly bug or two.

Related

unrequire a file once it's been required in PHP

Suppose I do
require('lol.php');
whereby lol.php contains the following function declaration
function lolfunc(){
}
is it possible to "unrequire" lol.php such that I can then require another file
require('lol2.php');
whereby lol2.php contains a function with the same name previously declared in lol.php:
function lolfunc(){
echo "this is lol2 biyotch";
}
and have lolfunc() be the one declared in lol2.php? eg if I call lolfunc() it'll echo "this is lol2 biyotch"??
My answer: don't do that.
Try to work with the original author to include the functions you need into a patched version of the old code and then use that patched version everywhere.
If you can't do that, find out how big a job it would actually be to update all the code to new version. Start with white-box analysis: see what's changed in terms of interfaces, data structures et al. Then examine the calling code to see whether the caller cares about any of the things that have changed.
If you can't even do that, use namespacing or some other form of wrapping so that you can include both libs. However, make sure any initialisaton or setup is done on both libs!
What you should do, is to include the required (sets) of files based on conditional clauses, instead of trying to "unrequire".
So:
if($flag_use_oldver)
{
include("oldver.php");
}
else
{
include("newver.php");
}
If you want a more sophisticated solution, of course you could try to have a wrapper class hierarchy that will extend/override as required, but I think that is a bit over-engineering for a pretty straightforward problem statement.

How to properly call a class while providing error reporting at the class-caller level

I am writing fresh code, as part of refactoring an older legacy codebase.
Specifically, I am writing a Device class that will be used to compute various specifications of a device.
Device class depends on device's model number and particle count and I can call it as $device = new Device($modelNumber, $particleCount);
Problem: since this class will go into existing legacy code, I have no direct influence on if this class will be called properly. For Device to work, it needs to have correct model number and correct particle count. If it does not receive the proper configuration data, internally device will not be initialized, and the class will not work. I think that I need to find a way to let the caller know that there was an error, in case an invalid configuration data was supplied. How do I structure this to be in line with object oriented principles?
Or, alternatively, do I need to concern myself with this? I think there is a principle that if you supply garbage, you get garbage back, aka my class only needs to work properly with proper data. If improper data is supplied, it can bake a cake instead, or do nothing (and possibly fail silently). Well, I am not sure if this principle will be great. I do need something to complain if supplied configuration data is bad.
Here is some code of what I am thinking:
$device = new Device($x, $y);
$device->getData();
The above will fail or produce bad or no data if $x or $y are outside of device specs. I don't know how to handle this failure. I also want to assume that $device is valid when I call getData() method, and I can't make that assumption.
or
$device = new Device($x, $y);
if ($device->isValid())
$device->getData();
else
blow_up("invalid device configuration supplied");
The above is better, but the caller has to now they are to call isValid() function. This also "waters down" my class. It has to do two things: 1) create device, 2) verify device configuration is valid.
I can create a DeviceChecker class that deals with configuration vefication. And maybe that's a solution. It bothers me a little that DeviceChecker will have to contain some part of the logic that is already in Device class.
Questions
what problem am I trying to solve here? Am I actually trying to design an error handling system in addition to my "simple class" issue? I think I probably am... Well, I don't have the luxury of doing this at the moment (legacy code base is huge). Is there anything I can do now that is perhaps localized to the pieces of code I touch? That something is what I am looking for with this question.
I think you need to use below code to verify your passed arguments in construct
class Device {
public function __constructor($modelNumber, $particleCount) {
if(!$this->isValid($modelNumber, $particleCount) {
return false; //or return any error
}
}
}
This will check the passed params are valid or not and create object based on that only, otherwise return false or any error.

Is there a way to tell Smarty not to print an expression?

I'd like to use Smarty in conjuction with the Zend Framework, especially some of it's View Helpers.
Now i got to the point, where i implemented a Zend_View that uses Smarty to display templates. I can assign values as usual. So far so good.
Now I would really like to use Zend View Helpers in Smarty. I asssigned the Zend_View object as "this" and tried this in the template:
{$this->layout()->setLayout('default')}
As this will print the return value of the setLayout() method (which is a Zend_Layout), there is an error:
Catchable fatal error: Object of class Zend_Layout could not be converted to string in /path/to/templates_c/089c3d67082722c7cabc028fa92a077f8d8b4af5.file.default.tpl.cache.php on line 27
This is clear to me, so I went into Smarty's core to fix this:
The generated code did look like this:
<?php
echo $_smarty_tpl->tpl_vars['this']
->value->layout()
->setLayout('default');
?>
And now it reads:
<?php
$hack = $_smarty_tpl->tpl_vars['this']
->value
->layout()
->setLayout('default');
if( is_string($hack) ||
( is_object($hack) && method_exists($hack, '__toString') ) )
echo $hack;
?>
Now this is probably the worst fix i can think of, for several reasons (Smarty compatibility loss, performance). Sadly, it's the only one. Is there a way to stop Smarty from trying to print the output of the expression? Also, i want the syntax to stay as intuitive as possible, and i don't want to write Smarty functions for all the Helpers, because I want to use this code with a third-party application (Pimcore) that might add new helpers.
Thanks in advance for any suggestions!
Some suggestions (only ideas, nothing so good):
Create a __toString() in Zend_Layout who returns null or empty string (big/ugly/worse workaround).
Create a variable modifier/filter who return null or empty string, so your call will be something like {$this->layout()->setLayout('default')|noreturn} (you can use it with other things too and noreturn can be called with an friendly name like definition or define to indicate the purpose of the instruction, but a workaround too)
Using the assign to build a expression who set all this thing to another var (workaround too).
Maybe this can give you some good ideas =)

Conditional Component Loading in CakePHP

I'm using the DebugKit component in my project but I want to turn it on only on the staging server and have it not load when running from the production server.
I know I can turn it off with the debug config value but I want to keep that value at 1 for both servers.
I tried conditionally defining a contstant 'DEBUG_KIT' in bootstrap.php as either the component name (ie. 'DebugKit.Toolbar') or null. Then using that constant in the var $component definition at the top of the app_controller file. Well, Cake doesn't like having a null in the component array and barfs. Doesn't like an empty string either.
I feel like I'm missing something but can't quite see the forest for the trees. Thanks in advance!
I think the fundamental purpose of DebugKit is tied to being in debug mode, so I can understand that the tools don't provide the capacity to be disabled without also disabling debug mode.
That said, if you absolutely must do this, I think your best bet is to directly modify app/plugins/debugkit/controllers/components/toolbar.php, supplementing the existing debug-mode check in ToolbarComponent::initialize with a check against your constant.
(For what it's worth, I think you'd be better off turning debug-mode off on your production server, and using errors/warnings logged in /app/tmp/logs/error.log to identify issues that have slipped through your testing.)
I do something similar in my apps: I would use the __construct method to detect the presence DEBUG_KIT and add it to the $components array. This function gets called before the $components array is processed, so you can add/remove components transparently.
In your app_controller
function __construct(){
if(DEBUG_KIT){
$this->components[] = 'DebugKit.Toolbar'
}
parent::__construct();
}
If you have a _construct function in any or your individual controllers, remember to include parent::_construct(); otherwise you'll 'break the chain'.
Hope this helps
First, thanks to Adam Giles for a great answer. I hadn't thought to look at the __construct() callback. That just may be a better way than I found. And to Daniel Wright, point made sir. I'll probably change my production server to 0 debug soon and start watching the error logs.
I found my own answer shortly after posting this question. The DebugKit has an 'autoRun' parameter that will turn it on and off. So, I first set a global constant in bootstrap.php like this:
define( 'IS_DEV', ($_SERVER['SERVER_NAME'] == 'staging.example.com') );
Then in app_controller.php, I use it to set the 'autoRun' parameter in the $components statement.
var $components = array( 'DebugKit.Toolbar'=>array('autoRun'=>IS_DEV) );
This seems to work pretty well so far.

systematizing error codes for a web app in php?

I'm working on a class-based php web app. I have some places where objects are interacting, and I have certain situations where I'm using error codes to communicate to the end user -- typically when form values are missing or invalid. These are situations where exceptions are unwarranted ( and I'm not sure I could avoid the situations with exceptions anyways).
In one object, I have some 20 code numbers, each of which correspond to a user-facing message, and a admin/developer-facing message, so both parties know what's going on. Now that I've worked over the code several times, I find that it's difficult to quickly figure out what code numbers in the series I've already used, so I accidentally create conflicting code numbers. For instance, I just did that today with 12, 13, 14 and 15.
How can I better organize this so I don't create conflicting error codes? Should I create one singleton class, errorCodes, that has a master list of all error codes for all classes, systematizing them across the whole web app? Or should each object have its own set of error codes, when appropriate, and I just keep a list in the commentary of the object, to use and update that as I go along?
Edit: So I'm liking the suggestions to use constants or named constants within the class. That gives me a single place where I programatically define and keep track of error codes and their messages.
The next question: what kind of interface do I provide to the outside world for this class' error codes and messages? Do I do something like triggerError(20) in the class, and then provide a public method to return the error code, the string constant, and the user- and admin-facing message?
You could create a couple of defines to create named constants for all your error codes :
define('ERROR_CODE_SQL_QUERY', 1);
define('ERROR_CODE_PAGE_NOT_FOUND', 2);
define('ERROR_CODE_NOT_ALLOWED', 3);
// and so on
And, then, use the constants in your code :
if ($errorCode == ERROR_CODE_SQL_QUERY) {
// deal with SQL errors
}
With that, nowhere in your code you'll use the numerical value : everywhere (except in the on and only file where you put the defines), you'll use the codes.
It means :
Less risk of errors, as all numerical values are set in only one file
Less risk of errors, as you'll use the constants, that have a name which indicates what it means
And code that's easier to read.
Another idea could be to create a class to deal with errors :
class Error {
const CODE_SQL_QUERY = 1;
const CODE_PAGE_NOT_FOUND = 2;
const CODE_NOT_ALLOWED = 3;
// Add some methods here, if needed
}
And, then, use something like this :
if ($errorCode == Error::CODE_SQL_QUERY) {
// deal with SQL errors
}
Which one is the best ?
It's probably a matter of personnal preferences... If you need to add some methods to deal with the errors, using a class might be useful. Else, defines are a great solution too.
At the very least, can you bump the code numbers up to be class constants or members?
class MyErrorProneClass {
const TURNED_INTO_A_NEWT = 12;
...
public function dontBurnMe() {
// echo your error here using self::TURNED_INTO_A_NEWT
}
This way you can manage the errors in the same place where you use them, rather than having to maintenance a large central file. I tried something to that effect in the past and it becomes difficult to keep up.
Generating error numbers programmatically may be a better long-term solution. If you could use information about the file or line number (__FILE__ and __LINE__ respectively), that would help.
Hope that moves in the right direction at least.
Thanks, Joe
Edit:
A class member would follow this syntax instead:
class MyErrorProneClass {
protected static $turnedIntoANewt = 12;
...
public function dontBurnMe() {
// echo your error here using self::$turnedIntoANewt
}
Since constants are public by default, you can access them from other classes directly if you want. So, from the outside, the error would be referenced as:
MyErrorProneClass::TURNED_INTO_A_NEWT
For associating to messages, you would use a mapping (either in a database, or in some localization file) from error ID (and frontend/backend) to displayed string. This use of keys for messages isn't optimal, but it would allow you to change error messages without changing code as well.
If you don't know already it might be an idea to use trigger_error (), plus an error handler if you want to present the user with a better error message.
Have you thought about using exceptions? They may be a good choice for your problem here although adding them to your project now would probably require some restructuring.
You can extend the basic exception class so it fits your problem in terms the of user / developer error message separation.

Categories