Non-existant model class properties, no errors, and ZendFramework - php

We are using SocialEngine, produced using ZendFramework. This is not directly a question about SocialEngine, though it relates. This is not specifically a question about ZendFramework either; I imagine the lessons here are broadly applicable to most PhP MVC frameworks.
We have a problem whereby apparently under conditions of high load, some parts of the website stop showing up. For example, an entire widget's content will just fail to load without any apparent errors. The lack of errors to diagnose the problem is driving me crazy.
This is not at all a question about load or optimization.
I can reproduce the similar problem by calling a nonexistant class property from the ZendFramework view, model or controller, e.g.:
<?php echo $this->article->fubar; ?>
At that point the widget it is part of will fail to display without any apparent error. This is problematic when the widget itself is the main display part of the page.
I suspect these problems are ultimately caused by a class variable which has not been initialised but the codebase is too large to identify where without better error reporting. It could also be the result of a chained object failure, e.g. something like:
<?php $this->article->getCategory()->getTitle(); ?>
... could theoretically cause this behaviour if the getCategory() method returned null.
Furthermore, I believe the dearth of error reporting to be caused by 'magic' properties within the ZendFramework's data model, which allows for dynamic class properties such that if the data model has some field "blablabla", $this->article->blablabla is populated with the contents of that field. However, if the property to be accessed is not a database field this magical behaviour does not help very much, especially if it disables normal error reporting. This also explains why $this->article->fubar(); caused the widget to fail to load in the same manner.
How can I get accurate errors out of ZendFramework when faced with this behaviour?

Have you tried to catch the error by putting below code in controller's action or widget controller file?
error_reporting(E_ALL);
ini_set('display_errors', TRUE);
It can be possible that some of your article do not associated with any category or associated category has been deleted from category table, so $this->article()->getCategory() is coming null. It should not happen if category is required field for the article and category is exist in the category table. You can avoid the error by putting the !empty()/instanceof check for such code.

Related

Cake PHP 2.x - view variables not defined as expected

So we are running into a problem that is recurring several times, caught through logs. We are getting loads of undefined variable notices. When we trace where they are supposedly undefined, they are always defined in the matching controller action to the view where it is complaining. We can't figure out how someone is getting to the view either without hitting the controller action, or with hitting it but losing variable definitions somehow.
We tried logging the controller and action whenever a view does this (by checking for undefined vars at thee top of the view), and it always says the correct controller action, so we don't have any unexpected controller actions where the variables aren't defined. It's problematic partially because it's filling up our logs, but we also worry actual users may be getting unexpected results. Does anyone have any idea of a scenario that could cause this?
It has happened with several views that do work fine when tested on our end (we've had several people hit the appropriate urls and the problem doesn't happen). We also checked with a code search, and no other controllers render these views. We have basic safety checks going on for when certain variables are expected in the url; for example, if an id is missing, it will throw a not found exception rather than trying to continue, so we know that's not the cause either.

Fatal error: Call to undefined method Mage_Adminhtml_Model_System_Config_Source_Yesno::setAttribute() in Abstract.php on line 389

I've looked everywhere and can't find how to fix this error. It doesn't show up in any error logs I'm aware of. I can only see it if I look at the page source. It completely stops the page from rendering half way through. How can I fix this?
I also ran into this error so I'm going to assume Freejoy was trying to do the same as me, which was using custom attributes on the customer entity. The Mage_Adminhtml_Model_System_Config_Source_Yesno source model will not work with the customer entity, or any EAV entity for that matter.
Changing to Mage_Eav_Model_Entity_Attribute_Source_Boolean as a source model fixed it for me.
I hope this can help others too.
You've truncated your error message, this
in Abstract.php on
should be pointing to a full file path. Without knowing that full file path, it will be hard to diagnose the problem.
My assumption is Abstract.php is part of a custom module, and that custom module has instantiated a Mage_Adminhtml_Model_System_Config_Source_Yesno (maybe with code that looks like this)
$model = Mage::getModel('adminhtml/system_config_source_yesno');
$model->setAttribute();
and is then trying to call the setAttribute method -- which doesn't exist on this model.
Another possibility is you have a custom modules (or hacked core file) where you've used the model alias adminhtml/system_config_source_yesno in a place where Magento expects a different alias type.
Again, very hard to tell without knowing the exact file the error happens in.

How to implement generic php exception handler

As shown in the php documentation is it possible to create your own exception handler. I see this as a reasonable way to handle my user generated errors and exceptions throughout the project I am working on. Through research I have made a decent amount of progress in implementing a specific one, just for one class, including things like using ErrorException (from the first answer) and making sure to return false for error levels that I can't handle.
I have however run into a wall with making it more generic. I don't want to have to write a separate handler for every class I write (especially because the vast majority of that code is going to be the same for every one). Yet it feels like terribly bad practice to have every single error for the entire project in the same handler.
The closest I have gotten to what feels like an acceptable solution is to write a subclass of ErrorException for every class I want to handle the errors for and store messages in each of those. But even with this I am probably going about it wrong (I don't think that would be the proper place to store default error messages). Is there a universally accepted way of doing this that I have been unable to find? or is one of these ways actually the way it's generally done? or are there multiple solutions that are scalable based on the size of the project?
EDIT: Just realized I can write a generic Exception_Handler with the reused code and extend it for each set of errors I have (real herp moment for me), but it still seems like I should handle all errors in the same place. If I'm completely wrong, let me know.
EDIT 2: Decided to go with a config file containing the error messages for each class that will throw errors, then the name of the class that throws the error defines what config file is loaded to get the list of messages associated with error number. This also allows me to easily define messages that should get logged as opposed to messages that should get sent to the user (essentially specific vs. generic messages).
I guess I'll mark this as answered or something, but if I'm doing something wrong feel free to let me know, help is always appreciated.
Decided to go with a config file containing the error messages for each class that will throw errors, then the name of the class that throws the error defines what config file is loaded to get the list of messages associated with error number. This also allows me to easily define messages that should get logged as opposed to messages that should get sent to the user (essentially specific vs. generic messages).
More specifically I'll probably use an ini file that defines an array of arrays where each number contains the array of error messages for that error number. Then use a foreach with the thrown error numbers to return the error message(s).

Help comprehending how the following framework fits together:

I am just getting into OOP and framework design. I have started by using the following three tutorials;
http://net.tutsplus.com/tutorials/php/creating-a-php5-framework-part-1/
http://net.tutsplus.com/tutorials/php/create-a-php5-framework-part-2/
http://net.tutsplus.com/tutorials/php/create-a-php5-framework-part-3/
This is the first framework I have tried to work with and because the tutorial is not aimed at complete novices I am finding myself having to reverse-engineer the code to see how everything works. The problem is I'm stuck.
First, I understand the basic concepts of the framework including the directory structure.
Second, I understand what the registry and database class are for (although I don't fully understand every function within them just yet).
My problem comes with the index.php, template.class.php and page.class.php files. I broadly know what each should do (although further explanation would be nice!) but I do not get how they fit together i.e. how does the index page interact with the template and page objects to actually produce the page that is displayed. I especially cannot work out in what order everything is called.
The index appears to me as:
require registry class
create instance of registry (don't quite get this bit - easier way to access database?)
store the database and template objects
creates new connection from the stored database object
choose the skin for the page
Then, and here is where I get lost:
build actual page via buildFromTemplates function (which I can't get my head round)
cache a database query
assign tab (i'm completely lost as to what a tag is!)
set page title
display content
Can anyone help break this down for me? I tried Zend before this but it was far too complicated, this one is more accessible but as you can still has me stumped (although I have started to understand objects FAR more by trying).
Thanks in advance.
Firstly I think they over complicated the implementation of the Registry pattern. I always used the following approach which is more straightforward (I'll print a simplified version of it).
class Registry {
protected static $_instances = array();
public static function add($instance, $name) {
self::$_instances[$name] = $instance;
}
public static function get($name) {
return self::$_instances[$name];
}
}
The Registry combined with the Singleton is just a mess.
Regarding the aspects where you got lost:
1. buildFromTemplates
Method accepts unlimited numbers of parameters func_get_args() as template file locations, either relative or absolute. If relative (as in skins/ not being part of the parameter send) overwrite the variable holding the name $bit with the absolute location. If the file exists read in the variable $content. Repeat until all method arguments are used and add the end result to the Page class.
2. Query cache
If the given query does not return a resource_id (which a database query should) it means the query didn't execute successfully and the method triggers and error. Otherwise save the resource_id in the property queryCache for later use. For example:
// assume $db is a reference to the database object and that this is the first
// query
$db->cacheQuery('SELECT * FROM whatever');
$results = $db->resultFromCache(0); // previous query resource_id
.... ahhh, forget it.
This is so messed up, rather recommend you start with some sane framework good for learning internal works. Like CodeIgniter, and move onwards when those concepts are clear.
This tutorial is full of wrong decisions, like errors instead of exceptions, tight coupling, custom template engine (where plain PHP would have sufficed) and more.
Even symfony, which is a big framework is not that hard to follow along the lines.
Ok, its taken me all of the last two nights and tonight (:-S) but I think I have an answer so I will post it to see if it helps anyone else.
I will start from the '//database connection' line
database connection is made
skin is chosen
'buildFromTemplates' function chosen from the 'template' class.
Set the parameter to the page you are trying to build. The layout of the page you wish to create should be stored under skins>templates>filename.
The constructer called when executing the template class will then initiate a new Page instance.
This buildFromTemplates function then takes the parameter aka the file name and then retrieves the content from the file. This will be stored in the $content variable.
the database query is then made and executs the cacheQuery function
the addTag function for the Page object you have instantiated is then called
the title of the page is then set
Finally,
the parseOutput function is called which runs the replaceBits, replaceTags and parseTitle functions. This replaces the respective code written with the page you are trying to create.
Finally the content is output to the page.

check for error

I have my own AppCotroller and using the beforeRender method to make changes to $this->viewPath based on the desired output format.
Is there a way I can check if Cake is currently outputting an error message? If I change the viewPath and then it's displaying an error (like can't load model, etc) it will error on the error :)
By the time Cake is displaying the error it should already be too late to do something about it. Not quite sure why you'd get an error about missing models when you change the viewPath, I hope that was just an example.
You might have some luck overriding or extending the ErrorHandler to intercept errors, but I wouldn't recommend doing that. Errors don't exist to be hidden, they're there to tell you something.
Creating a custom View might be a good idea depending on what you want to do (see the MediaView as an example of an alternative view).
The best thing to do though should be to avoid triggering errors by only allowing certain, predefined views to be set or making sure that a certain view file exists before trying to invoke it.

Categories