I am very new to web development.
I'm newbie in here, my first question in stackoverflow..
i am confused what error on code, Code will be store data array csv to a database,
sorry my bad english.
Controller
public function actionUpload()
{
$model = new Skt();
//error_reporting(E_ALL);
//ini_set('display_error', 1);
if ($model->load(Yii::$app->request->post())) {
$file = UploadedFile::getInstance($model, 'file');
$filename = 'Data.' . $file->extension;
$upload = $file->saveAs('uploads/' . $filename);
if ($upload) {
define('CSV_PATH', 'uploads/');
$csv_file = CSV_PATH . $filename;
$filecsv = file($csv_file);
foreach ($filecsv as $data) {
$modelnew = new Skt();
$hasil = explode(",", $data);
$no_surat= $hasil[0];
$posisi= $hasil[1];
$nama= $hasil[2];
$tgl_permanen= $hasil[3];
$grade= $hasil[4];
$tgl_surat= $hasil[5];
$from_date = $hasil[6];
$to_date = $hasil[7];
$modelnew->no_surat = $no_surat;
$modelnew->posisi = $posisi;
$modelnew->nama = $nama;
$modelnew->tgl_permanen = $tgl_permanen;
$modelnew->grade = $grade;
$modelnew->tgl_surat = $tgl_surat;
$modelnew->from_date = $from_date;
$modelnew->to_date = $to_date;
$modelnew->save();
//print_r($modelnew->validate());exit;
}
unlink('uploads/'.$filename);
return $this->redirect(['site/index']);
}
}else{
return $this->render('upload',['model'=>$model]);
}
return $this->redirect(['upload']);
}
Model
class Skt extends \yii\db\ActiveRecord
{
public static function tableName()
{
return 'skt';
}
public $file;
public function rules()
{
return [
[['file'], 'required'],
[['file'], 'file', 'extensions' => 'csv', 'maxSize' => 1024*1024*5],
[['no_surat'], 'required'],
[['tgl_surat', 'from_date', 'to_date'], 'string'],
[['no_surat', 'posisi', 'nama', 'tgl_permanen', 'grade'], 'string', 'max' => 255],
];
}
public function attributeLabels()
{
return [
'no_surat' => 'No Surat',
'posisi' => 'Posisi',
'nama' => 'Nama',
'tgl_permanen' => 'Tgl Permanen',
'grade' => 'Grade',
'tgl_surat' => 'Tgl Surat',
'from_date' => 'From Date',
'to_date' => 'To Date',
'file' => 'Select File'
];
}
}
thanks for helping..
change your code to the following to output the errors which could happen when you try to save. Errors could occur depending on your model rules.
if (!$modelnew->save()) {
var_dump($modelnew->getErrors());
}
getErrors() from Api
A better approach is to use exceptions to throw and catch errors on your import. Depends if you want to skip csv lines on errors or not.
finally it working with change this $hasil = explode(";", $data);
Related
I have a lot of fields generated from loops. I would like to validate them through validation rules (integer). I don't know how to throw so many fields with random names into the model to the rules () function. How can I validate fields without a model?
View:
<?= Html::input('number', 'file[' . $indexRow . ']' . '[' . $indexCell . ']', $cell, $options = ['class' => 'form-control', 'filter' => 'intval', 'integer']) ?>
Controller:
` public function actionEdit($fileName)
{
$siteHelper = new SiteHelper();
$editForm = new EditForm();
$preparedRows = $siteHelper->prepareRows($fileName);
$preparedHTML = '';
if (Yii::$app->request->isPost) {
$post = Yii::$app->request->post();
if (isset($post['file'])) {
$dataFile = $post['file'];
$preparedRows = $siteHelper->updateExcelFile($fileName, $dataFile);
Yii::$app->session->setFlash('success', 'Plik zostaĆ zaktualizowany!');
} else if (isset($post['EditForm'])) {
$events = $post['EditForm']['events'];
$preparedHTML = $siteHelper->prepareHTML($events, $preparedRows, $fileName);
Yii::$app->session->setFlash('success', 'Wygenerowano plik PDF!');
}
}
$viewParameters = [
'rows' => $preparedRows,
'editForm' => $editForm,
'scoreHTML' => $preparedHTML,
'downloadLink' => Url::toRoute(['site/download', 'fileName' => $fileName])
];
return $this->render('edit', $viewParameters);
}`
Model:
`
class EditForm extends Model
{
public $events;
public function rules()
{
return [
[['events'], 'required'],
['events', 'integer'],
];
}
}`
When you have an array you can use each validator:
https://www.yiiframework.com/doc/api/2.0/yii-validators-eachvalidator
The validation function should be:
public function rules()
{
return [
[['events'], 'each', 'rule' => ['required']],
[['events'], 'each', 'rule' => ['integer']],
];
}
You may need to avoid multidemnsional array in html and render the field like this:
<?= Html::input('number', 'file[' . $indexRow . '-' . $indexCell . ']', $cell, $options = ['class' => 'form-control', 'filter' => 'intval', 'integer']) ?>
later you can "explode" the row cell index (isn't it supposed to be col?) to identify the row and the column.
$rowCellIndecies = explode('-', $rowCellIndex);
explode function: https://www.php.net/manual/en/function.explode.php
I am trying to add captcha validation based on scenario, for which I am first retrieving number of failed attempts from database. For which I am using checkattempts() function. Based on the result I am displaying captcha in view and adding scenario condition in controller as below.
In LoginForm model:
public function rules()
{
return [
[['username', 'password'], 'required', 'on'=>'loginpage'],
[['username', 'password'], 'required', 'on'=>'withCaptcha'],
[['reference_url'], 'safe'],
[['verifyCode'], 'captcha', 'skipOnEmpty' => true,'on'=>'withCaptcha'],
['username','email', 'on'=>'loginpage', 'message'=> 'Please enter a valid email address'],
['password', 'validatePassword', 'on'=>'loginpage'],
['password', 'validatePassword', 'on'=>'withCaptcha'],
];
}
public function checkattempts($uname)
{
$user = \frontend\models\User::findByEmail($uname);
$ip = $this->get_client_ip();
if($user){
$data = (new Query())->select('*')
->from('login_attempts')
->where(['ip' => $ip])->andWhere(['user_ref_id' => $user->id])
->one();
if($data["attempts"] >=3){
return true;
}else{
return false;
}
}
return false;
}
in SiteController.php controller
public function actionLogin() {
if (!\Yii::$app->user->isGuest) {
return $this->redirect(Yii::$app->getUrlManager()->getBaseUrl() . '/../../');
}
$model = new \common\models\LoginForm();
$model->scenario = 'loginpage';
$captcha = false;
if(Yii::$app->request->post()){
$post_variables =Yii::$app->request->post('LoginForm');
if ($model->checkattempts($post_variables['username'])) {
$model->scenario = 'withCaptcha';
$captcha = true;
}
}
if ($model->load(Yii::$app->request->post()) && $model->validate()) {
$model->login(); print_r($model->getErrors()); exit;
} else {
return $this->render('login', [
'model' => $model, 'captcha' => $captcha,
]);
}
In my login.php view:
<?php if($captcha) { ?>
<?= $form->field($model, 'verifyCode')->widget(Captcha::className(),
['template' => '<div class="captcha_img">{image}</div>'
. '<a class="refreshcaptcha" href="#">'
. Html::img('/images/imageName.png',[]).'</a>'
. 'Verification Code{input}',
])->label(FALSE); ?>
<?php } ?>
In my controller when I am tring to print model errors at $model->login() function it is giving below error everytime even though the verification code is correct.
Array ( [verifycode] => Array ( [0] => The verification code is incorrect. ) )
Why is it failing every time. Is there any mistake in the code written?
Thanks in advance
I'm coding a multiple upload function for my website. The upload was successful. But it's only save the first value to my database. Example i upload 3 files name 1.jpg, 2.jpg, 3.jpg. Then it will upload the 3 files successfully but save only the 1.jpg's name to database.
My controllers
public function actionCreate()
{
$model = new Resource3d();
if ($model->load(Yii::$app->request->post())) {
$model->files = UploadedFile::getInstances($model, 'files');
foreach ($model->files as $files){
$files->saveAs('uploads/resource3d/' . $files->baseName . $files->extension);
$model->path = '../web/uploads/resource3d/'. $files->baseName . $files->extension;
$model->name = $files->baseName;
$model->save();
}
return $this->redirect(['index']);
} else {
return $this->render('create', [
'model' => $model,
]);
}
}
My models:
public $files;
public function rules()
{
return [
[['name', 'path'], 'string', 'max' => 255],
[['files'], 'file', 'skipOnEmpty' => false, 'maxFiles' => 0],
];
}
Please help.
Thank you.
You are creating single object of your model Resource3d. You need to create multiple object if you want to save multiple records.
Try this :
public function actionCreate()
{
$model = new Resource3d();
if ($model->load(Yii::$app->request->post())) {
$model->files = UploadedFile::getInstances($model, 'files');
foreach ($model->files as $files){
$res_model = new Resource3d();
$res_model->load(Yii::$app->request->post());
$files->saveAs('uploads/resource3d/' . $files->baseName . $files->extension);
$res_model->path = '../web/uploads/resource3d/'. $files->baseName . $files->extension;
$res_model->name = $files->baseName;
$res_model->save();
}
return $this->redirect(['index']);
} else {
return $this->render('create', [
'model' => $model,
]);
}
}
This is just an example, change it according to your need.
In an ActiveDataProvider you can use closures as values, like:
$dataprovider = new ArrayDataProvider([
'allModels' => $array
]);
$gridColumns = [
'attrib_1',
[
'attribute' => 'attrib_2',
'label' => 'Label_2',
'value' => function($model) {
return Html::encode($model->value_2);
}
],
'attrib_3'
];
echo GridView::widget([
'dataProvider'=> $dataprovider,
'columns' => $gridColumns
]);
Is it possible to do the same or something like this, in an ArrayDataProvider?
Yes. Only difference is that $model is not an object but array so:
'value' => function($model) {
return Html::encode($model['value_2']);
}
For this purpose, I have created an extended version of ActiveDataProvider, that for each model got from provider I call a callback.
This is the custom ActiveDataProvider, put in common\components namespace in this case.
<?php
namespace common\components;
class CustomActiveDataProvider extends \yii\data\ActiveDataProvider
{
public $formatModelOutput = null;
public function getModels()
{
$inputModels = parent::getModels();
$outputModels = [];
if($this->formatModelOutput != null)
{
for($k=0;$k<count($inputModels);$k++)
{
$outputModels[] = call_user_func( $this->formatModelOutput, $k , $inputModels[$k]);
}
}
else
{
$outputModels = $inputModels;
}
return $outputModels;
}
}
This is the action in controller that uses it. For reusability, I call a model method instead calling a clousure, but you can call also a clousure.
public function actionIndex()
{
$query = Model::find();
$dataProvider = new \common\components\CustomActiveDataProvider([
'query' => $query,
'pagination' => ['pageSize' => null],
'formatModelOutput' => function($id, $model) {
return $model->dataModelPerActiveProvider;
}
]);
return $dataProvider;
}
At last, this is the method getDataModelPerActiveProvider in model:
public function getDataModelPerActiveProvider()
{
$this->id = 1;
// here you can customize other fields
// OR you can also return a custom array, for example:
// return ['field1' => 'test', 'field2' => 'foo', 'field3' => $this->id];
return $this;
}
I have a registration form with fields that are validated in User entity class. The validation works fine, however I can't return JsonResponse with form error messages in it.
My registration form controller method looks like this:
/**
* #Route("/register", name="register")
*/
public function registerAction(Request $request)
{
$user = new User();
$form = $this->createForm(RegistrationType::class, $user);
$form->handleRequest($request);
$errors = "";
if ($form->isSubmitted())
{
if ($form->isValid())
{
$password = $this->get('security.password_encoder')
->encodePassword($user, $user->getPlainPassword());
$user->setPassword($password);
$user->setIsActive(1);
$user->setLastname('none');
$em = $this->getDoctrine()->getManager();
$em->persist($user);
$em->flush();
return new JsonResponse(
array(
'message' => 'Success! User registered!',
), 200);
}
else
{
$errors = ($this->get('validator')->validate($form));
return new JsonResponse(
array(
'message' => 'Not registered',
'errors' => $errors,
), 400);
}
}
return $this->render(
'ImmoBundle::Security/register.html.twig',
array('form' => $form->createView(), 'errors' => $errors)
);
}
I get the following json response when I submit the registration form with invalid data:
{"message":"Not registered","errors":{}}
Actually I'm expecting that "errors":{} will contain some error fields, but it doesn't. Does anyone know what the problem here is?
UPD:
My RegistrationType looks like this:
class RegistrationType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('firstname', TextType::class)
->add('email', EmailType::class)
->add('plainPassword', RepeatedType::class, array(
'type' => PasswordType::class,
'first_options' => array('label' => 'Password'),
'second_options' => array('label' => 'Repeat password'),
'invalid_message' => "Passwords don't match!",
))
->add('register', SubmitType::class, array('label' => 'Register'));
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'ImmoBundle\Entity\User',
'csrf_protection' => true,
'csrf_field_name' => '_token',
'csrf_token_id' => 'authenticate',
));
}
}
UPD2: Found the solution. I needed to do this iteration and then call for getMessage():
$allErrors = ($this->get('validator')->validate($form));
foreach ($allErrors as $error)
{
$errors[] = $error->getMessage();
}
Form validated when you call $form->handleRequest($request);
To get form errors use getErrors method
$errors = $form->getErrors(true); // $errors will be Iterator
to convert errors object to messages array you can use code from this response - Handle form errors in controller and pass it to twig
This is exapmle how i'm process errors in one of my projects
$response = $this->get('http.response_formatter');
if (!$form->isValid()) {
$errors = $form->getErrors(true);
foreach ($errors as $error) {
$response->addError($error->getMessage(), Response::HTTP_BAD_REQUEST);
}
return $response->jsonResponse(Response::HTTP_BAD_REQUEST);
}
It's worked for me.
And also this can help you - Symfony2 : How to get form validation errors after binding the request to the form
You must set error_bubbling to true in your form type by explicitly setting the option for each and every field.