How to retrieve a form from processFrom into an other action? - php

I want to retrieve data from my first form into my function executeAddDomaines to use these into a second form called by this function but when i give $form in parameters to this function i have this error :
Catchable fatal error: Argument 2 passed to domaineActions::executeAddDomaines() must be an instance of sfForm, none given, called in /home/webs/extranet100p100.net/htdocs/lib/vendor/symfony/lib/action/sfActions.class.php on line 60 and defined in /home/webs/extranet100p100.net/htdocs/apps/backend/modules/domaine/actions/actions.class.php on line 206
This is my code:
protected function processForm(sfWebRequest $request, sfForm $form)
{
$name = $form->getName();
$form->bind($request->getParameter($name), $request->getFiles($name));
if($form->isValid())
{
if($form->isNew())
{
$this->executeAddDomaines($request, $form);
$this->redirect('#add_domaines');
}
[...]
}
public function executeAddDomaines(sfWebRequest $request, sfForm $form)
{
$name = $form->getName();
$params = $request->getParameter($name);
$this->list_domaines = $params;
$this->form = new AddDomainesForm();
$this->setTemplate('listDomaines');
}
So how i can do it ?
Thank you :)

You can try to save the form data in session and then get it in the 2nd action.
Try this (i didn't test):
protected function processForm(sfWebRequest $request, sfForm $form)
{
$name = $form->getName();
$form->bind($request->getParameter($name), $request->getFiles($name));
if($form->isValid())
{
if($form->isNew())
{
# Replaced
$request->setAttribute("form", $form);
$this->redirect('#add_domaines');
}
[...]
}
public function executeAddDomaines(sfWebRequest $request)
{
# Added
$form = $request->getAttribute("form");
$name = $form->getName();
$params = $request->getParameter($name);
$this->list_domaines = $params;
$this->form = new AddDomainesForm();
$this->setTemplate('listDomaines');
}
After use it, you can clean the attribute form from the request

Related

PHP class has two methods with different parameters, how to take advantage of the constructor?

I want to make a class let's say it's called validation, it has two functions, either registrationVal or loginVal.
I want to pass data from two different pages that will use the same class. I want to initialize the variables in a constructor so it looks cleaner... how can I do this?
How can I call the constructor from one page when it doesn't have all the variables to be passed to the constructor?
For example:
registration page
$obj = new validation($password, $password2, $email, $phone);
$obj->registrationVal();
login page
$obj = new validation($email, $password);
$obj->loginVal();
You can make something like this. It's not the best code - but for start is not bad.
<?php
class Validator
{
private array $params;
private array $validated = [];
private array $errors = [];
public function __construct(array $params)
{
$this->params = $params;
$this->validate();
}
private function validate(): void
{
foreach ($this->params as $field => $param){
$validationMethod = 'validate' . ucfirst(strtolower($field));
if(! method_exists($this, $validationMethod)){
continue;
}
if($error = $this->{$validationMethod}($param)){
$this->errors[$field] = $error;
}else{
$this->validated[$field] = $param;
}
}
}
public function validateOrFail(): void
{
if($this->hasErrors()){
throw new ValidationException($this->getErrors());
}
}
public function validated(): array
{
return $this->validated;
}
private function validateLogin($value): ?string
{
//validation logic - return null on success or error string
return $validation_result;
}
public function __get($name)
{
return $this->params[$name] ?? null;
}
public function getErrors(): array
{
return $this->errors;
}
public function hasErrors(): bool
{
return count($this->errors) > 0;
}
}
You must write validation methods such validateLogin() for login field or validatePassword() for password field.
How it working:
$params = [
'login' => 'login',
'password' => 'password'
...
];
$validator = new Validator($params);
//it will throw exception when validation failing.
$validator->validateOrFail();
//or you can manually working with errors
if($validator->hasErrors()){
...
}
$password = $validator->password;
//or you can get only validated fields
$params = $validator->validated();

How to use SplObserver for Hook system?

I code a class for Hook system. But this is outdated. I want to use splObserver to code it.
<?php
class Event
{
private static $filters = [];
private static $actions = [];
public static function addAction($name, $callback, $priority = 10)
{
if (! isset(static::$actions[$name])) {
static::$actions[$name] = [];
}
static::$actions[$name][] = [
'priority' => (int)$priority,
'callback' => $callback,
];
}
public function doAction($name, ...$args)
{
$actions = isset(static::$actions[$name]) ? static::$actions[$name] : false;
if (! $actions) {
return;
}
// sort actions by priority
$sortArr = array_map(function ($action) {
return $action['priority'];
}, $actions);
\array_multisort($sortArr, $actions);
foreach ($actions as $action) {
\call_user_func_array($action['callback'], $args);
}
}
}
Event::addAction('action1', function(){
echo 'balabala1';
});
Event::addAction('action1', function(){
echo 'balabala2';
});
Event::doAction('action1');
Output: balabala1 balabala2
It works good.
I want to use SplObserver to re-code it and try to code but no idea.
I don't really know whether this implementation could be useful in a real life application or not but, for the sake of answering your question, here we go...
Let's imagine we have a User class that we'd like to hook with our custom functions.
First, we create a reusable trait containing the Subject logic, capable of managing "event names" to whom we can hook our actions.
trait SubjectTrait {
private $observers = [];
// this is not a real __construct() (we will call it later)
public function construct()
{
$this->observers["all"] = [];
}
private function initObserversGroup(string $name = "all")
{
if (!isset($this->observers[$name])) {
$this->observers[$name] = [];
}
}
private function getObservers(string $name = "all")
{
$this->initObserversGroup($name);
$group = $this->observers[$name];
$all = $this->observers["all"];
return array_merge($group, $all);
}
public function attach(\SplObserver $observer, string $name = "all")
{
$this->initObserversGroup($name);
$this->observers[$name][] = $observer;
}
public function detach(\SplObserver $observer, string $name = "all")
{
foreach ($this->getObservers($name) as $key => $o) {
if ($o === $observer) {
unset($this->observers[$name][$key]);
}
}
}
public function notify(string $name = "all", $data = null)
{
foreach ($this->getObservers($name) as $observer) {
$observer->update($this, $name, $data);
}
}
}
Next, we use the trait in our SplSubject User class:
class User implements \SplSubject
{
// It's necessary to alias construct() because it
// would conflict with other methods.
use SubjectTrait {
SubjectTrait::construct as protected constructSubject;
}
public function __construct()
{
$this->constructSubject();
}
public function create()
{
// User creation code...
$this->notify("User:created");
}
public function update()
{
// User update code...
$this->notify("User:updated");
}
public function delete()
{
// User deletion code...
$this->notify("User:deleted");
}
}
The last step is to implement a reusable SplObserver. This observer is able to bind himself to a Closure (anonymous function).
class MyObserver implements SplObserver
{
protected $closure;
public function __construct(Closure $closure)
{
$this->closure = $closure->bindTo($this, $this);
}
public function update(SplSubject $subject, $name = null, $data = null)
{
$closure = $this->closure;
$closure($subject, $name, $data);
}
}
Now, the test:
$user = new User;
// our custom functions (Closures)
$function1 = function(SplSubject $subject, $name, $data) {
echo $name . ": function1\n"; // we could also use $data here
};
$function2 = function(SplSubject $subject, $name, $data) {
echo $name . ": function2\n";
};
// subscribe the first function to all events
$user->attach(new MyObserver($function1), 'all');
// subscribe the second function to user creations only
$user->attach(new MyObserver($function2), 'User:created');
// run a couple of methods to see what happens
$user->create();
$user->update();
The output will be:
User:created: function2
User:created: function1
User:updated: function1
NOTE: we could use SplObjectStorage instead of an array, to store observers in the trait.

ZF2 bind form data

I am trying to bind the form data before I set the edited form data as I don't want to lose values which hasn't be changed. It actually throws me an error and the ZF2 website doesn't provide me a good working example. I am stuck and I don't want to wrote a dirty workaround, someone? :)
I've created a model as follow:
namespace Application\Model;
class Advertisement {
public $id;
public $name;
public $code;
public $banner;
public $fileupload;
public function exchangeArray($data)
{
$this->id = isset($data['id']) ? $data['id'] : null;
$this->name = isset($data['name']) ? $data['name'] : null;
$this->code = isset($data['code']) ? $data['code'] : null;
$this->banner = isset($data['banner']) ? $data['banner'] : '';
$this->fileupload = isset($data['fileupload']) ? $data['fileupload'] : '';
}
public function exchangeJsonToPhpArray($json)
{
}
public function getArrayCopy()
{
return get_object_vars($this);
}
}
My Controller;
public function editAction()
{
# Get Request and Params
$request = $this->getRequest();
$language = $this->params('language');
$id = $this->params('id');
# Get advertisement data
$oAdvertisement = new Advertisement();
if (!$oAdvertisement = $this->getAdvertisementTable()->selectAdvertisementToEdit(array('id' => $id)))
return $this->redirect()->toRoute('admin/advertisement');
# Advertisement form
$sm = $this->getServiceLocator();
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$form = new AdvertisementForm($dbAdapter, $this->params('language'));
$form->bind($oAdvertisement);
# Post request
$request = $this->getRequest();
if ($request->isPost()) {
# Set post data
$post = array_merge_recursive($this->request->getPost()->toArray(), $this->request->getFiles()->toArray());
$form->setData($post);
# Validate form
if ($form->isValid()) {
# Get form data
$formData = $form->getData();
Debug::dump($form->getData());
# Get service config
$serviceLocator = $this->getServiceLocator();
$config = $serviceLocator->get('config');
$sBannerName = $config['banner_upload_path'] . '/' . md5(mt_rand()) .'.jpg';
# Insert into database
$oAdvertisement->exchangeArray($formData);
# Validate and rename image upload
//.. image upload
Debug::dump($oAdvertisement);
exit;
# Update database record
$this->getAdvertisementTable()->updateAdvertisement($oAdvertisement, $id);
// success..
} else {
// false..
}
}
# Return view model
return new ViewModel(array(
'form' => $form,
));
}
Error;
Fatal error: Cannot use object of type Application\Model\Advertisement as array in ..../module/Application/src/Application/Model/Advertisement.php on line 29
In exchangeArray () method try to test the type of the parameter $ data.
Personally, I put systematically:
if ($data instanceof IteratorAggregate) {
$data = iterator_to_array($data->getIterator(), true);
} elseif ($data instanceof Iterator) {
$data = iterator_to_array($data, true);
} elseif (! is_array($data)) {
throw new Exception(_('Data provided is not an array, nor does it implement Iterator or IteratorAggregate'));
}

PHP - Calling a Class Method

I've been handed a PHP class, and I'm not interested in fully restructuring it. (it works!)
But I'd like to add a slight modification inside a few methods.
Here is one of the many methods inside the class:
<?php
class SomeFunClass {
public function getAccountInfo()
{
$request = $this->prepareRequest('get_account_info');
$response = $this->execute($request);
return $response;
}
}
?>
The return $response is a string value.
I've come to a point that I need to return the $request string, which happens to be a json string.
The prepareRequest() method always returns a json string, which is then passed to the exec() method, which simply sends the data via cURL to a domain.
I'd like to extract the $request string (when I call the getAccountInfo() method), for later review.
Here's what I'm doing now:
<?php
$api = new SomeFunClass();
$curlresponse = $api->getAccountInfo();
?>
Obviously, the example immediately above only gives me back what the cURL response would be.
Would be nice to call a method that lets me see what the $request looks like.
I'm open to suggestions.
Just return an array with the request and the response:
<?php
class SomeFunClass {
public function getAccountInfo()
{
$request = $this->prepareRequest('get_account_info');
$response = $this->execute($request);
return array('request' => $request, 'response' => $response);
}
}
?>
You can modify those methods to store the last request into an attribute of the current class :
<?php
class SomeFunClass {
$last_request;
...
public function getAccountInfo()
{
$request = $this->prepareRequest('get_account_info');
$last_request = request;
$response = $this->execute($request);
return $response;
}
public function getLastRequest()
{
return $this -> last_request;
}
}
?>
Or, better, if prepareRequest is a method of yours, then just modify this one to store the last request.
You can do something like this:
<?php
class SomeFunClass {
public $request;
public $response;
public function getAccountInfo()
{
$this->request = $this->prepareRequest('get_account_info');
$this->response = $this->execute($this->request);
return $this->response;
}
}
?>
Now, you can do something like this:
<?php
$api = new SomeFunClass();
$curlresponse = $api->getAccountInfo();
$request = $api->request;
?>
Ideally, you can do implement your class like this to take actual advantage of OOP (so that these instance variables request and response are auto-set for all your methods):
<?php
class SomeFunClass {
public $request;
public $response;
public function getAccountInfo()
{
$this->prepareRequest('get_account_info');
return $this->execute();
}
public function anotherMethod()
{
$this->prepareRequest('another_method', 'some', 'args');
return $this->execute();
}
public function prepareRequest()
{
$args = func_get_args(); // contains your arguments
$method = array_shift($args); // contains your method name
...
...
$this->request = $return // value returned by this method
}
public function execute()
{
$request = $this->request;
...
...
$this->response = $return // value returned by this method
}
}
?>
You could also do this:
<?php
class SomeFunClass {
public function reviewRequest($request)
{
return $this->prepareRequest($request);
}
}
And then:
<?php
$api = new SomeFunClass();
$request = $api->reviewRequest('get_account_info');

Zend_Form not displaying data

Here is my code:
<?php
class IndexController extends Zend_Controller_Action
{
public function indexAction()
{
$this->_forward('search');
}
public function searchAction()
{
if($this->getRequest()->isGet())
{
$form = $this->getForm();
$value = $form->getValue('search');
echo "'", $value, "'"; // <-- prints ''
}
$this->view->form = $this->getForm();
}
public function getForm()
{
$form = new Zend_Form();
$form->setAction('/index/search')
->setMethod('get');
$search = $form->createElement('text', 'search');
$search->addFilter('StripTags')
->addFilter('StringTrim');
// Add elements to form:
$form->addElement($search)
->addElement('submit', 'submit', array('label' => 'Search'));
return $form;
}
}
In searchAction() $value is always blank even after I submit the form and I see the data in the URL. What is the problem?
EDIT: I fixed getValue() to getValues() but it still isn't working.
Before you are able to use ->getValue(); you have to validate the form.
public function searchAction()
{
if($this->getRequest()->isGet())
{
$form = $this->getForm();
if ($form->isValid()) {
$value = $form->getValue('search');
echo "'", $value, "'"; // <-- prints ''
} else {
// what ever
}
}
$this->view->form = $this->getForm();
}
You need to pass $this->_request->getParams() to $form->isValid(), otherwise the form will not have any values to work with.
The function you want is getValue, not getValues.
A subtle difference but they do two totally different things.

Categories