I have this function:
/**
* #Secure(roles="IS_AUTHENTICATED_FULLY")
* #Route("/chequearFabricanteDistribuidor", name="chequearFabricanteDistribuidor", condition="request.headers.get('X-Requested-With') == 'XMLHttpRequest'")
* #Method("GET")
*/
public function chequearFabricanteAction(Request $request)
{
$em = $this->getDoctrine()->getManager();
$entities = $em->getRepository('AppBundle:FabricanteDistribuidor')->findOneBy(
array( 'nombre' => $request->query->get('fabricante')['nombre'] )
);
$response['valid'] = true;
if ($entities) {
$response['valid'] = false;
}
return new JsonResponse($response);
}
The function needs to be called from two different forms and the only different is the request var that holds the value. In the first form is: $request->query->get('fabricante')['nombre'] while in the second is $request->query->get('distribuidor')['nombre'] so I'm asking if the right way to handle this could be:
if (isset($request->query->get('fabricante')))
{
$nombre = $request->query->get('fabricante')['nombre'];
}
else
{
$nombre = $request->query->get('distribuidor')['nombre'];
}
Is this right? Exists a better one?
As Cerad posted on the responses, you could use:
$request->query->has('distribuidor')
Related
I have a collection called work-monitor where-in I have two fields namely
assignor_remarks and assignee_remarks.
so when a comment is submitted by either assignor or assignee, I want to add those comments in the respective comment filed.
I am able to save the comments in the collection, but new comments is overriding the existing one.
my code is like this:
public function actionWorkUpdate($id)
{
\Yii::$app->request->enableCsrfValidation = false;
$work = $this->modelClass::find()->where(['_id'=>$id])->one();
$work->load(Yii::$app->getRequest()->getBodyParams(), '');
$work->assignee_remarks = ["timestamp"=>date('d-m-Y h:i'),"comments"=>$work->assignee_remarks];
$work->update();
return "success";
}
how I can achieve this.
update like in the example below:
"assignee_remarks":{"comment":"test comment","commentTime":2020-04-29 12.41},
{"comment":"test comment2","commentTime":2020-04-29 12.45},
{"comment":"test comment3","commentTime":2020-04-29 12.50}
Try something like that, if I have understood you correctly.
// In Work Model
public $assignee_remarks;
public function rules()
{
return [
//...
['assignee_remarks', 'safe'] // for free load
];
}
// In controller
/**
* In bodyParams you have new comment like assignee_remarks: 'some text'
* #param $id
* #return mixed
*/
public function actionWorkUpdate($id)
{
\Yii::$app->request->enableCsrfValidation = false;
$work = $this->modelClass::find()->where(['_id' => $id])->one();
$currentComments = $work->assignee_remarks ?? [];
$work->load(Yii::$app->getRequest()->getBodyParams(), '');
$currentComments[] = ["commentTime" => date('d-m-Y h:i'), "comment" => $work->assignee_remarks];
$work->assignee_remarks = $currentComments;
$result = $work->update();
if ($result === false) {
// validation error
} else {
return $result > 0 ? 'success' : 'fail';
}
}
I am using FOSElasticaBundle and Symfony. I have a method to return some results merged from two types of objects:
public function getMergedResults($query)
{
//See https://github.com/FriendsOfSymfony/FOSElasticaBundle/blob/master/doc/cookbook/multi-type-search.md
$indexManager = $this->get('fos_elastica.index_manager');
$transformer = $this->get('app.elastica_to_model.transformer.snapshot');
/* #var \Elastica\Search $search */
$search = $indexManager->getIndex('app')->createSearch();
$search->addType('snapshot');
$search->addType('traffic_company');
$search->setQuery($query);
$resultSet = $search->search();
$transformer = $this->get('fos_elastica.elastica_to_model_transformer.collection.app');
$resultSet = $transformer->transform($resultSet->getResults());
return $resultSet;
}
... which works well. Now I want to add a filter that was left to me by a previous developer:
protected function addSiteFilter(Query\BoolQuery $boolFilter, SiteInterface $site = null)
{
if ($site) {
$termFilter = new Query\Term(array('site' => array('value' => $site->getId())));
$boolFilter->addMust(array(
$termFilter
));
}
}
... but I'm not sure how to glue these two pieces together. What code can I add to the first function so that it integrates the second one?
I'll provide an example, If it wouldn't be so clear for you, ping me.
/**
* #param string $ownerId
* #return Query
*/
public function getByOwnerId(string $ownerId): Query
{
$terms = new Terms('ownerId', [$ownerId]);
$boolQuery = (new BoolQuery())->addMust($terms);
return (new Query())->setQuery($boolQuery);
}
Actually,
as you see below code,
in model two functions are calling
$this->sendMailtoTutor(),$this->sendMailtoLearner()
i want to check a condition in model that if that condition will true then only these both function will call otherwise not. Is there any way to pass attributes or variable so that i can check condition in aftersave().
my code is as below
in controller
public function actionBooking()
{
$booking_temp = new BookingTemp();
$this->performAjaxValidation($booking_temp);
if (Yii::app()->request->isPostRequest && Yii::app()->request->getPost('BookingTemp'))
{
$booking_temp->attributes = Yii::app()->request->getPost('BookingTemp');
//echo '<pre>';print_r($booking_temp->attributes);exit;
if ($booking_temp->validate())
{
$extra_price = 0;
$post_data = Yii::app()->request->getPost('BookingTemp');
$cam = Cam::model()->findByPk($post_data['temp_cam_id']);
$data = array();
$data = $post_data;
$data['temp_book_user_id'] = Yii::app()->user->id;
$data['temp_book_cam_price'] = $cam->cam_price;
$data['temp_book_duration'] = $cam->cam_duration;
if ($post_data['temp_book_session'] == 2) {
$data['temp_book_cam_price'] = 2 * $cam->cam_price;
$data['temp_book_duration'] = 2 * $cam->cam_duration;
}
if ($post_data['temp_book_is_extra'] == "Y") {
$extra_price = $cam->camExtras->extra_price;
$data['temp_book_extra_price'] = $extra_price;
}
$price_calculation = CamBooking::price_calculation(Yii::app()->user->country_id, $data['temp_book_cam_price'], $extra_price);
$data['temp_book_processing_fees'] = $price_calculation['processing_fees'];
$data['temp_book_service_tax'] = $price_calculation['service_tax'];
$data['temp_book_total_price'] = $price_calculation['total_price'];
$booking_temp->temp_value = serialize($data);
$booking_temp->user_id = Yii::app()->user->id;
$booking_temp->tutor_id = $cam->tutor_id;
$booking_temp_variable = 'check_aftersave';
$booking_temp->save(false, $booking_temp_variable);
//$booking_temp->saveAttributes(array('tutor_id', 'user_id', 'temp_value'));
$created_at = Yii::app()->localtime->fromUTC($booking_temp->created_at);
$created_at_time = strtotime($created_at);
$end_time = $created_at_time + (60 * 3); // 3 min greater from created
$end_time_format = date("Y/m/d H:i:s", $end_time);
echo json_encode(array(
'status' => 'success',
'temp_guid' => $booking_temp->temp_guid,
'end_time_format' => $end_time_format,
), JSON_UNESCAPED_SLASHES);
Yii::app()->end();
} else {
$error = CActiveForm::validate($booking_temp);
if ($error != '[]')
echo $error;
Yii::app()->end();
}
}
}
in model
protected function afterSave()
{
if ($this->isNewRecord)
{
$this->sendMailtoTutor();
$this->sendMailtoLearner();
if ($this->is_message == 'Y' && !empty($this->book_message))
{
Message::insertMessage($this->book_message, $this->book_user_id, $this->cam->tutor_id, $this->cam_id);
}
$user_profile_link = CHtml::link($this->bookUser->fullname, array("/site/user/profile", "slug" => $this->bookUser->slug));
$cam_link = CHtml::link($this->cam->cam_title, array("/site/cam/view", "slug" => $this->cam->slug));
$message = "You have a new booking from {$user_profile_link} for your {$cam_link}";
Notification::insertNotification($this->cam->tutor_id, $message, 'book', $this->book_id);
}
return parent::afterSave();
}
How can I perform this?
Hi See if you want to do it in the afterSave() of BookingTemp Model;. Then you can define a variable in that model like
like
class BookingTemp extends CActiveRecord
{
public $booking_temp_variable;
............
}
now assign this variable before saving your model in actionBooking();
as
$booking_temp->booking_temp_variable = 'check_aftersave';
$booking_temp->save(false);// no need to pass a varible
now in your aftersave function you can easily get it like
protected function afterSave()
{
if ($this->isNewRecord)
{
$this->booking_temp_variable; // this has your value
}
return parent::afterSave();
}
Don't forget to keep it in rules as safe
public function rules(){
// your rules
array('booking_temp_variable','safe');
}
What exacly you want to do?
At first you have to know, that when you are calling save() method and u pass there two args - false and, $booking_temp_variable . The first arg says that you do not run validation, the second one is (should be) array of attributes.
http://www.yiiframework.com/doc/api/1.1/CActiveRecord#save-detail
I want to create a webservice to which I submit a form, and in case of errors, returns a JSON encoded list that tells me which field is wrong.
currently I only get a list of error messages but not an html id or a name of the fields with errors
here's my current code
public function saveAction(Request $request)
{
$em = $this->getDoctrine()->getManager();
$form = $this->createForm(new TaskType(), new Task());
$form->handleRequest($request);
$task = $form->getData();
if ($form->isValid()) {
$em->persist($task);
$em->flush();
$array = array( 'status' => 201, 'msg' => 'Task Created');
} else {
$errors = $form->getErrors(true, true);
$errorCollection = array();
foreach($errors as $error){
$errorCollection[] = $error->getMessage();
}
$array = array( 'status' => 400, 'errorMsg' => 'Bad Request', 'errorReport' => $errorCollection); // data to return via JSON
}
$response = new Response( json_encode( $array ) );
$response->headers->set( 'Content-Type', 'application/json' );
return $response;
}
this will give me a response like
{
"status":400,
"errorMsg":"Bad Request",
"errorReport":{
"Task cannot be blank",
"Task date needs to be within the month"
}
}
but what I really want is something like
{
"status":400,
"errorMsg":"Bad Request",
"errorReport":{
"taskfield" : "Task cannot be blank",
"taskdatefield" : "Task date needs to be within the month"
}
}
How can I achieve that?
I am using this, it works quiet well:
/**
* List all errors of a given bound form.
*
* #param Form $form
*
* #return array
*/
protected function getFormErrors(Form $form)
{
$errors = array();
// Global
foreach ($form->getErrors() as $error) {
$errors[$form->getName()][] = $error->getMessage();
}
// Fields
foreach ($form as $child /** #var Form $child */) {
if (!$child->isValid()) {
foreach ($child->getErrors() as $error) {
$errors[$child->getName()][] = $error->getMessage();
}
}
}
return $errors;
}
I've finally found the solution to this problem here, it only needed a small fix to comply to latest symfony changes and it worked like a charm:
The fix consists in replacing line 33
if (count($child->getIterator()) > 0) {
with
if (count($child->getIterator()) > 0 && ($child instanceof \Symfony\Component\Form\Form)) {
because, with the introduction in symfony of Form\Button, a type mismatch will occur in serialize function which is expecting always an instance of Form\Form.
You can register it as a service:
services:
form_serializer:
class: Wooshii\SiteBundle\FormErrorsSerializer
and then use it as the author suggest:
$errors = $this->get('form_serializer')->serializeFormErrors($form, true, true);
This does the trick for me
$errors = [];
foreach ($form->getErrors(true, true) as $formError) {
$errors[] = $formError->getMessage();
}
PHP has associative arrays, meanwhile JS has 2 different data structures : object and arrays.
The JSON you want to obtain is not legal and should be :
{
"status":400,
"errorMsg":"Bad Request",
"errorReport": {
"taskfield" : "Task cannot be blank",
"taskdatefield" : "Task date needs to be within the month"
}
}
So you may want to do something like this to build your collection :
$errorCollection = array();
foreach($errors as $error){
$errorCollection[$error->getId()] = $error->getMessage();
}
(assuming the getId() method exist on $error objects)
By reading other people's answers I ended up improving it to my needs. I use it in Symfony 3.4.
To be used in a controller like this:
$formErrors = FormUtils::getErrorMessages($form);
return new JsonResponse([
'formErrors' => $formErrors,
]);
With this code in a separate Utils class
<?php
namespace MyBundle\Utils;
use Symfony\Component\Form\FormError;
use Symfony\Component\Form\FormInterface;
class FormUtils
{
/**
* #param FormInterface $form
* #return array
*/
public static function getErrorMessages(FormInterface $form)
{
$formName = $form->getName();
$errors = [];
/** #var FormError $formError */
foreach ($form->getErrors(true, true) as $formError) {
$name = '';
$thisField = $formError->getOrigin()->getName();
$origin = $formError->getOrigin();
while ($origin = $origin->getParent()) {
if ($formName !== $origin->getName()) {
$name = $origin->getName() . '_' . $name;
}
}
$fieldName = $formName . '_' . $name . $thisField;
/**
* One field can have multiple errors
*/
if (!in_array($fieldName, $errors)) {
$errors[$fieldName] = [];
}
$errors[$fieldName][] = $formError->getMessage();
}
return $errors;
}
}
This will do the trick. This static method runs recursively through the Symfony\Component\Form\FormErrorIterator delivered by calling $form->getErrors(true, false).
<?php
namespace App\Utils;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormError;
use Symfony\Component\Form\FormErrorIterator;
class FormUtils
{
public static function generateErrorsArrayFromForm(FormInterface $form)
{
$result = [];
foreach ($form->getErrors(true, false) as $formError) {
if ($formError instanceof FormError) {
$result[$formError->getOrigin()->getName()] = $formError->getMessage();
} elseif ($formError instanceof FormErrorIterator) {
$result[$formError->getForm()->getName()] = self::generateErrorsArrayFromForm($formError->getForm());
}
}
return $result;
}
}
Here is the result :
{
"houseworkSection": "All the data of the housework section must be set since the section has been requested.",
"foodSection": {
"requested": {
"requested": "This value is not valid."
}
}
}
I'm using Zend-Framework 1.9.5 to make a web-application, But it's Url_Helper was quite tricky to me in the matter of parameter reset!, I know it's a good feature (parameter preserving) but in most cases I don't need it!.
So I'm thinking of overriding the default Router to force it loosing parameters Unless I ask for it or maybe specifying a certain parameters that it keeps like (lang, or something like that).
Also I want to make it the default router so I don't have to edit my Controllers, Views to get that done!
Any suggestions?
Update:
I spent the whole morning trying to write my url helper Admin_View_Helper_Xurl, But I couldn't do anything that solves the problem:
<?php
class Admin_View_Helper_Xurl extends Zend_View_Helper_Abstract
{
public function xurl(array $urlOptions = array(), $name = 'default', $reset = false, $encode = true)
{
$router = Zend_Controller_Front::getInstance()->getRouter();
$wanted_params = array('module', 'controller', 'action', 'lang', 'page', 'search');
$route = $router->getCurrentRoute();
$something = anyWayToGetThatObjectOrClass();
$params = $something->getParams();
foreach($params as $key => $val) {
if (!in_array($key, $wanted_params)) {
$params[$key] = null; // OR uset($params[$key]);
}
}
$something->clearParams();
$something->setParams($params);
return $router->assemble($urlOptions, $name, $reset, $encode);
}
}
I tried to get current URL parameters and filter them and clear the current parameters and pass my filtered ones but I couldn't do anything that does it without hard-code editing one Zend_Framework code :(.
Thanks
When generating a link a view, you can ask the helper to get rid of all aparamters with a simple boolean :
<?php echo $this->url(array('controller' => 'index', action => 'action'), 'default', true); ?>
The last parameter tells whether to reset parameters or not.
I came up with this solution. It took 7 hours to be functional.
class Zend_View_Helper_Xurl extends Zend_View_Helper_Abstract
{
const RESET_ALL = 'all';
const RESET_CUSTOM = 'normal';
const RESET_NON_MVC = 'mvc';
const RESET_NONE = 'none';
protected $_wantedParams = array('module', 'controller', 'action', 'lang', 'page', 'search');
protected $_router;
/**
* Generates an url given the name of a route.
*
* #access public
*
* #param array $urlOptions Options passed to the assemble method of the Route object.
* #param mixed $name The name of a Route to use. If null it will use the current Route
* #param bool $reset Whether or not to reset the route defaults with those provided
* #return string Url for the link href attribute.
*/
public function __construct()
{
$router = Zend_Controller_Front::getInstance()->getRouter();
$this->_router = clone $router;
}
public function xurl(array $urlOptions = array(), $reset = 'mvc', $encode = true)
{
$urlOptions = $this->_getFilteredParams($urlOptions, $reset);
return $this->_router->assemble($urlOptions, $name, true, $encode);
}
protected function _getFilteredParams($data = array(), $level)
{
// $filteredValues = array();
$request = Zend_Controller_Front::getInstance()->getRequest();
$filteredValues = $request->getUserParams();
$$filteredValues['module'] = $request->getModuleName();
$$filteredValues['controller'] = $request->getControllerName();
$$filteredValues['action'] = $request->getActionName();
switch ($level) {
case self::RESET_ALL:
$filteredValues['module'] = null;
$filteredValues['controller'] = null;
$filteredValues['action'] = null;
// break omitted intentionally
case self::RESET_NON_MVC:
$filteredValues['page'] = null;
$filteredValues['lang'] = null;
$filteredValues['search'] = null;
// break omitted intentionally
case self::RESET_CUSTOM:
foreach ($filteredValues as $key=>$val) {
if (!in_array($key, $this->_wantedParams)) {
$filteredValues[$key] = null;
}
}
break;
case self::RESET_NONE:
break;
default:
throw new RuntimeException('Unsuppoted Xurl URL helper reset level.');
break;
}
foreach ($filteredValues as $key => $val) {
if (!array_key_exists($key, $data)) {
$data[$key] = $val;
}
}
return $data;
}
}
Clearly it's a View Helper class, may be not the best solution but it works fine with me for now.