Zend_Form disable populate before isValid() - zend-form

Im not able to disable populating values in Zend_Form .
I have my own form class. With hidden token element where I would like to dynamicaly setup random value every time the form is called (or reposted). I thought that setValue will make the job.
class MY_Form_Test extends Zend_Form {
public function init() {
...
$this->addElement('hidden', 'token');
$this->getElement('token')->setValue(uniqid('',true));
...
}
BUT: When I have simple controller like this. Zend automate populating old hidden values except to generate new one.
$form = new JC_Form_Test();
if($form->isValid($_POST)){
// Action ...
}
else{
// Error
}
SOLUTION: The only solution I found is to call setValue in Controler AND AFTER isValid method. eg. in Error block.
QUESTION: Is there any way to setup element values directly in form class OR disable populate values in form class or before isValid() is called?

I think it's the best way to do it.
I work much with Zend Framework and have my own library for overwrite some Zend classes.
It's not bad to change something, but don't do it directly within Zend Framework

SECOND SOLUTION: Second solution I found is to overload isValid() method in Form class. Like this. Then I dont need to put setValue() into every Controller.
class MY_Form_Test extends Zend_Form {
...
public function isValid($data){
// Propagate values
$valid = parent::isValid($data);
$this->getElement('token')->setValue(uniqid('',true));
return $valid;
}
Are there any other solution eg. some element option to do this job more simple?

Related

MVC 4 is overwriting specific Action-Parameters

MVC 4 does present me some strange behaviour at the moment.
Imagine the following Code:
TestController.cs
public class TestController : Controller
{
public ActionResult Index(Function function, string action)
{
return View();
}
public class Function
{
public string Action { get; set; }
}
}
It seems, that when I call the URL directly through the browser (localhost:PORT/Test), the Action-Property gets automatically filled with "Index".
If the Action would be named "MySuperDuperActionWhichGetsInvokedQuiteOften", exactly this Methodname would be in the property.
Can somebody explain what MVC is doing here?
The Problem is, that I of course want to fill that stuff myself, for example through an AJAX-Query. But if MVC is filling in this property all by itself, this breaks some behaviour.
I could, of course, just rename my property and it would be working, but it would still be quite interesting what's going on.
EDIT
I would understand it that my second parameter, string action, get's filled with the method-name. But why on earth would MVC bind any property/parameter that is named the same to the request-value of it?
It is problem with default model binder. It "maps" request fields to properties in your class. There is an article of MSDN describing how does it works but to simply this situation the code will be like this:
Action = Request["action"] //where of course Request["action"] equals to name of your action

Base class for common YII functions?

I know how to create a class the will allow me to instantiate it and use across my project. What I want to be able to do is have functions without instantiating classes. For example, I know how to do this:
$core = new core();
$val = $core->convertToMyNotation($anotherval);
But what I want is to be able to do this ANYWHERE in any view, class whatever:
$val = convertToMyNotation($anotherval);
Where would I place these functions in order to be able to do that?
best way to do it, create a public function in components/Controller.php
public function globalFunction(){
// do something here.
}
and access it anywhere by
$this->globalFunction();
You can define a static method as an option.
class core{
public static function convertToMyNotation($value){
//do whatever here
return $value;
}
}
Then call it like so:
$val = core::convertToMyNotation($anotherval);
This requires no instantiation of the object to use. The only restriction is that you cannot use the $this property inside a static method.
Alternately, just define a file with your functions in it and include the file at some point early like, like within the boostrap script in your public_html/index.php file.
Edit: darkheir makes some good suggestions. Include such a class in your protected/components folder, and have it extend CComponent to gain some potentially useful enhancements.
By including the class in the protected/components folder, you gain the advantage of autoloading the class, by default.
There is no definitive question of your answer, it depends a lot on what the function will be doing!
If the function is performing some things specific to a model
(getting the last users, ...) this has to be in the User model as
Willem Renzema described:
class theModelClass {
public static function convertToMyNotation($value){
//do whatever here
return $value;
}
}
And you'll call it like
$val = theModelClass::convertToMyNotation($anotherval);
If the function is handling user inputs (sanitizing he inputs,
checking the values, ...) then it has to go to the controller and
you'll use Hemc solution:
Create a public function in components/Controller.php
public function globalFunction(){
// do something here.
}
and access it anywhere by
$this->globalFunction();
If the function is an Helper: performing some actions that do not
depend on models or user inoput then you can create a new class that
you'll put in your component directory:
class core extends CComponent{
public static function convertToMyNotation($value){
//do whatever here
return $value;
}
}
And
$val = core::convertToMyNotation($anotherval);
Actually, I think you're looking for this answer instead:
http://www.yiiframework.com/wiki/31/use-shortcut-functions-to-reduce-typing/
In essence, in your entry script, before you load up Yii, include a global functions file:
require('path/to/globals.php');
Then, any function defined in that file can be used as a shortcut. Be careful, but enjoy the power! :-)
Create something like
Class Core extends CApplicationComponent{
public function doSomething(){}
}
and in config main.php
'components'=>array(
'core'=>array(
'class' => 'Core'
),
),
and now you can call whenever you want
Yii::app()->core->doSomething();

Connecting data to a GUI - OOP

I have an application with several graphs and tables on it.
I worked fast and just made classes like Graph and Table that each contained a request object (pseudo-code):
class Graph {
private request;
public function setDateRange(dateRange) {
request.setDateRange(dateRange);
}
public function refresh() {
request.getData(function() {
//refresh the display
});
}
}
Upon a GUI event (say, someone changes the date range dropdown), I'd just call the setters on the Graph instance and then refresh it. Well, when I added other GUI elements like tables and whatnot, they all basically had similar methods (setDateRange and other things common to the request).
What are some more elegant OOP ways of doing this?
The application is very simple and I don't want to over-architect it, but I also don't want to have a bunch of classes with basically the same methods that are just routing to a request object. I also don't want to set up each GUI class as inheriting from the request class, but I'm open to any ideas really.
As you commented the methods are identical. In that case I would suggest the following approach.
abstract class AbstractGUIElement {
protected request;
public function setDateRange(dateRange) {
request.setDateRange(dateRange);
}
abstract function refresh();
}
Refreshing would probably be element specific so I have added it as an abstract method the inheriting types have to implement.
class Graph extends AbstractGUIElement {
public function refresh() {
// Graph specific refreshing
}
}

Yii: attaching events to models

I have a User model which is bundled in a module installed on my Yii application. This module is third party and I do not want to alter its code.
I also have a Cv Model that has a BELONGS_TO relation with the User model.
My question is: How can I delete the cv when a user is deleted ?
I know that I can achieve this with on delete cascade ... on mysql. However, i do need to delete other data such as a photo, files, etc.
What I have tried
I have created a component that is preloaded on my application. This component attaches to an onAfterDelete event
class EventListener extends CComponent
{
public function init() {
Yii::import("application.modules.users.models.User");
User::model()->attachEventHandler('onAfterDelete', array($this, 'deleteUser'));
}
public function deleteUser($event)
{
// stuff here ...
}
}
However this does not work.
Any suggestions ?
This may help you.
User::model() is a singleton
$user1 = User::model();
$user2 = new User; // will be used in insert action
$user3 = User::model()->findByPk(10); // will be used in update/delete action
$user1, $user2 and $user3 are completely different objects.
You can attach events to objects, in this case you have to add events to all these 3 objects individually.
$user1->attachEventHandler(...);
$user2->attachEventHandler(...);
$user3->attachEventHandler(...);
look like Yii does not provide any way to add events at Class level.
Well, guys, I have just stumbled upon the same problem and I solved it this way:
You should use the init() of a Model, not your event listener collection class.
In my case I have devModel class:
public function init()
{
parent::init();
$this->onLicenseUpdated = array(new MEventProcessor, 'licenseUpdateHandler');
}
And the handler is licenseUpdateHandler($event) in a MEventProcessor class.
This way every time you work with model instance, it'll call init() for every object and attach the event handler to every instance of this Model.
Now any time the event (in my case onLicenseUpdated()) is invoked for the model - the handler will be called too.
You could also to use Behaviors.
1 - behaviors can listen to events : you just have to override their events() method
class MyBehavior extends Behavior {
public function events() {
return [
ActiveRecord::EVENT_BEFORE_VALIDATE => 'beforeValidate',
];
}
public function beforeValidate($event) {
// ...
}
}
2 - although it is more common to attach a behavior to a component in the component's behaviors() method, you can also attach them dynamically and keep the original code unmodified :
use app\components\MyBehavior;
// attach a behavior object
$component->attachBehavior('myBehavior1', new MyBehavior);
You will find some useful documentation here :
yii 1 : http://www.yiiframework.com/doc/api/1.1/CBehavior
yii 2 : http://www.yiiframework.com/doc-2.0/guide-concept-behaviors.html

How to assert if a method was called within another method in RhinoMocks?

I have a class that has two methods. One method needs to call the other method and in my test I want to assert that it was called.
public class Tasks : ITasks
{
public void MethodOne()
{
MethodTwo(1);
}
public int MethodTwo(int i)
{
return i + 1;
}
}
I want to mock Tasks and do something like tasks.AssertWasCalled(x => x.MethodTwo(1)). Must MethodTwo be virtual?
The concept you're looking for is partial mocks (this shows old syntax, but I don't remember the new one off the top of my head). You should read up on it. Essentially you create the mock on Tasks (not ITasks) and tell it to mock out only MethodTwo (which needs to be virtual).
However...you might want to reconsider your design. What is ITasks? What is the role? Are they different actual tasks? Is there any reason why you would want them in the same class? My understanding is that partial mocks is only included for when you need to test legacy components - I've never found a use for it.
Of course my thinking at that time was flawed. I should be mocking ITasks, not the implementation (Tasks):
ITasks tasks = MockRepository.GenerateMock<ITasks>();
tasks.AssertWasCalled(x => x.MethodTwo(Arg<int>.Is.Equal(1)));