I have a function in model
public static function updateDetail($model)
{
$model->username = $model->partnerApiDetail->username;
$model->password = $model->partnerApiDetail->password;
}
username and password are public properties in partner table
PatnerApiDetail is relation of Partner table with partner_api_detail
table.
Why phpstorm haven't find the relation both show the error
$model-username(field declared dynamically error)
$model->partnerApiDetail->username(field partnerAapiDetail not found)
What i have to do actually to override the error
<?php
namespace common\models;
use Yii;
use yii\db\Expression;
/**
* This is the model class for table "ad_partner_api_detail".
*
* #property int $id
* #property string $username
* #property string $password
* #property string $access_token
* #property bool $is_deleted
* #property int $is_active
* #property int $created_by
* #property int $updated_by
* #property string $created_at
* #property string $updated_at
* #property int $ad_partner_id
*
* #property Partner $Partner
*/
class PartnerApiDetail extends \yii\db\ActiveRecord
{
const statusDeleted = false;
const statusActive = 1;
/**
* {#inheritdoc}
*/
public static function tableName()
{
return 'ad_partner_api_detail';
}
/**
* {#inheritdoc}
*/
public function rules()
{
return [
[['is_deleted'], 'boolean'],
[['is_active', 'created_by', 'updated_by', 'ad_partner_id'], 'integer'],
[['created_at', 'updated_at'], 'safe'],
[['ad_partner_id'], 'required'],
[['username', 'password', 'access_token'], 'string', 'max' => 255],
[['ad_partner_id'], 'exist', 'skipOnError' => true, 'targetClass' => Partner::class, 'targetAttribute' => ['ad_partner_id' => 'id']],
['is_active', 'default', 'value' => self::statusActive],
['is_deleted', 'default', 'value' => self::statusDeleted],
];
}
/**
* {#inheritdoc}
*/
public function attributeLabels()
{
return [
'id' => Yii::t('app', 'ID'),
'username' => Yii::t('app', 'Username'),
'password' => Yii::t('app', 'Password'),
'access_token' => Yii::t('app', 'Access Token'),
'is_deleted' => Yii::t('app', 'Is Deleted'),
'is_active' => Yii::t('app', 'Status'),
'created_by' => Yii::t('app', 'Created By'),
'updated_by' => Yii::t('app', 'Updated By'),
'created_at' => Yii::t('app', 'Created At'),
'updated_at' => Yii::t('app', 'Updated At'),
'ad_partner_id' => Yii::t('app', 'Partner Name'),
];
}
/**
* {#BlameableBehavior}
*/
public function behaviors()
{
return [
[
'class' => 'yii\behaviors\BlameableBehavior',
'createdByAttribute' => 'created_by',
'updatedByAttribute' => 'updated_by',
],
[
'class' => 'yii\behaviors\TimestampBehavior',
'createdAtAttribute' => 'created_at',
'updatedAtAttribute' => 'updated_at',
'value' => new Expression('NOW()'),
],
];
}
/**
* #return \yii\db\ActiveQuery
*/
public function getPartner()
{
return $this->hasOne(Partner::class, ['id' => 'ad_partner_id']);
}
}
I have found the solution myself
Baically yii defined the property of relation with capital letter at the start
like here
* #property PartnerApiDetail[] $PartnerApiDetail
for this rlation
/**
* #return \yii\db\ActiveQuery
*/
public function getPartnerApiDetail()
{
return $this->hasOne(PartnerApiDetail::class, ['ad_partner_id' => 'id']);
}
You just need to small the first letter
* #property PartnerApiDetail[] $partnerApiDetail
Working like cham
Related
i want to use sub fillable array in model
protected $fillable = [
'requestInfo'=>[
'companyname',
'province',
'district',
'village',
'phone',
],
'owner'=>[
'fullname',
'province',
'district',
'village',
'nationality',
'fax',
'phone',
'factorynamela',
'factorynameen',
'located',
'locatprovince',
'locatdistrict',
'locatvillage',
'locatein'
],
];
but have error:
C:\xampp\htdocs\mocbizrrequest\blog\vendor\laravel\framework\src\Illuminate\Database\Eloquent\Concerns\GuardsAttributes.php
/**
* Determine if the model is totally guarded.
*
* #return bool
*/
public function totallyGuarded()
{
return count($this->getFillable()) == 0 && $this->getGuarded() == ['*'];
}
/**
* Get the fillable attributes of a given array.
*
* #param array $attributes
* #return array
*/
protected function fillableFromArray(array $attributes)
{
if (count($this->getFillable()) > 0 && ! static::$unguarded) {
return array_intersect_key($attributes, array_flip($this->getFillable()));
}
return $attributes;
}
}
Arguments
"array_flip(): Can only flip STRING and INTEGER values!"
ErrorException (E_WARNING)
array_flip(): Can only flip STRING and INTEGER values!
please help me thank
i want to use sub fillable array in model
in my model file
<?php
/**
* Created by IntelliJ IDEA.
* User: EXTRA
* Date: 4/5/2019
* Time: 11:48 AM
*/
namespace App\Model;
use Jenssegers\Mongodb\Eloquent\Model as Eloquent;
class RequestFrom extends Eloquent
{
protected $connection = 'mongodb';
protected $collection = 'requestForm';
protected $fillable = [
'requestInfo'=>[
'companyname',
'province',
'district',
'village',
'phone',
],
'owner'=>[
'fullname',
'province',
'district',
'village',
'nationality',
'fax',
'phone',
'factorynamela',
'factorynameen',
'located',
'locatprovince',
'locatdistrict',
'locatvillage',
'locatein'
],
];
in controller file
namespace App\Http\Controllers;
use App\Model\RequestFrom;
use Illuminate\Http\Request;
class RequestFromController extends Controller
{
public function index()
{
$requestForms = RequestFrom::all();
return view('requestForm.index',compact('requestForms'))
->with('i', (request()->input('page', 1) - 1) * 5);
}
public function create()
{
return view('requestForm.create');
}
/**
* Store a newly created resource in storage.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function store(Request $request)
{
request()->validate([
'requestInfo'=>[
'companyname' => 'required',
'province' => 'required',
'district' => 'required',
'village' => 'required',
'phone' => 'required'
],
'owner'=>[
'fullname' => 'required',
'province' => 'required',
'district' => 'required',
'village' => 'required',
'nationality' => 'required',
'fax' => 'required',
'phone' => 'required',
'factorynamela' => 'required',
'factorynameen' => 'required',
'located' => 'required',
'locatprovince' => 'required',
'locatdistrict' => 'required',
'locatvillage' => 'required',
'locatein' => 'required'
],
]);
RequestFrom::create($request->all());
return redirect()->route('requestForm.index')
->with('success','created successfully.');
}
I've read all the Yii2 Framework documentation but it's confusing when trying to implement it.
I have a view of Customer where it shows all the fields in customer table, including the address_id field in the address table.
I want to implement a join query using MySQL in the Yii2 Framework but the generated code is the following:
CustomerSearch in the models:
class CustomerSearch extends Customer{
/**
* {#inheritdoc}
*/
public function rules()
{
return [
[['customer_id', 'store_id', 'address_id', 'active'], 'integer'],
[['first_name', 'last_name', 'email', 'create_date', 'last_update'], 'safe'],
];
}
/**
* {#inheritdoc}
*/
public function scenarios()
{
// bypass scenarios() implementation in the parent class
return Model::scenarios();
}
/**
* Creates data provider instance with search query applied
*
* #param array $params
*
* #return ActiveDataProvider
*/
public function search($params)
{
$query = Customer::find();
// add conditions that should always apply here
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
$this->load($params);
if (!$this->validate()) {
// uncomment the following line if you do not want to return any records when validation fails
// $query->where('0=1');
return $dataProvider;
}
// grid filtering conditions
$query->andFilterWhere([
'customer_id' => $this->customer_id,
'store_id' => $this->store_id,
'address_id' => $this->address_id,
'active' => $this->active,
'create_date' => $this->create_date,
'last_update' => $this->last_update,
]);
$query->andFilterWhere(['like', 'first_name', $this->first_name])
->andFilterWhere(['like', 'last_name', $this->last_name])
->andFilterWhere(['like', 'email', $this->email]);
return $dataProvider;
}
Customer class:
class Customer extends \yii\db\ActiveRecord{
/**
* {#inheritdoc}
*/
public static function tableName()
{
return 'customer';
}
/**
* {#inheritdoc}
*/
public function rules()
{
return [
[['store_id', 'first_name', 'last_name', 'address_id'], 'required'],
[['store_id', 'address_id', 'active'], 'integer'],
[['create_date', 'last_update'], 'safe'],
[['first_name', 'last_name'], 'string', 'max' => 45],
[['email'], 'string', 'max' => 50],
];
}
/**
* {#inheritdoc}
*/
public function attributeLabels()
{
return [
'customer_id' => 'Customer ID',
'store_id' => 'Store ID',
'first_name' => 'First Name',
'last_name' => 'Last Name',
'email' => 'Email',
'address_id' => 'Address ID',
'active' => 'Active',
'create_date' => 'Create Date',
'last_update' => 'Last Update',
];
}
}
You need to declare some relations in your ActiveRecord models...
See here in the official docs for Working with Relational Data
If you are storing the address_id in your customer table then you will be tied to each customer having 1 single address (i.e. a one-to-one relationship), which is a rather bad design. Or you could use a junction table. You are better off storing the customer_id in each address record and defining a one-to-many relation, enabling each customer to store multiple addresses (more like in real life, i.e. for home, work address etc).
For example, in your Customer model, you would define a has-many relation for customer addresses:
use app\models\Address;
class Customer extends \yii\db\ActiveRecord
{
/**
* {#inheritdoc}
*/
public static function tableName()
{
return 'customer';
}
/**
* {#inheritdoc}
*/
public function rules()
{
return [
[['store_id', 'first_name', 'last_name', 'primary_address_id'], 'required'],
[['store_id', 'primary_address_id', 'active'], 'integer'],
[['create_date', 'last_update'], 'safe'],
[['first_name', 'last_name'], 'string', 'max' => 45],
[['email'], 'string', 'max' => 50],
];
}
/**
* {#inheritdoc}
*/
public function attributeLabels()
{
return [
'customer_id' => 'Customer ID',
'store_id' => 'Store ID',
'first_name' => 'First Name',
'last_name' => 'Last Name',
'email' => 'Email',
'primary_address_id' => 'Primary Address ID',
'active' => 'Active',
'create_date' => 'Create Date',
'last_update' => 'Last Update',
];
}
/**
* #return \yii\db\ActiveQuery
*/
public function getAddresses()
{
return $this->hasMany(Address::className(), ['customer_id' => 'id']);
}
}
And in your Address model you would have the inverse has-one relation defined:
/**
* #return \yii\db\ActiveQuery
*/
public function getCustomer()
{
return $this->hasOne(Customer::className(), ['id' => 'customer_id']);
}
You can then Access relational data from model instances via defined relation names, for example:
// SELECT * FROM `customer` WHERE `id` = 123
$customer = Customer::findOne(123);
// SELECT * FROM `address` WHERE `customer_id` = 123
// $addresses is an array of Address objects
$addresses = $customer->addresses;
Also note, if you define proper primary/foreign keys in your schema, the Gii Model/CRUD generators will automatically create the boilerplate relations code in your models and CRUD files.
I have a database having relationship of three levels. cheque->account->customer. Now I am trying to retrieve data from all three table at same time using the following method.
$query = Cheque::find();
$query->joinWith(['account.customer']);
$query->orderBy('sr desc');
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
Cheque Model:
class Cheque extends \common\components\db\ActiveRecord {
/**
* #inheritdoc
*/
public static function tableName() {
return 'cheque';
}
/**
* #inheritdoc
*/
public function rules() {
return [
[['sr'], 'integer'],
[['ID', 'account_ID'], 'required'],
[['ID', 'account_ID', 'created_by', 'branch_ID', 'application_ID'], 'string'],
[['serial_start', 'serial_end', 'status'], 'number'],
[['created_on'], 'safe']
];
}
/**
* #inheritdoc
*/
public function attributeLabels() {
return [
'ID' => 'ID',
'account_ID' => 'Account ID',
'serial_start' => 'Serial Start',
'serial_end' => 'Serial End',
'created_on' => 'Created On',
'created_by' => 'Created By',
'branch_ID' => 'Branch ID',
'application_ID' => 'Application ID',
'status' => 'Status',
'sr' => 'ID'
];
}
/**
* #return \yii\db\ActiveQuery
*/
public function getAccount() {
return $this->hasOne(Account::className(), ['ID' => 'account_ID']);
}
public static function getActiveChequeBook($account_ID) {
return Cheque::findAll(['account_ID' => $account_ID, 'status' => array_search('Active', \common\models\Lookup::$cheque_status)]);
}
}
But executing this I get the following error:
pre>Exception 'yii\base\InvalidCallException' with message 'Setting read-only property: common\models\Account::customer'
Property customer in your common\models\Account model has no setter (only getCustomer method exists). Check you model and add appropriate property to class.
I have 2 Doctrine entities (Environment and EnvironmentConfig). They have a bi-directional OneToOne relationship.
Each entity has their own Fieldset so that re-use is easy.
To create an Environment it can also have an EnvironmentConfig, however not required. To allow them to be made at the same time I have an EnvironmentForm that uses the EnvironmentFieldset and the EnvironmentConfigFieldset.
The Form renders properly. However, it saves the Environment but not the EnvironmentConfig.
Where is it that I've gone wrong in setting this up and how to fix it?
Code below, leaving out getters/setters, would be too much.
Entities
// abstract class AbstractEntity has $id + getters/setters.
class Environment extends AbstractEntity
{
/**
* #var string
* #ORM\Column(name="name", type="string", length=255, nullable=false)
*/
protected $name;
/**
* #var EnvironmentConfig
* #ORM\OneToOne(targetEntity="Environment\Entity\EnvironmentConfig", inversedBy="environment")
*/
protected $config;
/**
* #var EnvironmentScript
* #ORM\OneToOne(targetEntity="EnvironmentScript")
*/
protected $script;
//Getters/setters
}
class EnvironmentConfig extends AbstractEntity
{
/**
* #var string
* #ORM\Column(name="name", type="string", length=255, nullable=false)
*/
protected $name;
/**
* #var Environment
* #ORM\OneToOne(targetEntity="Environment\Entity\Environment", mappedBy="config")
*/
protected $environment;
//Getters/setters
}
Fieldsets
class EnvironmentFieldset extends AbstractFieldset
{
/**
* {#inheritdoc}
*/
public function init()
{
//Loads id element validation
parent::init();
$this->add([
'name' => 'name',
'type' => Text::class,
'options' => [
'label' => _('Name'),
'label_attributes' => [
'class' => 'col-xs-2 col-form-label',
],
],
'attributes' => [
'id' => 'name',
'class' => 'form-control'
],
]);
$this->add([
'name' => 'environment_config',
'type' => EnvironmentConfigFieldset::class,
'options' => [
'use_as_base_fieldset' => false,
],
]);
$this->add([
'type' => ObjectSelect::class,
'name' => 'environment_script',
'options' => [
'object_manager' => $this->getEntityManager(),
'target_class' => EnvironmentScript::class,
'property' => 'id',
'display_empty_item' => true,
'empty_item_label' => '---',
'label_generator' => function ($targetEntity) {
return $targetEntity->getId() . ' - ' . $targetEntity->getName();
},
],
]);
}
}
class EnvironmentConfigFieldset extends AbstractFieldset
{
/**
* {#inheritdoc}
*/
public function init()
{
//Loads id element validation
parent::init();
$this->add([
'name' => 'name',
'type' => Text::class,
'options' => [
'label' => _('Name'),
'label_attributes' => [
'class' => 'col-xs-2 col-form-label',
],
],
'attributes' => [
'id' => 'name',
'class' => 'form-control'
],
]);
}
}
Form
class EnvironmentForm extends AbstractForm
{
/**
* EnvironmentForm constructor.
* #param null $name
* #param array $options
*/
public function __construct($name = null, array $options)
{
//Also adds CSRF
parent::__construct($name, $options);
}
/**
* {#inheritdoc}
*/
public function init()
{
//Call parent initializer. Adds submit button.
parent::init();
$this->add([
'name' => 'environment',
'type' => EnvironmentFieldset::class,
'options' => [
'use_as_base_fieldset' => true,
],
]);
}
}
Edit: added debug data and AddAction()
Above debugging done on the persist() line in the function below.
public function addAction($formName, array $formOptions = null, $route, array $routeParams = [])
{
if (!$this->formElementManager instanceof FormElementManagerV2Polyfill) {
throw new InvalidArgumentException('Dependency FormElementManagerV2Polyfill not set. Please check Factory for this function.');
}
if (!class_exists($formName)) {
throw new ClassNotFoundException('Given class could not be found. Does it exist?');
}
/** #var AbstractForm $form */
$form = $this->getFormElementManager()->get($formName, (is_null($formOptions) ? [] : $formOptions));
/** #var Request $request */
$request = $this->getRequest();
if ($request->isPost()) {
$form->setData($request->getPost());
if ($form->isValid()) {
$entity = $form->getObject();
$this->getEntityService()->getEntityManager()->persist($entity);
$this->getEntityService()->getEntityManager()->flush();
$this->flashMessenger()->addSuccessMessage(
_('Successfully created object.')
);
$this->redirectToRoute($route, $this->getRouteParams($entity, $routeParams));
}
}
return [
'form' => $form,
'validationMessages' => $form->getMessages() ?: '',
];
}
You created a field called 'environment_config' but in class Environment you called protected $config;. Both names must be the same. Same problem for 'environment_script' field and $script attribute.
Another thing, you want to create a EnvironmentConfig dynamically so you must add in $config annotation a cascade option to be able to create a $config from Environment:
/**
* #var EnvironmentConfig
* #ORM\OneToOne(targetEntity="Environment\Entity\EnvironmentConfig", inversedBy="environment", cascade={"persist"})
*/
protected $config;
I want to display data relation by making a relation between table alumniintegrasi with alumnys2, but when I made it with gridview, there was an error.
it said '
getting unknown property: app\models\AlumnyS2::alumniintegrasi.
here is the code
<?php
use yii\helpers\Html;
use yii\grid\GridView;
use app\models\AlumniIntegrasi;
/* #var $this yii\web\View */
/* #var $searchModel app\models\AlumnyS2Search */
/* #var $dataProvider yii\data\ActiveDataProvider */
$this->title = Yii::t('app', 'Alumny S2s');
$this->params['breadcrumbs'][] = $this->title;
?>
<div class="alumny-s2-index">
<h1><?= Html::encode($this->title) ?></h1>
<?php // echo $this->render('_search', ['model' => $searchModel]); ?>
<p>
<?= Html::a(Yii::t('app', 'Create Alumny S2'), ['create'], ['class' => 'btn btn-success']) ?>
</p>
<?= GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'columns' => [
['class' => 'yii\grid\SerialColumn'],
'NRP',
//'NamaMahasiswa',
[
'attribute' => 'NamaMahasiswa',
'value' => function($data) {
return $data->alumniintegrasi->NamaMahasiswa;
},
/*'filter' => Html::activeDropDownList($searchModel, 'orang_ID', ArrayHelper::map(Orang::find()->asArray()->all(), 'ID', 'Nama'),['class'=>'form-control','prompt' => 'Select Category']),
*/
],
'ProgramStudi',
'Tanggal_Masuk',
'Tanggal_Lulus',
['class' => 'yii\grid\ActionColumn'],
],
]); ?>
</div>
and here is the model
<?php
namespace app\models;
use Yii;
/**
* This is the model class for table "alumnys2".
*
* #property string $NRP
* #property string $NamaMahasiswa
* #property string $ProgramStudi
* #property string $Tanggal_Masuk
* #property string $Tanggal_Lulus
*
* #property AlumniIntegrasi $nRP
*/
class AlumnyS2 extends \yii\db\ActiveRecord
{
/**
* #inheritdoc
*/
public static function tableName()
{
return 'alumnys2';
}
/**
* #inheritdoc
*/
public function rules()
{
return [
[['NRP', 'NamaMahasiswa'], 'required'],
[['NRP'], 'string', 'max' => 15],
[['NamaMahasiswa'], 'string', 'max' => 50],
[['ProgramStudi'], 'string', 'max' => 5],
[['Tanggal_Masuk', 'Tanggal_Lulus'], 'string', 'max' => 30],
[['NRP'], 'exist', 'skipOnError' => true, 'targetClass' => AlumniIntegrasi::className(), 'targetAttribute' => ['NRP' => 'NRP']],
];
}
/**
* #inheritdoc
*/
public function attributeLabels()
{
return [
'NRP' => Yii::t('app', 'Nrp'),
'NamaMahasiswa' => Yii::t('app', 'Nama Mahasiswa'),
'ProgramStudi' => Yii::t('app', 'Program Studi'),
'Tanggal_Masuk' => Yii::t('app', 'Tanggal Masuk'),
'Tanggal_Lulus' => Yii::t('app', 'Tanggal Lulus'),
];
}
/**
* #return \yii\db\ActiveQuery
*/
public function getNRP()
{
return $this->hasOne(AlumniIntegrasi::className(), ['NRP' => 'NRP']);
}
}
I want to display NamaMahasiswa in table alumniintegrasi. how can I fix that?
You should use a proper getter for the field NamaMahasiswa
in your model
change the name of model getter (aviding case convention problem for name
/**
* #return \yii\db\ActiveQuery
*/
public function getNrp()
{
return $this->hasOne(AlumniIntegrasi::className(), ['NRP' => 'NRP']);
}
and add the getter simply use the attribute name (based on getter)
/* Getter for NamaMahasiswa */
public function getNamaMahasiswa() {
return $this->Nrp->NamaMahasiswa;
}
in the view
<?= GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'columns' => [
['class' => 'yii\grid\SerialColumn'],
[
'attribute' => 'namaMahasiswa',
],
'ProgramStudi',
'Tanggal_Masuk',
'Tanggal_Lulus',
['class' => 'yii\grid\ActionColumn'],
],
]); ?>
NB using UpperCamleCase ( Pascal Notation) for database name is not the best choice .. for database is better use underscore notattion ..