I'm trying to transform the following piece of code into a Facade.
But I don't know how to call $this in the facade. I want to do this without using $this or passing it as a parameter. Can I somehow dependency inject it?
The following piece of code is inside a livewire component which will dispatch event to show a toast by a JS listener.
//turn this
$this->dispatchBrowserEvent('showToast', ['name'=>'success','title' => 'Updated','message'=>'Your data is saved']);
//into this
$toast::success('Updated','Your data is saved');
How can I simplify this code?
I usually create a trait Toast.
trait Toast
{
public function successAlert(string $title, string $message)
{
$this->dispatchBrowserEvent('showToast', [
'name' => 'success',
'title' => $title,
'message' => $message,
])
}
}
Then on my livewire component I use:
class MyComponent extends Component
{
use Toast;
public function save()
{
// save
$this->successAlert('Updated','Your data is saved');
}
}
I couldn't think in an easy way to implement the facade, since you need to access internal features of the livewire component to dispatch the browser event.
Related
Since laravel can use custom validation rules when using Request validation
public function store(ModelStoreRequest $request) {
//
}
is there a way to reuse a custom validation rules without using request ? I am using a livewire and it doesn't need to use request.
public function store() {
$this->validate([
'foo' => 'required'
]);
}
My form validation code in controller is,
$this->form_validation->set_rules("name", "Name", "trim|callback_custom_validation");
if ($this->form_validation->run() !== FALSE) {}
My helper code is,
function custom_validation($str) {
// validation logic
}
If i move this custom_validation function to controller then it is working but it is not working as helper.
I need to call this function from controller and model so i am using helper.
So how to call from helper?
There are two ways to do this.
You should create a helper file in the application/helpers folder and place the function in the helper file. Then load the helper file in your controller.
custom_validation.php:
function custom_validation($str) {
// validation logic
}
Inside controller:
$this->load->helper('custom_validation');
You can also extend the Form_validation library.
Create a file: application/libraries/MY_Form_validation.php
<?php
class MY_Form_validation extends CI_Form_validation {
public function custom_validation($str) {
// validation logic
}
}
And then just load it as normal validation:
$this->form_validation->set_rules('name', 'Name', 'required|custom_validation');
Add your custom validation method to any model and use it in controllers and models like this example:
$this->form_validation->set_rules(
'name', 'Name',
array(
'trim',
'required',
array($this->Mymodel_m, 'custom_validation')
)
);
if ($this->form_validation->run() !== FALSE) {...}
More info
Callable: Use anything as a rule
I am mounting my component with an object $form which I need to access between requests.
The data in $form is not secret, but should not be tampered with so I would like to make it a protected property. Though only public properties are preserved between requests leaving it exposed to front end.
If possible, how can I prevent manipulation on this public property?
I tried a check
public function updating($key, $value)
{
if($key === 'form') return;
}
But I don't think that really does anything.
Also, using sessions is not an alternative in my situation.
Any ideas?
In my opinion you have these options:
Do not store the data as public property, instead just pass it to
your view in the render() method.
public function render(){
return view('Livewire.nameofyourview ', [
'form' => YourDataSource::get()
]);
}
This will refetch the data on every interaction with your component. You can access this in your template as before as $form.
Make sure to remove $form as public property. Manipulating the $form data form client/user site isn't possible with this solution. Docs
Use validation rules if you need your user/client to manipulate the
data, but only ways you expect.
protected $rules = [
'form.name' => 'required|min:6',
'form.email' => 'required|email',
];
Full Example
Use Laravel cache to preserve data between requests. This technique
is useful if you can't refetch your data from the source, like when
it was passed to your Livewire component as parameter (<livewire:form-component :form="$form">).
/* Cache the data on component mount */
public function mount($form)
{
Cache::set($this->id."_form", $form, 60*10);
}
public function someFunction()
{
/* read the data form cache, if you need it again */
cache($this->id."_form");
}
Validation functions don't work.
Validation customs rules are not applied to the usernmane field
module dektrium/user
PHP 7.1
Yii 2.0.16
Already try all from here: https://www.yiiframework.com/doc/guide/2.0/en/input-validation (Inline Validators and Standalone Validators)
Model Agent :
class Agent extends Profile
{
public $username;
public $password;
public $password2;
public function rules()
{
$rules = [
['username', AgentValidator::className()],// it's not work
[['email'], 'email'], // it's work
['password2', 'compare', 'compareAttribute' => 'password', 'message' => 'Пароли должны совпадать'],//// it's work
];
return array_merge(parent::rules(), $rules);
}
}
AgentValidator.php
<?php
namespace app\components;
use yii\validators\Validator;
class AgentValidator extends Validator
{
public function validateAttribute($model, $attribute)
{
if (User::findOne(['username' => $this->$attribute]]) {
$this->addError($attribute, 'Такой логин уже занят');
}
}
}
You are using standalone validator and you want the frontend validation to be working along with the backend so you need to override the yii\validators\Validator::clientValidateAttribute() in your Standalone validator AgentValidator, which returns a piece of JavaScript code that performs the validation on the client-side.
Within the JavaScript code, you may use the following predefined variables:
attribute: the name of the attribute being validated.
value: the value being validated.
messages: an array used to hold the validation error messages for the attribute.
deferred: an array which deferred objects can be pushed into.
You can go through the section Implementing Client Validation to read in detail.
Apart from everything listed above you have a mistake in your validator code User::findOne(['username' => $this->$attribute]], you need to use $model->$attribute rather than $this->$attribute which will never get the exact value entered in the form. You might have mistakenly added it from the model.
Your current validator should be like below
<?php
namespace app\components;
use yii\validators\Validator;
class AgentValidator extends Validator
{
public $message='Такой логин уже занят';
public function validateAttribute($model, $attribute)
{
if (User::findOne(['username' => $model->$attribute])!==null)
{
$model->addError($attribute, $this->message);
}
}
public function clientValidateAttribute($model, $attribute, $view) {
//check if user exists
$userExists = User::findOne(['username' => $model->$attribute])!==null;
$message = json_encode($this->message, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
return <<<JS
if($userExists){
messages.push($message);
return;
}
JS;
}
}
So, Thank Muhammad Omer Aslam for right answer.
Yii2 does't generate any js code for validation by custom rules. Therefore it is necessary to add a check to the controller and the form
For me it:
Controller
if (\Yii::$app->request->isAjax) {
\Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
$model->load(\Yii::$app->request->post());
return \yii\widgets\ActiveForm::validate($model);
}
Form
$form = ActiveForm::begin([ 'enableAjaxValidation' => true]);
I use proengsoft/laravel-jsvalidation in combination with a custom FormRequest and custom validation rules that I defined via Validator::extend(...) in a service provider. This works well.
However, when I port my custom rules to the new(ish) custom Rule class in Laravel 5.5+, JsValidator fails at getting my custom Rule messages.
I have this custom rule:
use Illuminate\Contracts\Validation\Rule;
class MyRule implements Rule
{
public function passes($attribute, $value) {
return $value > 10;
}
public function message() {
return 'Your :attribute is pretty small, dawg!';
}
}
My form request uses this rule:
use Illuminate\Foundation\Http\FormRequest;
use App\Rules\MyRule;
class MyRequest extends FormRequest
{
public function authorize() {
return true;
}
public function rules() {
$rules = [
'foo' => 'required|numeric',
'bar' => ['required', new MyRule()],
];
return $rules;
}
}
This should work, but I get thrown an Exception on
{!! JsValidator::formRequest('\App\Http\Requests\MyRequest') !!}
An Exception is thrown from a call to Str::snake(Object(App\Rules\MyRule)) made by Proengsoft\JsValidation\Javascript\MessageParser.php.
JsValidation does not look at the $rule object type before calling Validator->getMessage($attribute, $rule)
where instead it should be calling $rule->messages();
Can I work around this bug somehow, and use laravel-jsvalidation together with my custom Rule and FormRequest -- or does it necessarily require i make a pull request and hope it will be fixed... someday? I'd like to make this work now-ish.
This can be archived by passing JsValidator instance based on rules and message arrays instead of passing the form request. In controller Pass this instance to blade. Read here for more details.
JsValidator::make($rules, $messages, $customAttributes, $selector)
In controller,
$validator = JsValidator::make(
[
'name' => 'required',
],
[
'name.required' => 'Name field is a required field',
]
)
return View::make("Your view", compact($validator));
In blade,
{!! $validator->selector('.wizard_frm') !!}
<form class='wizard_frm'></form>
And in this case we can create object of request class and pass rules function returned array to JsValidator::make if needed.