Yii2 Kartik-V Typeahead Advanced Widget: How to store result in Mysql - mysql

Tearing my hair out at this point, hopefully someone can help me out!
I am using the Kartik-V Typeahead Advanced widget with Yii2.
The plugin works, in that the functionality is working perfectly on the page, I search and the results appear in the auto complete list.
Unfortunately, I am unable to store the result in my database. I am seeing an issue on the following line:
->where([ 'name' => $model->name ])//This variable is returning null
Am I trying to store the data incorrectly? I have tried everything I can think of, but I am sure someone here will come up with something better!
See below for the full code.
My controller:
public function actionIndex()
{
$model = new Member();
if ($model->load(Yii::$app->request->post())) {
$test = Test::find()
->where([ 'name' => $model->name ])//This variable is returning null
->one();
$test->updateCounters(['times_used' => 1]);
}
return $this->render('index', [
'model' => $model,
]);
}
/*************
* Initial prefetch of results
*************/
public function actionPrefetchlist() {
$query = new Query;
$query->select('name')
->from('test_table')
->limit(10)
->orderBy('times_used');
$command = $query->createCommand();
$data = $command->queryAll();
$out = [];
foreach ($data as $d) {
$out[] = ['value' => $d['name']];
}
echo Json::encode($out);
}
/*************
* Remote results
*************/
public function actionRemotelist() {
$query = new Query;
$query->select('name')
->from('test_table')
->where('name LIKE "%' . $q .'%"')
->limit(10)
->orderBy('times_used');
$command = $query->createCommand();
$data = $command->queryAll();
$out = [];
foreach ($data as $d) {
$out[] = ['value' => $d['name']];
}
echo Json::encode($out);
}
The view file:
echo $form->field($model, 'name')->label(false)->widget(Typeahead::classname(), [
'name' => 'name',
'options' => ['placeholder' => 'Filter as you type ...'],
'pluginOptions' => ['highlight'=>true],
'dataset' => [
[
'datumTokenizer' => "Bloodhound.tokenizers.obj.whitespace('value')",
'display' => 'value',
'prefetch' => Url::to(['prefetchlist']),
'remote' => [
'url' => Url::to(['remotelist']) . '?q=%QUERY',
'wildcard' => '%QUERY'
]
]
]
]);

you ask here for a new model:
$model = new Member();
so you get a empty model
so the $model->name is empty
if you set the model $model->name='test';
than it will be filled so, fill the model first

So it turns out it was a massive rookie error.
If anyone else stumbles upon something similar, I removed the attribute name from the model's "rules()"
I need an integer in the database but I wanted users to enter in a string (I would then convert it in the controller). Removing it from the rule broke everything.
Hopefully this helps someone else :)

Related

Is my logic to check data in database efficient?

I use laravel 5.6
I have a json file containing 500 thousand records. I want to create a logic to check whether the id of each record already exists or not in the database. If it doesn't already exist, then there will be a data insert process. If it already exists, there will be a data update process. Before updating the data, it will check whether last_modified_date in json file and database is the same or different. If it's different then it will update
I have made logic. I just want to make sure whether my logic is effective or not
My logic code like this :
$path = storage_path('data.json');
$json = json_decode(file_get_contents($path), true);
foreach ($json['value'] as $value) {
$last_modified_date = \Carbon\Carbon::parse($value['Last_Modified_Date']);
$data = \DB::table('details')->where('id', '=', $value['Code'])->get();
if ($data->isEmpty()) {
\DB::table('details')->insert(
[
'id' => $value['Code'],
'number' => $value['Number'],
'last_modified_at' => $last_modified_date,
...
]
);
}
else {
\DB::table('details')
->where('id', '=', $value['Code'])
->where('last_modified_at', '<>', $last_modified_date)
->update([
'id' => $value['Code'],
'number' => $value['Number'],
'last_modified_at' => $last_modified_date,
...
]);
}
}
The code is working. But the process seems really long
Do you have another solution that is better?
Update
I find another solution use updateOrCreate
I try like this :
$path = storage_path('data.json');
$json = json_decode(file_get_contents($path), true);
foreach ($json['value'] as $value) {
Details::updateOrCreate(
[ 'id' => $value['Code'] ],
[ 'number' => $value['Number'], 'last_modified_at' => $last_modified_date, ... ]
);
}
What do you think?
you can not use <> in updateOrCreate
i hope this code could help you:
$path = storage_path('data.json');
$json = json_decode(file_get_contents($path), true);
foreach ($json['value'] as $value) {
$detail = Details::firstOrCreate(
[ 'id' => $value['Code'] ],
[ 'number' => $value['Number'], 'last_modified_at' => $last_modified_date, ... ]
);
if($detail->last_modified_at != $last_modified_date) {
$detail->update([
'number' => $value['Number'],
'last_modified_at' => $last_modified_date,
...
]);
}
}

Yii 2 error - Trying to get a property of non object

I was trying to search the needed information, but couldn't find any of that. Somehow, I get this error and I don't know where I'm doing a mistake.
Here is my action:
public function actionFilter()
{
$filterParams = Yii::$app->request->get();
unset($filterParams['r']);
$model = new Sale();
$dataProvider = $model->filterParameters($filterParams);
return $this->render('filter', [
'dataProvider' => $dataProvider,
'filterParams' => $filterParams,
]);
}
And here is my view:
'attribute' => 'sale_id',
'width' => '14%',
'value' => function (Sale $model) {
return $model->sale->client->getClientName();
}
],
[
'attribute' => '',
'value' => function (Sale $model) {
return $model->sale->client->getClientSale();
}
],
I'm getting the error on the 'value' return line. The function getClientName() is in client model. Could someone explain what I'm doing wrong? Thanks for any help.
Propably there's no model linked to your main $model. You should check if it's set by:
return $model->debtor && $model->debtor->client ? $model->debtor->client->getFullName() : null;
AND
return $model->debtor && $model->debtor->user ? $model->debtor->user->getFullName() : null;
The answer is simple:
Turn-off PHP Notice Errors in PHP.ini
error_reporting E_ALL & ~E_NOTICE
In your view; just add # before the $model to override the problem. Find an example below:
return #$model->sale->client->getClientName();

Call to a member function saveAs() on a non-object

I am trying to upload image and database table.
on database table basic_info field name 'photo' that i want to store file name.
here is model
public function rules()
{
return [
[['photo'], 'string', 'max' => 255],
[['image'], 'safe'],
[['image'], 'file', 'extensions'=>'jpg, gif, png'],
];
}
here is controller
public function actionCreate()
{
$model = new BasicInfo();
if ($model->load(Yii::$app->request->post()))
{
$model->image = UploadedFile::getInstance($model, 'image');
$filename = pathinfo($model->image , PATHINFO_FILENAME);
$ext = pathinfo($model->image , PATHINFO_EXTENSION);
$newFname = $filename.'.'.$ext;
$path=Yii::getAlias('#membersImgPath');
if(!empty($newFname)){
$model->image->saveAs($path.$newFname);
$model->image = $newFname;
if($model->save()){
return $this->redirect(['view', 'id' => $model->id]);
}
}
}
return $this->render('create', [
'model' => $model,
]);
}
here is view
echo FileInput::widget([
'name' => 'photo',
'options' => ['accept' => 'image/*'],
]);
from your comment here,
$form = ActiveForm::begin(['type'=>ActiveForm::TYPE_VERTICAL],['opti‌​ons'=>['enctype'=>'m‌​ultipart/form-data']‌​]);
ActiveForm::begin does not have a second parameter. you need to use a single options array.
$form = ActiveForm::begin([
'type' => ActiveForm::TYPE_VERTICAL,
'opti‌​ons' => [
'enctype' => 'm‌​ultipart/form-data'
]‌
​]);
First of all, you have to check if there's a file. To do it try:
if(UploadedFile::getInstance($model, 'image')) {
// here should go your code with $model->image
}
Youre using pathinfo to get filename and extension. Remember, that youre using powerfull framework, you just initialized class UploadedFile which can do everything for you:
if(UploadedFile::getInstance($model, 'image')) {
$model->image = UploadedFile::getInstance($model, 'image');
$newFname = $model->image->name; // UploadedFile have properties like `name`, `tempName`, even `size`!
}
After doing this small fixes to your code (you should always check if something is set) - we can go to main problem.
Your input field name is photo, but youre trying to get image with name image.
Change this:
UploadedFile::getInstance($model, 'image');
To this:
UploadedFile::getInstance($model, 'photo'); // remeber to change it in `if` statement aswell!!
Theres also posibility that youre trying to upload file bigger than your post_max_size and upload_max_filesize allows. Change this properties in your php.ini, restart server and try again. If still something is not right, try to debug this thing, for start by doing var_dump($_FILES);die; in your controller.

Trying to get property of non-object while using kartik-v for image uploading in Yii2

I'm using yii2-widget-fileinput for an image uploading in a form.
When I click on upload or the create button I get Trying to get property of non-object error in controller.
Controller
public function actionCreate()
{
Yii::$app->params['uploadPath'] = Yii::$app->basePath . '/uploads/';
$model = new Ads();
$provinces = ArrayHelper::map(Province::find()->all(), 'name', 'name');
if ($model->load(Yii::$app->request->post())){
$image = UploadedFile::getInstances($model, 'image');
$model->filename = $image->name;
$ext = end((explode(".", $image->name)));
$avatar = Yii::$app->security->generateRandomString().".{$ext}";
$path = Yii::$app->params['uploadPath'].$avatar;
if ($model->save()) {
$image->saveAs($path);
$model->image_adr = $path;
return $this->redirect(['view', 'id' => $model->id]);
}else{
echo "error on saving the model";
}
}
return $this->render('create', [
'model' => $model,
'provinces'=>$provinces,
]);
}
model rules
public function rules()
{
return [
[['type', 'explanation', 'cost', 'province_name', 'address'], 'required'],
[['type', 'explanation', 'image_adr', 'address'], 'string'],
[['cost'], 'integer'],
[['province_name'], 'string', 'max' => 20],
[['province_name'], 'exist', 'skipOnError' => true, 'targetClass' => Province::className(), 'targetAttribute' => ['province_name' => 'name']],
[['image'],'safe'],
[['image'], 'file', 'extensions'=>'jpg, gif, png', 'maxFiles'=>3,],
];
and finnally the view
<?= $form->field($model, 'image[]')->widget(FileInput::classname(), [
'options'=>['accept'=>'image/*', 'multiple'=>true],
'pluginOptions'=>['allowedFileExtensions'=>['jpg','gif','png'], 'overwriteInitial'=>false,]
]); ?>
the problem should refer to this part in the controller I think
$image = UploadedFile::getInstances($model, 'image');
An image of the error might be helpful
You should check first is image in post or not.
....
$image = UploadedFile::getInstances($model, 'image'); //getInstanceByName
if (!empty($image))
$model->filename = $image->name;
.....
if ($model->save()) {
if (!empty($image))
$image->saveAs($path);
.........
Make sure in your form ency type is added:
$form = ActiveForm::begin([
'id' => 'form_id',
'options' => [
'class' => 'form_class',
'enctype' => 'multipart/form-data',
],
]);
The problem is when you're using UploadedFile::getInstances($model, 'image'); you should work with foreach or treat it like an array.
Something that made me a problem was that even if you're using UploadedFile::getInstanc (notice the obsoleted s in the end) you should still treat it like an array and in all parts you should use $image[0], not $iamge lonely.

Dynamic Multilevel Drop-down menu in Yii2

I want to create a dynamic menu with my table (db). I have followed some instructions which are given below:
Table : "menupanal"
Step 01: I just create a super controller in app\components\Controller.php
Here is the code:
namespace app\components;
use app\models\MenuPanal;
class Controller extends \yii\web\Controller
{
public $menuItems = [];
public function init(){
$items = MenuPanal::find()
->where(['c_type' => 'MENU'])
->orderBy('id')
->all();
$menuItems = [];
foreach ($items as $key => $value) {
$this->menuItems[] =
['label' => $value['c_name'],
'items'=> [
['label' => $value['c_redirect'], 'url' => ['#']],
],
];
}
parent::init();
}
Step 02: Changed n main layout page:
echo Nav::widget([
'options' => ['class' => 'navbar-nav navbar-right'],
'items' => Yii::$app->controller->menuItems,
]);
It is working in only one level. My question::
Question : how can I add multilevel menu using Super controller ?
I am new in Yii2. Helps are highly appreciated.
Create New MenuHelper in Component folder. There is no default component folder. Please create by yourself.
<?php
namespace app\components;
use app\models\MenuPanel;
use app\models\Zuser;
use app\models\Vwrole;
use app\assets\AppAsset;
class MenuHelper
{
public static function getMenu()
{
$role_id = 1;
$result = static::getMenuRecrusive($role_id);
return $result;
}
private static function getMenuRecrusive($parent)
{
$items = MenuPanel::find()
->where(['c_parentid' => $parent])
->orderBy('c_sortord')
->asArray()
->all();
$result = [];
foreach ($items as $item) {
$result[] = [
'label' => $item['c_name'],
'url' => ['#'],
'items' => static::getMenuRecrusive($item['id']),
'<li class="divider"></li>',
];
}
return $result;
}
}
in Main Layout Page put the following code
echo Nav::widget([
'options' => ['class' => 'navbar-nav navbar-right'],
'items' => app\components\MenuHelper::getMenu(),
Enjoy Coding!!
You may use nested sets. Look at this extension for Yii: http://www.yiiframework.com/extension/nestedsetbehavior/ and its documentation. All you need to do is component with dynamic creation of menu items array for nested sets.
I found that there is a Yii2 extension version: http://www.yiiframework.com/extension/yii2-nestedsetbehavior/
Good luck
You may use this extension for multilevel dropdownMulti level Dropdown