Creating a one-to-many relationship in Yii2 - yii2

Let's say we have two entities: User and Post.
In my understanding, in order to have a one-to-many relationship between User and Post, you need to do the following:
class User {
...
public function getPosts()
{
return $this->hasMany(Order::className(), ['user_id' => 'id']);
}
}
class Post {
...
public function getUser()
{
return $this->hasOne(Order::className(), ['id' => 'user_id']);
}
}
Is this right? Is there anything else I need to add in order to make everything work? The Yii2 documentation is not very clear to me.

Yes, this is enough (except that you inserted Order class name instead), however it's also recommended to add PHPDoc for relations:
User model:
/**
* ...
*
* #property Post[] $posts
*/
class User
{
/**
* #return \yii\db\ActiveQuery
*/
public function getPosts()
{
return $this->hasMany(Post::className(), ['user_id' => 'id']);
}
}
Post model:
/**
* ...
*
* #property User $user
*/
class Post
{
/**
* #return \yii\db\ActiveQuery
*/
public function getUser()
{
return $this->hasOne(User::className(), ['id' => 'user_id']);
}
}
Then when you will call $user->posts or $post->user you will get full autocomplete if you are using IDE. It's also useful because you can see the relation list just by looking at the top of the file, because relations accessed as virtual properties, $user->getPosts() call will return yii\db\ActiveQuery object and not \yii\db\ActiveRecord array. It's better to separate them with linebreak from model attributes (they are also added for autocomplete and seeing the structure of according database table without looking at database).
By the way, if you generate model with Gii, if you specified foreign keys correctly, relations and PHPDoc will be generated automatically.
Note that if you don't need to use $post->user, you can omit user relation declaration in Post model. You can declare relations that are only needed for usage.

Related

Yii2: Why in the beforeDelete method, does the hasMany return a null?

I'm trying to delete related data that has a many-to-many relationship
My complex model:
/**
* #return \yii\db\ActiveQuery
*/
public function getComplexDocument()
{
return $this->hasMany(ComplexDocument::className(), ['complex_id' => 'id']);
}
/**
* #return \yii\db\ActiveQuery
*/
public function getDocuments()
{
return $this->hasMany(Documents::className(), ['id' => 'document_id'])
->via('complexDocument');
}
In beforeDelete I do the following:
public function beforeDelete()
{
foreach ($this->documents as $document){
var_dump($document);
}
return parent::beforeDelete();
}
Deletion does not happen, I checked and all hasMany connections return NULL.
In debug I see the following
I did this way:
public function delete()
{
foreach ($this->documents as $document){
$document->delete();
}
return parent::delete(); // TODO: Change the autogenerated stub
}
Everything works, all related documents are deleted, but it seems strange to me. In fact, this should be in beforeDelete (), but why are not links returned and therefore not deleted, so it should be, or is it a shortage of the framework?

Having a challenge with Laravel 5.4 requests namespace

I'm trying to reference the Requests class in Laravel, I've tried so many fixes with the keyword "use" but each time I keep getting Reflection exception
that says app\path\specified doesn't exist. I'm confused.
Here is my code:`
<?php
namespace App\Http\Controllers;
//namespace App\Http\Request;
//use Illuminate\Http\Requests;
//use app\Http\Requests\ContactFormRequest;
use App\Message;
use App\Mail\SendMessage;
use Session;
//use App\Requests;
class AboutController extends Controller
{
public function create()
{
return view ('about.contact');
}
public function store(App\Requests\SendMessageRequest $request)
{
$message = $request->message;
Mail::to('myemail')
->send(new SendMessage($message, $request->email,$request->name));
THE REQUESTS CLASS
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class SendMessageRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return false;
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
//
'name' => 'required',
'email' => 'required|email',
"message" => 'required',
];
}
}
The commented line(//) are what I've tried
SendMessageRequest is the name of my Request class.
Sorry, I canĀ“t comment your post. However can you also send the SendMessageRequest Class? Is that a subclass of the Request in Laravel?

How to extend a model that is part of an Yii2 extension?

In my application I'm using an extension (which I own and may modify). This extension has an ActiveRecord based class that I want to extend in the application with another property. Can I do this somehow? Can a Factory help anyhow or Yii behaviour?
Class in extension:
namespace extension;
/**
* #property integer $id
* #property string $name
*/
class Product extends ActiveRecord {
public static function tableName() {
return 'product';
}
/**
* #inheritdoc
*/
public function rules() {
return [
[['id', 'name'], 'required'],
[['id'], 'integer'],
[['name'], 'string'],
];
}
}
There is also a ProductController and the corresponding view files (index, create, update, view, _form) in the extension which were regularly produced with gii. I just would like to add another property $description (string, required) to the Product. A migration in order to add the required column is available.
Do I have to overwrite the model and controller class and the view files? Or is the a more elegant solution?
E.g., consider the standard object creation that takes place within the extension:
public function actionCreate() {
$model = new Product();
if ($model->load(Yii::$app->request->post()) && $model->save()) {
return $this->redirect(['view', 'language' => $model->language]);
} else {
return $this->render('create', [
'model' => $model,
]);
}
}
From my understanding I cannot influence the creation. Or am I wrong?
My impression is that I have to override everything (also the view files since the property has to be displayed) and then change controllerNamespace.
As far as extending a class, just go ahead and add the property. Your new class will have inherited everything from the parent class plus have your new property.
Concerning overwriting the generated files, there is a diff option in gii when you generate the files, so you can preview and decide what to keep and what to overwrite. Be aware that you have to merge any changes manually however.

Validating JSON input Laravel

I am using laravel , and json input from the client. I would like to know if there is a way to create a form request that does json validation instead of url parameters. I found this class online :
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
abstract class JsonRequest extends FormRequest {
/**
* Get the validator instance for the request.
*
* #return \Illuminate\Validation\Validator
*/
protected function getValidatorInstance()
{
$factory = $this->container->make('Illuminate\Validation\Factory');
if (method_exists($this, 'validator'))
{
return $this->container->call([$this, 'validator'], compact('factory'));
}
return $factory->make(
$this->json()->all(), $this->container->call([$this, 'rules']), $this->messages(), $this->attributes()
);
}
}
Now , when I make a class that extends this instead of Request, I am able to validate. This is an example:
<?php
namespace App\Http\Requests;
use App\Http\Middleware\AuthTokenMiddleware;
use App\Http\Requests\Request;
use Illuminate\Support\Facades\Input;
class VotesCreateRequest extends JsonRequest
{
public function response(array $errors)
{
//
return response()->json(["error_list" => $errors], 200);
}
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{return true;
if(AuthTokenMiddleware::getUser()->can('access-group',Input::get("grp_id"))){
return true;
}
else{
return false;
}
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'sub_items'=>'required|array',
'sub_items.*.email' =>'required'
];
}
}
But I want to know how to validate items inside items of the json file .
For example, i have :
{"sub_items":["something","another thing","yet another","another ","last"]}
How do I validate if all these items in sub sub_items are of type email ?

How to Extend Yii2-user dektrium profile model to be able to adding more fields

I need to override the default Profile model. I have managed to add the fields i need but there is something i am missing since. On insert and update these fields are not getting update to the database.
I have created the necessary migrations so i have these fields in the database already
What am i missing> see below my app/models/Profile.php
<?php
namespace app\models;
/**
* Description Profile
*
* This form #overrides dektrium\user\models\Profile
*/
use dektrium\user\models\Profile as BaseProfile;
use yii\web\UploadedFile;
use Yii;
use dektrium\user\models\User;
class Profile extends BaseProfile {
/**
* public variables to be added to the model
*/
public $profile_pic;
public $expertise_id;
public $country_id;
public function rules() {
$rules = parent::rules();
$rules['profile_pic'] = ['profile_pic', 'file'];
$rules['expertise_id'] = ['expertise_id', 'integer'];
$rules['country_id'] = ['country_id', 'integer'];
return $rules;
}
/**
* #inheritdoc
*/
public function attributeLabels() {
$labels = parent::attributeLabels();
$labels['profile_pic'] = \Yii::t('user', 'Profile Picture');
$labels['bio'] = \Yii::t('user', 'Biography');
$labels['expertise_id'] = \Yii::t('user', 'Expertise');
$labels['country_id'] = \Yii::t('user', 'Country');
return $labels;
}
}
First thing, remove this lines:
public $profile_pic;
public $expertise_id;
public $country_id;
If you already added those fields in the table, you dont need to declare them. As you can see, none of the others properties are being declared either. This is already being done by extending the model from ActiveRecord and declaring the tableName