Some help needed?
I already going numb on this, on the controller, the action link is not being found (404), but the action "Other" works fine.
- basic theme
- inside a module
- url I am calling is /admin/banner-image/link
- namespace app\modules\admin\controllers
I am using krajee EditableColumn and grid here.
Please, any idea, what am I missing?
https://gist.github.com/moplin/0c43c38bf0b42d74a3a13a51e4356edf
class BannerImageController extends Controller
{
public function actions()
{
return ArrayHelper::merge(parent::actions(), [
'link' => [
'class' => EditableColumnAction::className(),
'modelClass' => CexBannerImg::className(),
'outputValue' => function ($model, $attribute, $key, $index) {
return $model->$attribute;
},
'outputMessage' => function($model, $attribute, $key, $index) {
return '';
},
]
]);
}
public function actionOther()
{
return 'other';
}
}
and the EditableColumn configuration en the grid.
[
'class' => 'kartik\grid\EditableColumn',
'attribute' => 'route',
'filter' => false,
'editableOptions' => [
'header' => '¿Link?',
'size'=>'md',
'formOptions'=>['action' => ['banner-image/link']],
'inputType' => Editable::INPUT_TEXT ,
],
'format' => ['text'],
],
Related
I have a form. The form has a Collection whose target element is a fieldset with a checkbox and a couple of text fields. The fieldset attached as the target element to Collection looks like this (simplified to avoid too much code):
class AFieldset extends Fieldset implements InputFilterProviderInterface
{
public function __construct(HydratorInterface $hydrator)
{
parent::__construct();
$this->setHydrator($hydrator)
->setObject(new SomeObject());
$this->add([
'type' => Hidden::class,
'name' => 'id',
]);
$this->add([
'type' => Checkbox::class,
'name' => 'selectedInForm',
]);
$this->add([
'type' => Text::class,
'name' => 'textField1',
]);
$this->add([
'type' => Text::class,
'name' => 'textField2',
]);
}
public function getInputFilterSpecification()
{
return [
'selectedInForm' => [
'required' => false,
'continue_if_empty' => true,
'validators' => [
['name' => Callback::class // + options for the validator],
],
],
'id' => [
'requred' => false,
'continue_if_empty' => true,
],
'textField1' => [
'required' => false,
'continue_if_empty' => true,
'validators' => [
['name' => SomeValidator::class],
],
],
'textField2' => [
'required' => true,
'validators' => [
['name' => SomeValidator::class],
],
],
],
}
}
I'd like to validate textField1 and textField2 based on if selectedInForm checkbox is checked in the form.
How could I do this?
I though of using a Callback validator for selectedInForm checkbox like this:
'callback' => function($value) {
if ($value) {
$this->get('textField1')->isValid();
// or $this->get('textField1')->getValue() and do some validation with it
}
}
but the problem with it is that, for some reason, the posted value of textField1 value isn't attached to the input yet. Same is true for textField2.
Two option is available. One is where you started, with callback validators.
The other one is to write a custom validator, and to make it reusable I recommend this solution.
<?php
use Zend\Validator\NotEmpty;
class IfSelectedInFormThanNotEmpty extends NotEmpty
{
public function isValid($value, array $context = null): bool
{
if (! empty($context['selectedInForm']) && $context['selectedInForm']) {
return parent::isValid($value);
}
return true;
}
}
And then you can use it as every other validator:
'textField2' => [
'required' => true,
'validators' => [
['name' => IfSelectedInFormThanNotEmpty::class],
],
],
This may not be your exact case, but I hope it helped to get the idea.
You may define options to make it more reusable with a configurable conditional field in public function __construct($options = null).
The problem
I have a Form and a FieldSet. I would like to validate that the FieldSet is not empty. Also, I want to validate each field in the FieldSet.
So far, whatever I have tried is validating one or the other, but not both. If elements is present in the Form's input filter specification, then it validates that elements is not empty, but does not validate the bar and baz fields of FieldSet. And, of course, the other way around. Any clue as to how to approach this issue would be much appreciated.
The Form
class FooForm extends Form implements InputFilterProviderInterface
{
public function init()
{
$this->add([
'name' => 'elements',
'type' => Collection::class,
'required' => true,
'options' => [
'target_element' => [
'type' => SomeElementFieldSet::class
]
]
]);
}
public function getInputFilterSpecification()
{
return [
[
'name' => 'elements',
'required' => true,
'validators' => [
['name' => 'NotEmpty']
]
]
];
}
}
The FieldSet
class SomeElementFieldSet extends Fieldset implements InputFilterProviderInterface
{
public function init()
{
$this->add(['name' => 'bar']);
$this->add(['name' => 'baz']);
}
public function getInputFilterSpecification()
{
return [
[
'name' => 'bar',
'required' => true,
'validators' => [
['name' => 'NotEmpty']
]
],
[
'name' => 'baz',
'required' => true,
'validators' => [
['name' => 'NotEmpty']
]
]
];
}
}
Edit: Added full validation spec.
After getting some hints on Google and digging through the source code, I found a solution. Unfortunately the zend-inputfilter implementation is a little buggy and won't work nicely with getInputFilterSpecification(), but we can just construct our own InputFilter and return that directly:
The Form
class FooForm extends BaseForm
{
public function init()
{
$this->add([
'name' => 'elements',
'type' => Collection::class,
'options' => [
'target_element' => [
'type' => SomeElementFieldSet::class
]
]
]);
}
public function getInputFilter()
{
if (!$this->filter) {
$this->filter = new InputFilter();
/** #var Collection $elementsCollection */
$elementsCollection = $this->fieldsets['elements'];
/** #var SomeElementFieldSet $elementsFieldSet */
$elementsFieldSet = $elementsCollection->getTargetElement();
$collectionFilter = new CollectionInputFilter();
$collectionFilter->setIsRequired(true);
$collectionFilter->setInputFilter(
$elementsFieldSet->getInputFilterSpecification()
);
$this->filter->add($collectionFilter, 'elements');
}
return $this->filter;
}
}
This will validate that there is at least one element in the collection. And will validate all the elements one by one by the FieldSet's specification.
One problem persists, though. Whenever the collection is empty, the validation will return false, but will not return any messages. This is due to a bug in the zend-inputfilter component. Issues reported here and here. But that is another problem altogether.
Use setValidationGroup() method in the Form object by specifying an array of input fields you want to validate. Please refer to the Doc!
You may give a try this way. Though I have added some extra fields to the form for testing purpose only.
class FooForm extends Form implements InputFilterProviderInterface
{
public function __construct($name = null, $options = array())
{
parent::__construct($name, $options);
$this->add(['name' => 'title']);
$this->add([
'name' => 'elements',
'type' => Collection::class,
'required' => true,
'options' => [
'target_element' => [
'type' => SomeElementFieldSet::class,
],
],
]);
$this->add([
'type' => 'submit',
'name' => 'submit',
'attributes' => [
'value' => 'Post'
],
]);
// I pointed this. Here you can specify fields to be validated
$this->setValidationGroup([
'title',
'elements' => [
'bar',
],
]);
}
public function getInputFilterSpecification()
{
return [
[
'name' => 'title',
'required' => true,
'validators' => [
['name' => 'NotEmpty']
]
],
];
}
}
And your fieldset class should be
class SomeElementFieldSet extends Fieldset implements InputFilterProviderInterface
{
public function init()
{
$this->add(['name' => 'bar']);
$this->add(['name' => 'baz']);
}
public function getInputFilterSpecification()
{
return [
[
'name' => 'bar',
'required' => true,
'validators' => [
['name' => 'NotEmpty']
]
],
[
'name' => 'baz',
'required' => true,
'validators' => [
['name' => 'NotEmpty']
]
]
];
}
}
Hope this would help!
I have added this 'sla_status' field in gridview and every thing is working fine only issue is I am unable to set filter values for this.
'sla_status' is not in my table.
[
'label' => Yii::t('app','Sla Status'),
'format' => 'raw',
'filterType' => GridView::FILTER_SELECT2,
'filter' => $status,
'filterWidgetOptions' => [
'options' => [
'placeholder' => Yii::t('app','All...' )
],
'pluginOptions' => [
'allowClear' => true
]
],
'headerOptions' => ['style' => 'text-align:center;color:#337ab7'],
'value' => function ($model, $key, $index, $widget)
{ }
]
and $status is $status = array('0'=>Yii::t('app', 'Inactive'),'1'=>Yii::t('app', 'Active'));
Add a public variable $sla_status and add sla_status as safe in the rules array in search model
public $sla_status;
public function rules()
{
return [
[['sla_status'], 'safe'],
];
}
in Search model you should add attribute sla_status
and in search() add required where.
for example:
class TaskSearch extends Task{
public $sla_status;
public function search($params){
$query = Task::find();
if($this->sla_status){ $query->andWhere(...); }
}}
Add your field "sla_status" to "safe" in rules method of your model or search model like
[['sla_status'], 'safe'],
I am stuck with a problem that don't know how to get the value from url. I am new in backpack. please help me with this.....
I want my details on a view based on the id that is passed from another view, how to implement this?? this is my code
Adcontroller.php
public $crud = array(
"model" => "App\Larapen\Models\Ad",
"entity_name" => "ad",
"entity_name_plural" => "ads",
"route" => "admin/ad",
"reorder" => false,
"add_permission" => false,
"columns" => [
[
'name' => 'reviewed',
'label' => "Reviewed",
'type' => "model_function",
'function_name' => 'getReviewedHtml',
],
],
"fields" =>[
[ // Hidden
'name' => 'id',
'label' => "id",
'type' => 'hidden'
],
],
);
Ad.php(model)
public function getReviewedHtml()
{
if ($this->reviewed == 1) {
return '<i class="fa fa-check-square-o" aria-hidden="true"></i><span> Reviews</span>';
} else {
return '<i class="fa fa-square-o" aria-hidden="true"></i>';
}
}
route.php
CRUD::resource('ad', 'AdController');
CRUD::resource('reviews', 'AdReviewController');
AdReviewController.php
public $crud = array(
"model" => "App\Larapen\Models\AdReviews",
"entity_name" => "Reviews",
"entity_name_plural" => "Reviews",
"route" => "admin/reviews",
"reorder" => false,
"add_permission" => false,
// *****
// COLUMNS
// *****
"columns" => [
[
'name' => 'created_at',
'label' => "Date",
],
[
'name' => 'user',
'label' => "User",
'type' => "model_function",
'function_name' => 'getuser',
],
[
'name' => 'review',
'label' => "Review",
],
],
"fields" => [
[
'name' => 'review',
'label' => "Review",
],
],
);
public function __construct()
{
//$this->crud['update_fields'][1]['options'] = $this->adType();
// $this->crud['update_fields'][2]['options'] = $this->categories();
parent::__construct();
}
public function store(StoreRequest $request)
{
return parent::storeCrud();
}
public function update(UpdateRequest $request)
{
return parent::updateCrud();
}
}
"I want to display the reviews based on each Ads now it display all the reviews from the review table, where should i write the condition???"
Waiting for a response...............
I presume you have one-to-one or one-to-many relationships between AdReview and Review, defined both in your Review model and your AdReview model.
If so, you can add:
a "select" column in your table view;
a "select" / "select2" field in your create/update views;
That will show the entity it's "connected" with and allow the user to edit it.
Is this what you were trying to achieve?
I have this behavior in my model:
public function behaviors()
{
return [
'styles' => [
'class' => ImageStyleBehavior::className(),
'path' => \Yii::getAlias('#webroot') . '/files/userphotos/styles',
'url' => \Yii::getAlias('#web') . '/files/userphotos/styles',
'attribute' => 'photo',
'styles' => [
'300x300' => [$this, 'style300'], //can be any valid callable
'100x100' => [$this, 'style100'], //can be any valid callable
]
]
];
}
The photo have default value of noavatar.png, and when I try to insert, I get this error:
Exception 'Imagine\Exception\RuntimeException' with message 'Unable to open image /var/www/c2c/Care2Shine/www/files/userphotos/'
Is there a way for me to prevent behavior on insert actions?
You can remove specific named behaviors by detaching them:
$model->detachBehavior('styles');
Or, if it's the only behavior, you can just detach all:
$model->detachBehaviors();
To ensure you only detach on insert, check isNewRecord property.
Does the ImageStyleBehavior extend the AttributeBehavior ? in that case you should be able to use:
public function behaviors()
{
return [
[
'class' => AttributeBehavior::className(),
'attributes' => [
ActiveRecord::EVENT_BEFORE_INSERT => 'attribute1',
ActiveRecord::EVENT_BEFORE_UPDATE => 'attribute2',
],
'value' => function ($event) {
return 'some value';
},
],
];
}