How to validate two dimensional array in Yii2 - yii

How to validate two dimensional array in Yii2.
passenger[0][name] = bell
passenger[0][email] = myemail#test.com
passenger[1][name] = carson123
passenger[1][email] = carson###test.com
how to validate the name and email in this array
Thanks

Probably the most clean solution for validating 2-dimensional array is treating this as array of models. So each array with set of email and name data should be validated separately.
class Passenger extends ActiveRecord {
public function rules() {
return [
[['email', 'name'], 'required'],
[['email'], 'email'],
];
}
}
class PassengersForm extends Model {
/**
* #var Passenger[]
*/
private $passengersModels = [];
public function loadPassengersData($passengersData) {
$this->passengersModels = [];
foreach ($passengersData as $passengerData) {
$model = new Passenger();
$model->setAttributes($passengerData);
$this->passengersModels[] = $model;
}
return !empty($this->passengers);
}
public function validatePassengers() {
foreach ($this->passengersModels as $passenger) {
if (!$passenger->validate()) {
$this->addErrors($passenger->getErrors());
return false;
}
}
return true;
}
}
And in controller:
$model = new PassengersForm();
$model->loadPassengersData(\Yii::$app->request->post('passenger', []));
$isValid = $model->validatePassengers();
You may also use DynamicModel instead of creating Passanger model if you're using it only for validation.
Alternatively you could just create your own validator and use it for each element of array:
public function rules() {
return [
[['passengers'], 'each', 'rule' => [PassengerDataValidator::class]],
];
}
You may also want to read Collecting tabular input section in guide (unfortunately it is still incomplete).

Related

Flatten laravel nested relationship (parent to descendants) get all childerns

This is my Controller
$categoryIds = Category::select('id')->with('childrenRecursive')->where('id', 1)->get();
Ad::whereIn('category_id', $categoryIds)->get();
This is my model
public function parent() {
return $this->belongsTo(Category::class, 'parent_id');
}
public function childs() {
return $this->hasMany(Category::class, 'parent_id');
}
public function Ads() {
return $this->hasManyThrough(Ad::class, Category::class, 'parent_id', 'category_id', 'id');
}
How get all childern categories ides
I solved this problem with this solution
My Controller
public function index()
{
$parent = Category::with('descendants')->find(1);
$descendants = $this->traverseTree($parent, collect([1]));
$ads = Ad::whereIn('category_id',$descendants)->get();
return response($ads);
}
protected function traverseTree($subtree, $des)
{
$descendants = $des;
if ($subtree->descendants->count() > 0) {
foreach ($subtree->descendants as $descendant) {
$descendants->push($descendant);
$this->traverseTree($descendant, $descendants);
}
}
return $descendants;
}
I'd do it with Laravel's Subqueries approach.
$parentId = 4;
Ad::whereIn('category_id', function($q) use ($parentId) {
$q->select('id')
->from('categories')
->where('parent_id', $parentId);
});
If you want to add the parent model, you can chain with():
Ads::whereIn('category_id', function($q) use ($parentId) {
$q->select('id')
->from('categories')
->where('parent_id', $parentId);
})
->with('category.parent')
->get();
Your code chunks are not clear so you may need to tweak my code example.
If I understand your question properly you need to get ads corresponding to id's of all related records also, for a given category record.
$category = Category::with('childs:id,parent_id')
->where('id', 1)
->firstOrFail();
$categoryIds = collect([$category->parent_id, $category->id]);
$category->childs->map(fn($child) => $categoryIds->push($child->id));
$ads = Ads::whereIn('category_id', $categoryIds->filter()->all())
// Can eager load the product(s) if needed
//->with('products')
->get();

Laravel (API): I need to insert the post with Multiple Blog categories by using API Request (React)

I am trying to create a functionality for blog post which suppose to add by using front application which is built on react and my api which is built on Laravel (5.6),
I have tried couple of things, but unfortunately I am unable to figure out how can I attach multiple blog categories with single post
BlogPostAPIController.php
public function store(Request $request)
{
$BlogPosts = new BlogPosts;
$BlogPosts->tutor_id = $request->user()->tutor->id;
$BlogPosts->title = $request->title;
$BlogPosts->BlogCategories = $request->BlogCategories; /* Unknown column*/
$BlogPosts->slug = str_slug($request->title);
$BlogPosts->short_description = $request->short_description;
$BlogPosts->post_content = json_encode($request->post_content);
$BlogPosts->featured_image = $request->featured_image;
$BlogPosts->status = $request->status;
$BlogPosts->BlogCategories()->attach($request->blog_categories_id);
$BlogPosts->save();
return $BlogPosts::create($request->all());
}
BlogPostsModel.php
class BlogPosts extends Model{
public $table = 'blog_posts';
const CREATED_AT = 'created_at';
const UPDATED_AT = 'updated_at';
protected $dates = ['deleted_at'];
public $fillable = [
'tutor_id',
'title',
'slug',
'short_description',
'post_content',
'featured_image',
'status'
];
/**
* The attributes that should be casted to native types.
*
* #var array
*/
protected $casts = [
'id' => 'integer',
'tutor_id' => 'integer',
'title' => 'string',
'slug' => 'string',
'short_description' => 'string',
'post_content' => 'string',
'featured_image' => 'string',
'status' => 'string'
];
/**
* Validation rules
*
* #var array
*/
public static $rules = [
];
/**
* #return \Illuminate\Database\Eloquent\Relations\BelongsTo
**/
public function tutor()
{
return $this->belongsTo(\App\Models\Tutor::class);
}
public function BlogCategories(){
return $this->belongsToMany(BlogCategories::class);
}
// Category.php
public function BlogPosts(){
return $this->hasMany(BlogPosts::class);
}
}
BlogCategoryBlogPost.php
Schema::create('blog_categories_blog_posts', function(Blueprint $table) {
$table->integer('blog_categories_id')->unsigned();
$table->integer('blog_posts_id')->unsigned();
$table->foreign('blog_categories_id')->references('id')->on('blog_categories')->onUpdate('cascade')->onDelete('cascade');
$table->foreign('blog_posts_id')->references('id')->on('blog_posts')->onUpdate('cascade')->onDelete('cascade');
});
API Response
Please find the screenshot for API response
You should save model before set relations, otherwise model doesn't have primary key (id) to set relations.
Better to use sync with belongsToMany relations (conveniently to update).
You should return saved model, now you create duplicate and return it.
Category belongsToMany Posts, and Post belongsToMany Categories.
Controller:
public function store(Request $request)
{
$BlogPosts = new BlogPosts;
$BlogPosts->tutor_id = $request->user()->tutor->id;
$BlogPosts->title = $request->title;
$BlogPosts->slug = str_slug($request->title);
$BlogPosts->short_description = $request->short_description;
$BlogPosts->post_content = json_encode($request->post_content);
$BlogPosts->featured_image = $request->featured_image;
$BlogPosts->status = $request->status;
$BlogPosts->save();
$BlogPosts->BlogCategories()->sync($request->blog_categories_id);
return $BlogPosts;
}
BlogPosts model:
public function BlogCategories(){
return $this->belongsToMany(BlogCategories::class, 'blog_categories_blog_posts');
}
BlogCategories model:
public function BlogPosts(){
return $this->belongsToMany(BlogPosts::class, 'blog_categories_blog_posts');
}

Laravel : How to get the first record of each collections in a 'with' function query

I want to get a collection of all artists with their latest image only.
The following code returns a collection of all artists but with only one image associated with the first artist.
$data = Artist::with(['images' => function($q){
$q->first();
}])
->get();
return $data;
My models:
class Artist extends Model {
public function images()
{
return $this->belongsToMany('App\Image');
}
}
class Image extends Model {
public function artists()
{
return $this->belongsToMany('App\Artist');
}
}
You can set in you modal:
public function FirstImage()
{
return $this->hasOne('image');
}
then:
$data = Artist::with('FirstImage')->get();

Phalcon keep a model persistant in all the controllers?

my website application is mostly model around a User Model which has all the key data that needed for most of the times.
Once the user is logged into the website I would like to keep it as a persistent variable across all the controllers. How do i achieve this as i cannot use session to hold a class object of Type Model.
My application is based on phalcon. However any suggestions are welcome.
I suggest you to write a simple class for user authentication & other user data manipulation, i wrote this Component and using in my project :
use Phalcon\Mvc\User\Component;
class Auth extends Component {
public function login($credentials) {
if(!isset($credentials['email'],$credentials['password'])) {
return FALSE;
}
if($this->isAuthorized()) {
return true;
}
$user = Users::findFirstByEmail($credentials['email']);
if($user == false) {
//block user for seconds
return false;
}
if($this->security->checkHash($credentials['password'],$user->password) && $user->status == 1) {
$this->_saveSuccessLogin($user);
$this->_setUserLoginSession($user);
return true;
} else {
return false;
}
}
public function isAuthorized() {
return $this->session->has('auth');
}
public function logout() {
$this->session->remove('auth');
return true;
}
public function user($key = null) {
if(!$this->isAuthorized()) {
return null;
}
if(is_null($key)) {
return $this->session->get('auth');
} else {
$user = $this->session->get('auth');
return array_key_exists($key, $user) ? $user[$key] : null;
}
}
private function _saveSuccessLogin(Users $user){
$userLogin = new UserLogins();
$userLogin->user_id = $user->id;
$userLogin->ip = $this->request->getClientAddress();
$userLogin->user_agent = $this->request->getUserAgent();
$userLogin->dns = gethostbyaddr($userLogin->ip);
if(!$userLogin->save()) {
return false;
}
return true;
}
private function _setUserLoginSession(Users $user) {
if(!$user) {
return false;
}
$this->session->set('auth',array(
'id' => $user->id,
'firstname' => $user->firstname,
'lastname' => $user->lastname,
'email' => $user->email,
'role_id' => $user->role_id
));
return true;
}
}
And in my services.php added into DI with this code :
$di->setShared('auth', function () {
return new Auth();
});
So when i want to get user info i use this :
$this->auth->user('email')
Also you can add more functionality to this component & modify it.
I hope that's useful for You.
You can use memcached and save it as key => value:
userId => serialized User model

Edit profile page with 3 tables - Yii frameworks

I am new on Yii framework, so please i need some help where to start.
What i need is, action and module to display a form to a user, which his will be able to edit is own profile (with profile picture), so i have 3 table
user_account || user_personal || user_general
how can i build a form that insert and update those 3 table at once?
i try this:
This is what i did, but its still not saving the data even into 1 table.
public function actionUpdate() {
$model = new ProfileUpdate();
if(isset($_POST['ProfileUpdate']))
{
$model->attributes = $_POST['ProfileUpdate'];
if($model->validate())
{
$account = new Profile();
$account->userid = Yii::app()->user->id;
$account->name = $model->name;
$account->website = $model->website;
$account->category = $model->category;
$account->save();
$this->redirect('profile');
}
}
model:
class Profile extends CActiveRecord
{
public $userid;
public $name;
public $website;
public $category;
public static function model()
{
return parent::model(__CLASS__);
}
public function tableName()
{
return 'userinfo';
}
public function primaryKey()
{
return 'id';
}
public static function userExists($user)
{
return self::model()->countByAttributes( array('username'=>$user) ) > 0;
}
}
You can use all three models in a single function
for example:
In create function
$model_account = new user_account;
$model_personal= new user_personal;
$model_general = new user_general;
$this->render('create',array(
'model_account'=>$model_account, 'model_personal' => $model_personal, 'model_general' => $model_general
));
here the all three models pass by render to create page.
in form page you can use the every model attributes as fields
Like this
echo $form->textField($model_account,'account_name');
echo $form->textField($model_personal,'email');
echo $form->textField($model_general,'address');
In create function / Update function
$model_account->attributes = $_POST['user_account'];
$model_personal->attributes = $_POST['user_personal'];
$model_general->attributes = $_POST['user_general'];
if($model_account->validate() && $model_personal->validate() && $model_general->validate())
{
$model_account->save();
$model_personal->save();
$model_general->save();
}