Yii: change active record field names - yii

I'm new to Yii and I have a table 'Student' with fields like 'stdStudentId', 'stdName', etc.
I'm making API, so this data should be returned in JSON. Now, because I want field names in JSON to just be like 'id', 'name', and I don't want all fields returned, i made a method in the model:
public function APIfindByPk($id){
$student = $this->findByPk($id);
return array(
'id'=>$student->stdStudentId,
'name'=>$student->stdName,
'school'=>$student->stdSchool
);
}
The problem is, stdSchool is a relation and in this situation, $student->stdSchool returns array with fields like schSchoolId, schName, etc. I don't want fields to be named like that in JSON, and also I don't want all the fields from School returned and I would like to add some fields of my own. Is there a way to do this in Yii, or I'll have to do it manually by writing methods like this?

I have been looking for the same thing. There is a great php lib named Fractal letting you achieve it: http://fractal.thephpleague.com/
To explain briefly the lib, for each of your models you create a Transformer that will be doing the mapping between your model attributes and the ones that need to be exposed using the api.
class BookTransformer extends Fractal\TransformerAbstract
{
public function transform(Book $book)
{
return [
'id' => (int) $book->id,
'title' => $book->title,
'year' => $book->yr,
];
}
}
In the transformer you can also set the relation that this model have :
class BookTransformer extends TransformerAbstract
{
/**
* List of resources relations that can be used
*
* #var array
*/
protected $availableEmbeds = [
'author'
];
/**
* Turn this item object into a generic array
*
* #return array
*/
public function transform(Book $book)
{
return [
'id' => (int) $book->id,
'title' => $book->title,
'year' => $book->yr,
];
}
/**
* Here we are embeding the author of the book
* using it's own transformer
*/
public function embedAuthor(Book $book)
{
$author = $book->author;
return $this->item($author, new AuthorTransformer);
}
}
So at the end you will call
$fractal = new Fractal\Manager();
$resource = new Fractal\Resource\Collection($books, new BookTransformer);
$json = $fractal->createData($resource)->toJson();
It's not easy to describe all the potential of fractal in one answer but you really should give it a try.
I'm using it along with Yii so if you have some question don't hesitate!

Since you are getting the values from the database using Yii active record, ask the database to use column aliases.
Normal SQL would be something like the following :
SELECT id AS Student_Number, name AS Student_Name, school AS School_Attending FROM student;
In Yii, you can apply Criteria to the findByPK() function. See here for reference : http://www.yiiframework.com/doc/api/1.1/CActiveRecord#findByPk-detail
$criteria = new CDbCriteria();
$criteria->select = 'id AS Student_Number';
$student = Student::model()->findByPk($id, $criteria);
Note that in order to use a column alias like that, you will have to define a virtual attribute Student_Number in your Student{} model.

Override the populateRecord() function of ActiveRecord can achieve this!
My DishType has 5 properties and override the populateRecord function Yii would invoke this when records fetched from db.
My code is here!
class DishType extends ActiveRecord
{
public $id;
public $name;
public $sort;
public $createTime;
public $updateTime;
public static function populateRecord($record, $row)
{
$pattern = ['id' => 'id', 'name' => 'name', 'sort' => 'sort', 'created_at' => 'createTime', 'updated_at' => 'updateTime'];
$columns = static::getTableSchema()->columns;
foreach ($row as $name => $value) {
$propertyName = $pattern[$name];
if (isset($pattern[$name]) && isset($columns[$name])) {
$record[$propertyName] = $columns[$name]->phpTypecast($value);
}
}
parent::populateRecord($record, $row);
}
}

Related

Laravel Excel cannot update records "WithUpserts" - error update

I face various issues while updating my existing table. I need to update the price field in my table, but I get an error in my code that I can't find. Even if I remove the sku it goes to the next "qty" field and outputs undefined. "Undefined index: sku"
<?php
namespace App\Imports;
use App\Models\CatalogStore;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\WithUpserts;
class CatalogupdateImport implements ToModel, WithUpserts
{
/**
* #param array $row
*
* #return \Illuminate\Database\Eloquent\Model|null
*/
public function model(array $row)
{
return new CatalogStore([
'sku' => $row['sku'],
'price' => $row['price'],
'qty' => $row['qty'],
]);
}
/**
* #return string|array
*/
public function uniqueBy()
{
return 'price';
}
}

Laravel 8 factory class is not overriding the parameters while creating the factories

I am developing a web application using Laravel 8. I have noticed that quite a lot of things have changed in Laravel 8 including factories.
I have a factory class MenuCategoryFactory for my MenuCategory model class with the following definition.
<?php
namespace Database\Factories;
use App\Models\Menu;
use App\Models\MenuCategory;
use Illuminate\Database\Eloquent\Factories\Factory;
class MenuCategoryFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* #var string
*/
protected $model = MenuCategory::class;
/**
* Define the model's default state.
*
* #return array
*/
public function definition()
{
return [
'name' => $this->faker->name,
'menu_id' => Menu::factory()->create(),
];
}
}
In my code (database seeder class), I am trying to override the menu_id as follow while I am creating the factories.
$restaurant = Restaurant::first();
MenuCategory::factory()->create([
'menu_id' => $restaurant->menu->id
]);
But it is not using the value I passed, $restaurant->menu->id. Instead, it is creating a new menu. What is wrong missing in my code and how can I fix it?
In your factory definition, don't call ->create(), instead set it up like this:
public function definition()
{
return [
'name' => $this->faker->name,
'menu_id' => Menu::factory(),
];
}
Then you you should be able to set up related models (assuming you the relationships setup in the model) like this:
$restaurant = Restaurant::first();
MenuCategory::factory()->for($restaurant)->create();
Change the definition to
public function definition()
{
return [
'name' => $this->faker->name,
'menu_id' => function() {
Menu::factory()->create()->id,
}
];
}
then you can replace the value

Phalcon query builder can't get joined table data

I have 2 table 'sanpham' and 'danhmuc'. I use phalcon query builder to get data from 2 tables.
$laytin = $this->modelsManager->createBuilder()
->from("sanpham")
->innerJoin('danhmuc','sanpham.danhmuc=danhmuc.sodanhmuc')
->where('sanpham.sosanpham = '.$id.'')
->getQuery()
->getSingleResult();
$breadcrumbs = array('/' => Tool::getTranslation()->_('trangchu'),"/Loai-san-pham/".$laytin->tendep."/".$laytin->sodanhmuc => $laytin->tendanhmuc,'' => $laytin->tieudesanpham );
The query runs, but $laytin->tendep, $laytin->sodanhmuc, $laytin->tendanhmuc in 'danhmuc' table doesn't display. Every column in 'sanpham' table (such as: $laytin->tieudesanpham) displays properly.
You can add specific columns with:
$this->modelsManager->createBuilder()->columns('danhmuc.tend‌​ep, danhmuc.sodanhmuc')
With this method you will have to add each column you want in your output. QueryBuilder docs.
Another method is to query the Sanpham model.
For example:
class Sanpham extends \Phalcon\Mvc\Model
{
public static function findSomething($something)
{
// this is your actual query, it replaces the queryBuilder
return self::query()
->where('sanpham.sosanpham = :id:', ['id' => $something])
->innerJoin('danhmuc', 'sanpham.danhmuc = danhmuc.sodanhmuc')
->execute()->getFirst();
}
public function initialize()
{
// define the relation to danhmuc
$this->belongsTo('danhmuc', 'danhmuc', 'sodanhmuc');
}
}
class Danhmuc extends \Phalcon\Mvc\Model
{
public function initialize()
{
// there are other options besides "hasMany", like "hasOne".
// this is your relation to sanpham
$this->hasMany('sodanhmuc', 'sanpham', 'danhmuc');
}
}
class YourController extends \Phalcon\Mvc\Controller
{
public function testAction()
{
// get your first record in Sanpham matching "12345"
$sanpham = Sanpham::findSomething(12345);
// from your Sanpham object, get the related danhmuc object.
// this works because we defined the relations (belongsTo and hasMany)
$danhmuc = $sanpham->getRelated('danhmuc');
// now you have access to the values of danhmuc via the $danhmuc variable
$breadcrumbs = [
'/' => Tool::getTranslation()->_('trangchu'),
"/Loai-san-pham/" . $danhmuc->tendep => $danhmuc->tendanhmuc,
'' => $danhmuc->tieudesanpham,
];
}
}
Check the Phalcon model docs for more info on this.

Creating Dynamic attributes for Mongo Collection - YII Framework

I am trying to create dynamic model class for Mongo Collection and populate data in Cgridview (using YIIMongodbsuite extension)
Getting Column from MySQL DB:
$sql="SELECT name FROM CRM_Field Where crm_base_contact_id = ".$base;
$names =Yii::app()->db->createCommand($sql)->query()-> readAll();
Accessing Model in view:
$cc = new ContactCollection($names);// Passing dynamic column names to Model
$criteria = new EMongoCriteria;
$criteria->crm_base_contact_id('==', $base);
$cc->setDbCriteria($criteria);
CgridView Code:
<?php $this->widget('zii.widgets.grid.CGridView', array(
'id' =>'BCImported-grid',
'dataProvider' => $cc->search(false),
'columns' => $names,
)); ?>
ContactCollection Model :
<?php
class ContactCollection extends EMongoDocument
{
public $dyn_fields;
public function __construct ($names) {
$this->dyn_fields = $names;
}
public function getCollectionName()
{
return 'cartoons';
}
/**
* #return array validation rules for model attributes.
*/
public function rules()
{
$allMembers = implode(', ', array_keys($this->dyn_fields));
return array(
array($allMembers, 'required'),
);
}
public function attributeLabels()
{
return $this->dyn_fields;
}
}
I am getting this error " Property "ContactCollection.0" is not defined."
You don't need the "attributeLabels()" method in that case since each attribute should have an associated value. If you don't set that method, Yii will use the property name as the label itself.

Kohana (KO3) columns with ORM join

I'm trying to retrieve information from a database using Kohana ORM.
There are two relevant tables in my database:
branches
id smallint
parent_id smallint
name varchar
active int
branches_options
id mediumint
branche_id smallint
name varchar
customer_id int
With the following code I want to retrieve the information from the branches_options table
` $branchesOptions[] = ORM::factory('branches_option')
->where('branche_id', '=', $subBranche)
->join('branches', 'LEFT')->on('branches.id', '=', 'branches_options.branche_id')
->order_by('name')
->find_all()
->as_array();`
Now I want to see the value of branches.name in the result set, but I'm not sure how to do this in Kohana.
The code of the models is:
`class Model_Branche extends ORM
{
protected $_has_many = array(
"options" => array('model' => 'branches_option'),
"adwords_templates" => array ('model' => 'adwords_template')
);
public $result = array();`
and
`class Model_Branches_option extends ORM
{
protected $_has_many = array (
"keywords" => array('model' => 'branches_options_keyword')
);
protected $_has_and_belongs_to = array (
"adwords_templates" => array (
"model" => "adwords_template",
"through" => "branches_options_templates"
)
);
protected $_belongs_to = array ( "branche" => array () );`
Can this be done and if so, how?
You need to make some important changes to you models for this to work properly:
class Model_Branche extends ORM
{
protected $_has_many = array(
'options' => array(
'model' => 'branches_option',
'foreign_key' => 'branche_id'
)
);
}
And the Branches_Option model (it should be in model/branche/ folder):
class Model_Branches_Option extends ORM
{
protected $_belongs_to = array(
'branche' => array()
);
}
Now you can do something like that:
$options = ORM::factory('branche', $branche_id)
->options
->find_all();
foreach ($options as $option)
{
$branche_active = $option->branche->active;
$branche_name = $option->branch->name;
$option_name = $option->name;
}
One of the most important changes here is that we specify the foreign_key option in the $_has_many relationship. Since the ORM is using the Kohana Inflector helper it might not recognize it automatically (branches in singular form is branch and not branche).
If it doesn't work try specifying the $_table_name property for the same reason.
I'm trying to also grasp the concept here. In order to think like an ORM in this regard, you need to start with tables that the main tables reference as related information.
So in my world, I have a waste report, (model/waste/report) and there exists another table that has all the codes (model/waste/codes). so in the waste_reports table there's a column called code. That field might have 2E. 2E means nothing without the waste_codes table. The waste_codes table is (id, code, name).
I defined this relationship as such:
class Model_Waste_code extends ORM {
protected $_primary_key = "code";
protected $_has_one = array(
'waste_report' => array()
);
}
Then in my waste report model:
class Model_Waste_report extends ORM
{
protected $_belongs_to = array(
'codes' => array(
'model' => 'waste_code',
'foreign_key' => 'code'
)
);
}
To show different examples:
public function action_ormwaste() {
$test = ORM::factory('waste_report',76);
if ($test->loaded())
echo $test->codes->name;
echo "<hr noshade />";
$test = ORM::factory('waste_report')->find_all();
foreach($test as $row)
echo $row->codes->name . "<BR>";
}
Would output:
Error with image file (mirrored, etc)
-------------------------------------
Wrong Size
Extra Prints
Error with image file (mirrored, etc)
etc...
So in essense, the join on the data is handled on the fly. I'm using Kohana 3.2.
Thanks, that cleared me up.