custom Yii validation class - yii

I've created this custom class to validate some numbers on my website.
class EPriceValidator extends CValidator
{
public $number_type;
/*
* Regular Expressions for numbers
*/
private $default_pattern = '/[^0-9,.]/';
private $price_pattern = '/[^0-9,.]/';
/*
* Default error messages
*/
private $default_msg = '{attribute} is an invalid number.';
private $price_msg = '{attribute} is an invalid price.';
/**
* Validates the attribute of the object.
* If there is any error, the error message is added to the object.
* #param CModel $object the object being validated
* #param string $attribute the attribute being validated
*/
protected function validateAttribute($object,$attribute)
{
// check the strength parameter used in the validation rule of our model
if ($this->number_type == 'price')
{
$pattern = $this->price_pattern;
$error_message = $this->price_msg;
}
else {
$pattern = $this->default_pattern;
$error_message = $this->default_msg;
}
// extract the attribute value from it's model object
$value=$object->$attribute;
if(!preg_match($pattern, $value))
{
$this->addError($object,$attribute, $error_message);
}
}
/**
* Implementing Client Validation
*
* Returns the JavaScript needed for performing client-side validation.
* #param CModel $object the data object being validated
* #param string $attribute the name of the attribute to be validated.
* #return string the client-side validation script.
* #see CActiveForm::enableClientValidation
*/
public function clientValidateAttribute($object,$attribute)
{
// check the strength parameter used in the validation rule of our model
if ($this->number_type == 'price')
{
$pattern = $this->price_pattern;
$error_message = $this->price_msg;
}
else
{
$pattern = $this->default_pattern;
$error_message = $this->default_msg;
}
$condition="value.match(".$pattern.")";
return "
if(".$condition.") {
messages.push(".CJSON::encode($error_message).");
}
";
}
}
it works fine. but how do i make it display the correct field name of the error? right now when there is an error detected on client side, the clientValidateAttribute() displays
{attribute} is an invalid number.
instead of
Total orders is an invalid number.
where Total orders is the input field that is in valid.
Any idea how to fix this?

I rechecked this in the Yii documentation, and it seems you have to add an array with parameters to replace the placeholders in your string. But if you only use the default placeholder for the attribute, it should work by default.
Do you have only the problem on client validation? Because I now checked also the Yii code, and it seems that your code is right, and should work (at least the server validation). But in the client validation you just pass the error mesasage to JSON without any processing, so the {attribute} is not replaces anywhere.
Try to add this to youc client validation before the return
$params['{attribute}']=$object->getAttributeLabel($attribute);
$error_message = strtr($error_message,$params));

Related

error when seeding data into a database in laravel 8

am getting this error when seeding data into my database. apparently the I have 2 models bookings and bookingstatus model.the bookingstatus seeder is working well and is seeding the status very well but when it comes to the bookings the data is unable to seed.this is the error that pops up
ErrorException
Undefined variable:
at F:\Main Server\htdocs\voskillproject\database\seeders\BookingsSeeder.php:73
69▕ 'event_details'=>'we would like to book you for a wedding'
70▕
71▕ ]);
72▕ $Approved->bookingstatus()->attach($Approvedstatus);
➜ 73▕ $Cancelled->bookingstatus()->attach($$Cancelledstatus);
74▕ $DepositPaid->bookingstatus()->attach($DepositPaidstatus);
75▕ $Published->bookingstatus()->attach($Publishedstatus);
76▕ }
77▕ }
1 F:\Main Server\htdocs\voskillproject\database\seeders\BookingsSeeder.php:73
Illuminate\Foundation\Bootstrap\HandleExceptions::handleError("Undefined variable: ", "F:\Main Server\htdocs\voskillproject\database\seeders\BookingsSeeder.php")
2 F:\Main Server\htdocs\voskillproject\vendor\laravel\framework\src\Illuminate\Container\BoundMethod.php:36
Database\Seeders\BookingsSeeder::run()
this is my BookingsFactory
<?php
namespace Database\Factories;
use App\Models\Bookings;
use Illuminate\Database\Eloquent\Factories\Factory;
class BookingsFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* #var string
*/
protected $model = Bookings::class;
/**
* Define the model's default state.
*
* #return array
*/
public function definition()
{
return [
'is_booking'=>0,
'full_name'=>$this->faker->unique()->name,
'location'=>$this->faker->location,
'phone'=>$this->faker->number,
'is_booking'=>3,
'email'=>$this->faker->safeEmail,
'date'=>$this->faker->date,
'event_id'=>$this->faker->event_id,
'event_details'=>$this->faker->paragraph,
];
}
}
this is my database seeder
<?php
namespace Database\Seeders;
use App\Models\Role;
use App\Models\Bookingstatus;
use Illuminate\Database\Seeder;
use Database\Seeders\RoleSeeder;
use Database\Seeders\Userseeder;
use Database\Seeders\BookingsSeeder;
use Database\Seeders\BookingstatusSeeder;
class DatabaseSeeder extends Seeder
{
/**
* Seed the application's database.
*
* #return void
*/
public function run()
{
$this->call([
BookingsSeeder::class,
BookingstatusSeeder::class,
]);
\App\Models\Bookingstatus::factory()->hasbookings(10)->create();
}
}
i have not understood where ie gone wrong in the code
i figure out where the issue was
1.first on the bookings factory i have to change the faker details to this
return [
'is_booking'=>0,
'full_name'=>$this->faker->unique()->name,
'location'=>$this->faker->address,
'phone'=>$this->faker->numerify('###-###-####'),
'is_booking'=>3,
'email'=>$this->faker->safeEmail,
'date'=>$this->faker->unique()->dateTime()->format('Y/m/d'),
'event_id'=>$this->faker->randomDigit(),
'event_details'=>$this->faker->paragraphs(2, true),
];
also i should have imported this code at the top of the bookingstatus factory
use Illuminate\Support\Str;

TYPO3 extension Model conflict with f:form.upload

For an own extension, I want o use the viewhelper f:form.upload
to retrieve the upload parameters I have to define the property for this viewhelper as an array. These work fine to get the name, type, tmp_name, error, and size parameters.
In the Domain Model, I read the parameters and save the uploaded file and store the file name inside the database. That works fine! Here the part of the Domain Modell for the variable iFile:
/**
* iFile
*
* #var array
* #TYPO3\CMS\Extbase\Annotation\ORM\Cascade("remove")
*/
protected $iFile = [];
/**
* Returns the iFile
*
* #return string iFile
*/
public function getIFile()
{
$temp = [];
$temp['image_name'] = $this->iFile;
error_log("Get_iFile: " . var_export($temp, true), 0);
error_log("Get_iFile0: " . var_export($this, true), 0);
return $temp;
}
/**
* Sets the iFile
*
* #param string $iFile
* #return void
*/
public function setIFile($iFile)
{
if($iFile['tmp_name'] != ""){
$docRoot = $_SERVER['DOCUMENT_ROOT'].'\\' ;
if (!is_dir($docRoot)) {
mkdir($docRoot, 07777, true);
}
$date = new \DateTime();
$fName = 'fileadmin\\Radio\\crNews\\' . $date->format('Ymd') . $iFile['name'];
if(copy($iFile['tmp_name'], $docRoot . $fName) == true);
unlink($iFile['tmp_name']);
}
error_log("Set _FILES: " . var_export($iFile, true), 0);
$this->iFile = $fName;
}
But if I try to read it from the database, I don't get back the file name from the database! Only an empty array.
'iFile' =>
array (
),
The problem seems to be, due to the definition of iFile as an array.
How can I solve the problem?
Is there any possibility, to add a new variable to the Model as an array, but not to store it in the database?
So I found a workaround. I only defined iFile as an string to read and save the file name in the database and used the $_FILES post variables to retrieve the name and tmp_name of the $_FILES.
In Typo3, access the $_FILES parameters is not so easy. So I recommend to use phpinstruction error_log("Create _FILES: " . var_export($_FILES, true), 0); to find out the structure of the array.

API Platform & Symfony: what is the correct way to make a custom controller for collection operations?

As far as I understand, Api Platform deletes and updates one by one the resources of a Collection. For example, I have an Activity Entity, which has a Many-To-One relation with OpeningHours: if I want to delete or add multiples OpeningHours through an Admin Back Office, I must call a "delete" operation for each openingHour with its unique #id. As long as I have very few OpeningHours, it's quite all right : the job is done in a few seconds. But what am I supposed to do when I have thousand of them ? Just wait ?
So I've created a Custom Controller and a Custom Route - so far only for the Delete Operation ; the update operation will come after.
First Question : is this the right way to do it or have I missed something in the docs?
Here is my API configuration for the Activity Entity:
/**
* #ApiResource(
* collectionOperations={
* "get"={"normalization_context"={"groups"="activity:list"}},
* "post"={"denormalization_context"={"groups"="activity:post"}},
* },
* itemOperations={
* "get"={"normalization_context"={"groups"="activity:item"}},
* "put"={"denormalization_context"={"groups"="activity:item"}},
"delete_opening_hours"={
* "method"="DELETE",
* "path"="/admin/activity/{id}/delete_opening_hours",
* "controller"=DeleteOpeningHoursAction::class,
* "read"=false,
* },
* "delete", "patch"
* },
* attributes={"pagination_items_per_page"=10}
* )
And my Custom Controller :
/**
* Class DeleteOpeningHoursAction
* #Security("is_granted('ROLE_ADMIN')")
*/
final class DeleteOpeningHoursAction extends AbstractController
{
/**
* #Route(
* name="delete_opening_hours",
* path="/admin/activity/{id}/delete_opening_hours",
* methods={"DELETE"},
* )
*/
public function deleteHours(Activity $data):Activity
{
$em = $this->getDoctrine()->getManager();
$activity = $em->getRepository('App\Entity\Activity')->find($data);
$openingHours = $activity->getOpeningHours();
foreach ($openingHours as $hour) {
$em->remove($hour);
}
$em->flush();
$response = new Response();
$response->setStatusCode(204);
return $response;
}
}
It does the requested job: all the OpeningHours are deleted at once, but it returns a 500 Error:
Return value of App\Controller\Action\DeleteOpeningHoursAction::deleteHours() must be an instance of App\Entity\Activity, instance of Symfony\Component\HttpFoundation\Response returned
And if I return $activity instead of the response above, the error message becomes :
Return value of App\Controller\Action\DeleteOpeningHoursAction::deleteHours() must be an instance of Symfony\Component\HttpFoundation\Response, instance of App\Entity\Activity returned
So what am I doing wrong? What is the correct response for a Custom Controller?
I'm quite confused.
Thanks for any help.

Behat Pass a value from a test step

I'm trying to make assertion that the random text entered in one field appears on next page (confirmation)
I do it like this
When I fill in "edit-title" with random value of length "8"
/**
* Fills in form field with specified id|name|label|value with random string
* Example: And I fill in "bwayne" with random value of length "length"
*
* #When /^(?:|I )fill in "(?P<field>(?:[^"]|\\")*)" with random value of length "(?P<length>(?:[^"]|\\")*)"$/
*/
public function fillFieldWithRandomValue($field, $length)
{
$field = $this->fixStepArgument($field);
$value = $this->generateRandomString($length);
$this->getSession()->getPage()->fillField($field, $value);
}
Than I want to make assertion - something like this:
Then I should see text matching "<RANDOM VALUE ENTERED IN THE PREVIOUS STEP>"
is it possible?
UPDATE:
But how would it look like with setters and getters if i want to use a generateRandomString method multiple times and then get the values of this methods one after another? DO I have to make variables and functions for every test step? like this:
When I fill in "x" with random value of length "8"
And I fill in "y" with random value of length "12"
And I go to other page
Then I should see text matching "VALUE ENTERED TO X"
And I should see text matching "VALUE ENTERED TO Y"
You can create a property and set it in the previous step. And use it in the next one, but assert it if it has value.
Also it would be nice and readable to define that property with proper visibility type
/**
* #var string
*/
private randomString;
/**
* Fills in form field with specified id|name|label|value with random string
* Example: And I fill in "bwayne" with random value of length "length"
*
* #When /^(?:|I )fill in "(?P<field>(?:[^"]|\\")*)" with random value of length "(?P<length>(?:[^"]|\\")*)"$/
*/
public function fillFieldWithRandomValue($field, $length)
{
$field = $this->fixStepArgument($field);
$this->randomString = $this->generateRandomString($length);
$this->getSession()->getPage()->fillField($field, $this->randomString);
}
/**
*
* #Then /^(?:|I )should see that page contains random generated text$/
*/
public function assertPageContainsRandomGeneratedText()
{
//Assertion from phpunit
$this->assertNotNull($this->randomString);
$this->assertPageContainsText($this->randomString);
}
NOTE: Depending on your behat setup - assertion from phpunit might not work.
Since you will will call the generateRandomString method in multiple places then you should also have a method for getting this value like getRandomString like setters and getters.
My recommendation would be to have a class with related methods that handle all the data and not saving in variable in every place you will use data, generate+save and read from the same place anywhere you need.
Tip: You could be more flexible about the step definition and have a default length for the random string in case one one not provided.
High level example:
class Data
{
public static $data = array();
public static function generateRandomString($length = null, $name = null)
{
if ($name = null) {
$name = 'random';
};
if ($length = null) {
$length = 8;
};
// generate string like $string =
return self::$data[$name] = $string;
}
public static function getString($name = null)
{
if ($name = null) {
$name = 'random';
};
// exception handling
if (array_key_exists($name, self::$data) === false) {
return null;
}
return self::$data[$name];
}
}
In context:
/**
* #Then /^I fill in "x" with random value as (.*?)( and length (\d+))?$/
*/
public function iFillInWithRandomValue($selector, $name, $length = null){
$string = Data::generateRandomString($length, $name);
// fill method
}
/**
* #Then /^I should see text matching "first name"$/
*/
public function iShouldSeeTextMatching($variableName){
$string = Data::getString($variableName);
// assert/check method
}
This is high level example, you might need to do some adjustments.
If you have the validation in the same class then you can also have all these in the same class, meaning generateRandomString and getString in the same class with the steps.

Play framework select input validation

I am using Play 2.1
I made a select drop down box using the helper field constructor.
The drop down box have 3 fields, default:"choose a gender", Male, and Female.
How do I ensure that the user choose one of male or female, and not the default value? (A required drop down field)
I am using Play!Framework 2.1.0, below is a simple solution for your problem:
The model should be like this: (Below is simple model for your problem)
package models;
import play.data.validation.Constraints;
public class Gender {
// This field must have a value (not null or not an empty string)
#Constraints.Required
public String gender;
}
The controller should be like this:
/** Render form with select input **/
public static Result selectInput() {
Form<Gender> genderForm = Form.form(Gender.class);
return ok(views.html.validselect.render(genderForm));
}
/** Handle form submit **/
public static Result validateSelectInput() {
Form<Gender> genderForm = Form.form(Gender.class).bindFromRequest();
if (genderForm.hasErrors()) { // check validity
return ok("Gender must be filled!"); // can be bad request or error, etc.
} else {
return ok("Input is valid"); // success validating input
}
}
The template/view should be like this:
#(genderForm: Form[models.Gender])
#import views.html.helper._
#main(title = "Validate Select") {
#form(action = routes.Application.validateSelectInput()) {
#********** The default value for select input should be "" as a value *********#
#select(
field = genderForm("gender"),
options = options("" -> "Select Gender", "M" -> "Male", "F" -> "Female")
)
<input type="submit" value="Post">
}
}
See also this post as reference : Use of option helper in Play Framework 2.0 templates