Chain a js action on form displayFieldError - php

I have a form that use displayFieldError when submitted to display errors on fields. I need to show/hide a container on certain error conditions, is possible to chain a js action on it?

Extending and redefining methods is a normal practice in Object Oriented development. Besides, you can do that globally by creating this:
class Form extends Form_Basic {
function displayFieldError(){
.. your actions ..
}
}
This will work across your project and will not loose any functionality.

all Views in Agile Toolkit carries a jquery class and is capable of calling jquery and is also chainable.
BUT the object extending the view class MUST implement an ID=NAME attribute in its HTML template.
here's an example of a view, a Text object which will not get hidden:
$t=$this->add('Text')->set('Press Buton To Hide Me');
$b=$this->add('Button');
$b->js('click',
$t->js()->hide() // hide it
)->univ()->successMessage('Hiding Text..'); // js chained
its clear that Text objects has javascript capability but will not work on itself, even attaching a click command will NOT work.
here's another example of a view, an extended HtmlElement class which WILL get hidden:
$t=$this->add('P')->set('Press Buton To Hide Me');
$b=$this->add('Button');
$b->js('click',
$t->js()->hide() // hide it
)->univ()->successMessage('Hiding Text..'); // js chained
inspect both sources and you will immediately see the difference.
therefore, make sure that the container you are referring to is a class extension of the View class and its associated Template has an id="<?$_name?>" implementation in it.
i am not sure of any other simpler way.

Related

Symfony EventSubscriber to change twig render path

i would ask You about proper way to change dynamicly the $twig->render path called from controller.
I want to create custom loader or event subscriber, which works like:
when i set parameter/param and call from controller
return $this->render('system/create.html.twig');
twig will check, if template in path
system/custom/variable_name/create.html.twig
exists, load it, if not, load normal path
system/create.html.twig
I can't find proper way to realize it, have not idea, what i should use, EventSubscriber(and how to Subscribe on render method), or just realize it with some custom Twig loader?
#EDIT
Problem solved! There is no way to do it "on the fly", so i extend AbstractController in custom Class, override render method and check in this method all conditions.

PHP - Calling abstract class child method only once?

I'm new to OOP programming and am in the process of creating a settings page and extending various abstract classes.
I have created two abstract classes admin_setting and theme_admin_setting (extends admin_setting) which itself has two extended classes: (not abstract) setting_news and setting_buttons with very similar functionality but different form fields outputted on the page.
Each button/news item is then able to be added to and removed on the settings page by javascript and then on submit it is all saved to the database.
When adding a new button/news item (in the JS) as the form fields are different it gets a bit messy so I wanted to pass some variables to the script to make the code a bit cleaner.
The problem arose when I wanted to pass Javascript some values in a script tag but only wanted to do this once per instance of each extended class.
For example:
setting_news:
<script>var news_array = <?php echo $news_array... </script>
setting_buttons:
<script>var button_array = <?php echo $button_array... </script>
But each time the class is instantiated (about 10 times per page) it obviously outputs the script tag and I wanted to keep the code tidy so to only do it once.
Is the answer perhaps to create another abstract class one deeper than theme_admin_setting with a counter function within that?
You can have public static $isCalled = false; inside each extended class and than when calling function just do
if (!self::$isCalled) {
self::$isCalled = true;
/* do your code */
}

How to make Zend automatically switch view and layout with contexts?

I have a mobile site that I added detection to for iPhones and other iOS devices. The iOS page needs a different layout and views than the regular pages (which are actually for older mobile devices). So, I have some code that does mobile detection, that part was easy. What I'd like to do is make it so that Zend automagically finds and uses the correct layout and view when an iOS device is detected, but that has turned out to be surprisingly hard...
I needed it to be up and running ASAP, so I did a quick and dirty hack that worked: in each action function, I have a simple If statement that detects if the iOS boolean flag has been set (which happens in the controller's init), and if so, overrides the layout and view explicitly. Existing code (in the actions):
if ($_SESSION['user']['iPhone']) {
$this->_helper->layout->setLayout('osriphone'); // 'osr' is the name of the app
$this->_helper->viewRenderer->setRender('iphone/index');
}
So this works, but it's kinda ugly and hacky and has to be put in each action, and each action's Renderer has to be set, etc. I got to reading about the Zend ContextSwitch, and that seemed like exactly the kind of thing I should use (I'm still kind of new to Zend), so I started messing around with it, but can't quite figure it out.
In the controller's init, I'm initializing the ContextSwitch, adding a context for 'iphone' and setting the suffix to 'iphone', and now what I'd like to do is have a single place where it detects if the user is an iOS device and sets the context to 'iphone', and that should make it automatically use the correct layout and view. New code (in the controller's init):
$this->_helper->contextSwitch()->initContext();
$contextSwitch = $this->_helper->getHelper('contextSwitch');
$contextSwitch->addContext('iphone', array('suffix' => 'iphone'));
$contextSwitch->setAutoDisableLayout(false);
if ($_SESSION['user']['iPhone']) {
//$this->_currentContext = 'iphone'; // Doesn't work.
//$contextSwitch->initContext('iphone'); // Doesn't work.
//$contextSwitch->setContext('iPhone'); // Not the function I'm looking for...
// What to put here, or am I barking up the wrong tree?
}
I did some reading on the contextSwitcher, and it seems like there is a lot of stuff on, e.g. setting it to be specific to each particular action (which I don't need; this needs to happen on every action in my app), and going through and modifying all the links to something like /osr/format/iphone to switch the context (which I also don't really need or want; it's already a mobile site, and I'd like the layout/view switch to be totally transparent to the user and handled only from the backend as it is with my quick and dirty hack). These seem like basically an equal amount of code to my quick and dirty hack. So... Anyone have some suggestions? I'm really hoping for just a single line like "$contextSwitch->setContext('iphone');" that I could use in an If statement in my controller's init, but the Zend documentation is awful, and I can't seem to find any examples of people doing something like this on Google or SO.
Ok I think I figured out how to put this into a plugin:
The Plugin:
//This is my own namespace for ZF 1.x library, use your own
class My_Controller_Plugin_Ios extends Zend_Controller_Plugin_Abstract {
public function preDispatch(Zend_Controller_Request_Abstract $request) {
parent::preDispatch($request);
if ($_SESSION['user']['iPhone']) {
$this->_helper->layout->setLayout('osriphone');
$this->_helper->viewRenderer->setRender('iphone/index');
}
}
}
register the plugin in your application.ini
resources.frontController.plugins.ios = "My_Controller_Plugin_Ios"
I think that's all there is to it. Although you may want to look into the userAgent plugin
ContextSwitch operates off the "format" property in the request object (by default). You need to set it somewhere in your app
$requestObject->setParam('format', 'iphone').
I'd set it in a bootstrap, or more appropriately, a controller plugin, but where it goes really depends on your app.
I don't use Zend ContextSwitch so I can't really help there, but you could use some inheritance in your controllers to set all layouts in just a couple of lines. Even though it might still be classed as a "hack" it is a way better hack
Now whenever you execute a action Zend first fires a number of other functions within the framework first, such as the routing, the preDispatch, Action helpers and so on. It also fires a number of things after the action such as PostDispatch. This can be used to your advantage.
First create a controller called something like "mainController" and let it extend Zend_Controller_action and in this controller create a function called predispatch()
Second. Extend your normal controllers to mainController. Since we now have a function called predispatch() Zend will automatically fire this on every controller, and if you do your iPhone/iOS check there it will automagically be performed on every action on every controller, as long as you don't overwrite the method in your controller (you can make this method final to prevent this). You can offcourse use a multitude of different non-Zend functions and/or helpers within the mainctroller to make the code as compact and reusable as possible Se example code below:
<?php
/**
*Maincontroller
*/
class MainController extends Zend_Controller_Action
{
/**
* Predispatch function is called everytime an action is called
*/
final public function preDispatch(){
//for security reasons, make sure that no one access mainController directly
$this->request = $this->getRequest();
if (strtolower($this->request->controller)=='main')
$this->_redirect('/index/index/');
//Check for iPhone
if ($_SESSION['user']['iPhone']) {
$this->_helper->layout->setLayout('osriphone'); // 'osr' is the name of the app
$this->_helper->viewRenderer->setRender('iphone/index');
}
}
}
<?php
/**
*Othercontroller
*/
class OtherController extends MainController
{
/**
* The correct layout for IndexAction is already set by the inherited preDispatch
*/
public function indexAction(){
/* YOUR CODE HERE */
}
}
For a good overview of the dispatch process check these links (same picture in both):
http://nethands.de/download/zenddispatch_en.pdf
http://img.docstoccdn.com/thumb/orig/22437345.png

PHP workaround to extend classes of the same name?

I know extending a class with the same name is not possible, but I was curious if anyone knew of a way to load a class then rename it, so i can later extend it with the original name. Hopefully like something below:
<?php
//function to load and rename Class1 to Class2: does something like this exist?
load_and_rename_class('Class1', 'Class2');
//now i can extend the renamed class and use the original name:
class Class1 extends Class2{
}
?>
EDIT:
Well, I understand that this would be terrible practice in a basic OOP environment where there are large libraries of class files. But i'm using the CakePHP MVC framework and it would make great sense to be able to extend plugin classes in this way since the framework follows a well established naming convention (Model names, view names, controller names, url routes (http://site.com/users), etc).
As of now, to extend a CakePHP plugin (eg: Users plugin) you have to extend all the model, view, and controller classes each with different names by adding a prefix (like AppUsers) then do some more coding to rename the variable names, then you have to code the renamed url routes, etc. etc. to ultimately get back to a 'Users' name convention.
Since the MVC framework code is well organized it would easily make sense in the code if something like the above is able to be implemented.
I'm trying to work out why this would be necessary. I can only think of the following example:
In a context that you have no control over, an object is initialised:
// A class you can't change
class ImmutableClass {
private function __construct() {
$this->myObject = new AnotherImmutableClass();
}
}
$immutable = new ImmutableClass();
// And now you want to call a custom, currently non existing method on myObject
// Because for some reason you need the context that this instance provides
$immutable->myObject->yourCustomMethod();
And so now you want to add methods to AnotherImmutableClass without editing either Immutable class.
This is absolutely impossible.
All you can do from that context is to wrap that object in a decorator, or run a helper function, passing the object.
// Helper function
doSomethingToMyObject($immutable->myObject);
// Or decorator method
$myDecoratedObject = new objectDecorator($immutable->myObject);
$myDecoratedObject->doSomethingToMyObject();
Sorry if I got the wrong end of the stick.
For more information on decorators see this question:
how to implement a decorator in PHP?.
I happen to understand why you would want to do this, and have come up with a way to accomplish what the end goal is. For everyone else, this is an example of what the author may be dealing with...
Through out a CakePHP application you may have references to helper classes (as an example > $this->Form->input();)
Then at some point you may want to add something to that input() function, but still use the Form class name, because it is through out your application. At the same time though you don't want to rewrite the entire Form class, and instead just update small pieces of it. So given that requirement, the way to accomplish it is this...
You do have to copy the existing class out of the Cake core, but you do NOT make any changes to it, and then when ever you upgrade cake you simply make an exact copy to this new directory. (For example copy lib/Cake/View/Helper/FormHelper.php to app/View/Helper/CakeFormHelper.php)
You can then add a new file called app/View/Helper/FormHelper.php and have that FormHelper extend CakeFormHelper, ie.
App::uses('CakeFormHelper', 'View/Helper');
FormHelper extends CakeFormHelper {
// over write the individual pieces of the class here
}

How do I print the HTML element hidden in Zend_Form_Element_Select?

I have a form which I create manually (a lot of JavaScript in it...). I am using the Zend_Form classes on the server side to validate input and some more.
Is there a way to get a Zend_Form_Element_Select (or any other element) to be rendered without rendering the entire Zend_Form object?
Do you mean something like,
$element = new Zend_Form_Element_Select(...);
echo $element->render();
?
That will render only a Select element, not an entire form.
That method is defined in the Zend_Form_Element class that is the parent of all the Zend_Form_Element_* classes. See the API for more information.

Categories