Symfony3 return array from query to json - arrays

I have problem, i can't return my posts array to json becouse symfony returns array with entity object?
Its my code:
public function indexAction()
{
$em = $this->getDoctrine()->getManager();
$posts = $em->getRepository('AppBundle:Post')->findAll();
return $this->json($posts);
}
I use $this->json is return json data, feature added on sf3.
But this is my result:
[
{},
{},
{}
]
i want to load my posts.
ps. i know, i can use Query builder, and method toArray or something, but is any method to use and DRY? Thx

Because entity can have multiple boundaries, proxy objects and related entities, I personally prefer to explicitly specify what is about to be serialized, like this:
use JsonSerializable;
/**
* #Entity
*/
class SomeEntity implements JsonSerializable
{
/** #Column(length=50) */
private $title;
/** #Column(length=50) */
private $text;
public function jsonSerialize()
{
return array(
'title' => $this->title,
'text' => $this->text,
);
}
}
And then it's as simple as json_encode($someEntityInstance);.
You can use JMSSerializerBundle as well to accomplish your task DRY.
Also, there is an option to write your own serializer to normalize the data.
UPDATE:
If you want multiple representations of a JSON, it can be achieved like this:
use JsonSerializable;
/**
* #Entity
*/
class SomeEntity implements JsonSerializable
{
// ...
protected $isList;
public function toList()
{
$this->isList = TRUE;
return $this;
}
private function jsonSerializeToList()
{
return [ // array representing list... ]
}
public function jsonSerialize()
{
if( $this->isList ) {
$normalized = $this->jsonSerializeToList();
} else {
$normalized = array(
'title' => $this->title,
'text' => $this->text,
);
}
return $normalized;
}
}
And called as json_encode($someEntityInstance->toList());. Any way, this is a bit dirty, so I suggest to be consistent with an idea of the interface.

A best solution is to enable the serializer component in Symfony:
#app/config/config.yml
framework:
serializer: ~
Note: the serializer component is disabled by default, you have to uncomment the config line in app/config/config.yml file.

Related

Codeigniter autocheck db depending on session value

I'm trying to force my app to check every time it loads a model or controller depending on which is my session value.
This is actually running, but just when I get throw this model.
class News_model extends CI_Model {
public function __construct()
{
parent::__construct();
if($this->session->dbname=='db1'){
$this->db=$this->load->database('db1', TRUE);
}
else{
$this->db=$this->load->database('db2', TRUE);
}
}
public function get_news($slug = FALSE)
{
if ($slug === FALSE)
{
$query = $this->db->get('news');
return $query->result_array();
}
$query = $this->db->get_where('news', array('slug' => $slug));
return $query->row_array();
}
}
But I do not war to include that __construct code to all my models or controllers.
I've tried to add on my autoload.php
$autoload['model'] = array('General');
Where my General code is something like this.
class General extends CI_Model {
function __construct()
{
parent::__construct();
if($this->session->dbname=='db1'){
$this->db=$this->load->database('db1', TRUE);
}
else{
$this->db=$this->load->database('db2', TRUE);
}
}
}
How can I do it?
You can do it by creating a base model which will be extended by your models that require the database check.
I have simplified the checking and loading code. A simple ternary determines the string to use and stores it in the variable $dbname. That variable is used to load the database, i.e. $this->load->database($dbname);.
I don't believe you need the second argument to load::database() which means you don't need to set $this->db explicitly. If I'm wrong, use
$this->db = $this->load->database($dbname, TRUE);
Below is the "base" model. The prefix of the file name is determined in config.php with the setting $config['subclass_prefix'] = 'MY_'; Adjust your base model's file and class name to match the 'subclass_prefix' you use.
/application/core/MY_Model.php
<?php
class MY_Model extends CI_Model
{
public function __construct()
{
parent::__construct();
$dbname = $this->session->dbname == 'db1' ? 'db1' : 'db2';
$this->load->database($dbname);
}
}
Use the above to create other models like so...
class News_model extends MY_Model
{
public function get_news($slug = FALSE)
{
if ($slug === FALSE)
{
$query = $this->db->get('news');
return $query->result_array();
}
$query = $this->db->get_where('news', array('slug' => $slug));
return $query->row_array();
}
}

Displaying array values in laravel 5.2

I have the following hasMany() relationship in App\User.php ,
public function partner_preference_occupation()
{
return $this-hasMany('App\Models\User\PartnerPreferenceOccupation', 'user_id');
}
The following is my PartnerPreferenceOccupation Model,
<?php
namespace App\Models\User;
use App\Models\BaseModel,
App\Models\ValidationTrait;
class PartnerPreferenceOccupation extends BaseModel {
use ValidationTrait;
public function __construct() {
parent::__construct();
$this->__validationConstruct();
}
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'partner_preferences_occupation';
protected $fillable = array('user_id', 'occupation_id');
protected $dates = array();
public $uploadPath = array();
protected function setRules() {
$this->val_rules = array();
}
protected function setAttributes() {
$this->val_attributes = array();
}
public function occupation_name() {
return $this->belongsTo('App\Models\Master\OccupationModel', 'occupation_id');
}
}
I want to display the array of occupation name in my view. I tried the following code, but it fails.
{{$obj->partner_preference_occupation ? $obj-partner_preference_occupation->occupation_name->name : null}}
The error is as follows,
Undefined property:Illuminate\Database\Eloquent\Collection::$occupation_name
How can I display them.Thanks in advance.
There is a typo in $obj-partner_preference_occupation->occupation_name->name
Should be $obj->partner_preference_occupation->occupation_name->name
Make sure that occupation_name exists in the collection. You can check by doing the following in your View:
dump( $obj->partner_preference_occupation );
It might help you identify where the issue lies.
Also, to display a collection as an array, you can use the toArray() method, e.g.:
$obj->partner_preference_occupation->toArray()
Ok I got it,
As it is an array of values to be fetched, I used foreach to display them in my view as,
#if($occ=$obj->partner_preference_occupation->lists('occupation_name'))
#foreach($occ as $oc)
{{$oc->name}}
#endforeach
#endif
occupatoin_name is the name of my relationship that I used in my model. And that worked for me :)

yii2 batch insert with ActiveRecord

I want to insert multiple record in my table using yii2 ActiveRecord.
I already know that I can use this code
$connection->createCommand()->batchInsert('user', ['name', 'age'], [
['Tom', 30],
['Jane', 20],
['Linda', 25],
])->execute();
but by this approach my model validations are not executing.
and I already have read this question
ActiveRecord batch insert (yii2)
but also by doing validation in a tricky way, consider I want to fill created_at and updated_at columns using ActiveRecords events.
just like this
public function beforeSave($insert)
{
if (parent::beforeSave($insert)) {
if($insert)
$this->created_at = date('Y-m-d H:i:s');
$this->updated_at = date('Y-m-d H:i:s');
return true;
} else {
return false;
}
}
I think is not good idea to use beforeSave events (and similar stuff) because it will trigger for each model. However you want save multiple models at once. I recommend to use bulk methods.
In similar cases I use usually following "bulk" approach (code not tested, just for example):
namespace common\components;
class Model extends yii\base\Model {
/**
* Saves multiple models.
*
* #param ActiveRecord[] $models
* #return bool
*/
public static saveMultiple($models){
if(count($models) > 0){
$firstModel = reset($models);
$columnsToInsert = $firstModel->attributes(); // here you can remove excess columns. for example PK column.
$modelsToInsert = [];
$rowsToInsert = [];
foreach($models as $model){
if ($this->beforeSave(true)) {
$modelsToInsert[] = $model;
}
}
foreach($modelsToInsert as $model){
$rowsToInsert[] = array_values($model->attributes); // here you can remove excess values
}
$numberAffectedRows = \Yii::$app->db->createCommand()
->batchInsert($firstModel->tableName(), $columnsToInsert, $rowsToInsert)
->execute();
$isSuccess = ($numberAffectedRows === count($models));
if($isSuccess){
$changedAttributes = array_fill_keys($columnsToInsert, null);
foreach($modelsToInsert as $model){
$model->afterSave(true, $changedAttributes);
}
}
return $isSuccess;
} else {
return true;
}
}
}
This class can be used:
use common\components\Model;
/**
* #var SomeActiveRecord[] $models Array that contains array of active records (type SomeActiveRecord)
*/
// ...
if (Model::validateMultiple($models)){
if(!Model::saveMultiple($models)){
// ... some error handling
}
} else {
foreach($models as $model){
if($model->hasErrors()){
$errors = $model->getFirtsErrors();
// ... some error handling
}
}
}
Additionally, for more convenient working with multiple models can be developed special Collection class that implements \ArrayAccess and \Iterator interfaces. This collection can iterated as simple array, however it contains special methods for bulk operations. Something like this:
foreach($modelCollection as $model){
// ...
}
$modelCollection->validate(); // works similar to common\components\Model::validateMultiple()
$modelCollection->save(); // works similar to common\components\Model::saveMultiple()

Zend framework 2 model for database, separate model for each table?

I looked through the manual of Zend Framework 2 about creating model to managing operations on table. Is the class with method exchangeArray() is necessary? It's only copy data :/ Can i create one model to manage a few tables?
I created two classes:
namespace Application\Model;
use Zend\Db\Adapter\Adapter;
use Zend\Db\Adapter\AdapterAwareInterface;
abstract class AbstractAdapterAware implements AdapterAwareInterface
{
protected $db;
public function setDbAdapter(Adapter $adapter)
{
$this->db = $adapter;
}
}
and:
namespace Application\Model;
class ExampleModel extends AbstractAdapterAware
{
public function fetchAllStudents()
{
$result = $this->db->query('select * from Student')->execute();
return $result;
}
}
I also add entries in Module.php:
'initializers' => [
'Application\Model\Initializer' => function($instance, \Zend\ServiceManager\ServiceLocatorInterface $serviceLocator){
if ($instance instanceof AdapterAwareInterface)
{
$instance->setDbAdapter($serviceLocator->get('Zend\Db\Adapter\Adapter'));
}
}
],
'invokables' => [
'ExampleModel' => 'Application\Model\ExampleModel'
],
I execute methods from model by:
$this->getServiceLocator()->get('ExampleModel')->fetchAllStudents();
You should do 2 things with your code. First, implement AdapterAwareInterface properly. Second, create an initializer which injects the adapter into your model. Consider the code below:
...
'initializers' => [
function($instance, ServiceLocatorInterface $serviceLocator){
if ($instance instanceof AdapterAwareInterface) {
$instance->setDbAdapter($serviceLocator->get('Zend\Db\Adapter\Adapter'));
}
}
]
...
abstract class AbstractModel implements AdapterAwareInterface
{
protected $db;
public function setDbAdapter(Adapter $adapter)
{
$this->db = adapter;
}
}
...
'invokables' => [
'ExampleModel' => 'Application\Model\ExampleModel'
]
As you can see from above, after all, you don't need a factory for each your model. You can either register invokables or create an Abstract Factory to instantiate your models. See an example below:
...
'abstract_factories' => [
'Application\Model\AbstractFactory'
]
...
class AbstractFactory implements AbstractFactoryInterface
{
public function canCreateServiceWithName(ServiceLocatorInterface $serviceLocator, $name, $requestedName)
{
return class_exists('Application\Model\'.$requestedName);
}
public function createServiceWithName(\Zend\ServiceManager\ServiceLocatorInterface $serviceLocator, $name, $requestedName)
{
$class = 'Application\Model\'.$requestedName();
return new $class
}
}
Hope this helps

Yii record is not inserting into DB

Below is my controller & model logic - I just started a barebones Yii installation to play around with it more.
I get no errors but don't see the new entry in the database - my db has been configured in the main.php (this works as Gii runs).
// controllers/PageController.php
class PageController extends Controller
{
public function actionSave($value='')
{
$pageObj = new Page;
$pageObj->savePage();
}
}
// models/Page.php
class Page extends CActiveRecord
{
/**
* #return string the associated database table name
*/
public function tableName()
{
return 'page';
}
/**
* #return array validation rules for model attributes.
*/
public function rules()
{
// NOTE: you should only define rules for those attributes that
// will receive user inputs.
return array(
array('title, date_updated', 'required'),
array('live', 'numerical', 'integerOnly'=>true),
array('user_id', 'length', 'max'=>10),
array('title', 'length', 'max'=>100),
array('content, date_published', 'safe'),
// The following rule is used by search().
// #todo Please remove those attributes that should not be searched.
array('id, user_id, live, title, content, date_updated, date_published', 'safe', 'on'=>'search'),
);
}
/**
* #return array relational rules.
*/
public function relations()
{
// NOTE: you may need to adjust the relation name and the related
// class name for the relations automatically generated below.
return array(
'comments' => array(self::HAS_MANY, 'Comment', 'page_id'),
'user' => array(self::BELONGS_TO, 'User', 'user_id'),
'files' => array(self::MANY_MANY, 'File', 'page_has_file(page_id, file_id)'),
);
}
/**
* #return array customized attribute labels (name=>label)
*/
public function attributeLabels()
{
return array(
'id' => 'ID',
'user_id' => 'User',
'live' => 'Live',
'title' => 'Title',
'content' => 'Content',
'date_updated' => 'Date Updated',
'date_published' => 'Date Published',
);
}
/**
* Retrieves a list of models based on the current search/filter conditions.
*
* Typical usecase:
* - Initialize the model fields with values from filter form.
* - Execute this method to get CActiveDataProvider instance which will filter
* models according to data in model fields.
* - Pass data provider to CGridView, CListView or any similar widget.
*
* #return CActiveDataProvider the data provider that can return the models
* based on the search/filter conditions.
*/
public function search()
{
// #todo Please modify the following code to remove attributes that should not be searched.
$criteria=new CDbCriteria;
$criteria->compare('id',$this->id,true);
$criteria->compare('user_id',$this->user_id,true);
$criteria->compare('live',$this->live);
$criteria->compare('title',$this->title,true);
$criteria->compare('content',$this->content,true);
$criteria->compare('date_updated',$this->date_updated,true);
$criteria->compare('date_published',$this->date_published,true);
return new CActiveDataProvider($this, array(
'criteria'=>$criteria,
));
}
/**
* Returns the static model of the specified AR class.
* Please note that you should have this exact method in all your CActiveRecord descendants!
* #param string $className active record class name.
* #return Page the static model class
*/
public static function model($className=__CLASS__)
{
return parent::model($className);
}
public function savePage($value='')
{
$page = new page;
$model->isNewRecord = true;
$model->primaryKey = NULL;
$page->title='sample page';
$page->content='content for the sample page';
$page->save(false);
}
}
In Yii, when you want to insert into a table which has some null columns, you must put null columns in your rules as SAFE like below:
array('primaryKey','safe'),
Now, Yii knows that primaryKey is a null column. So, there would be no problem via inserting into the current model.
As a note, when you call save() method with FALSE, you are telling to your model to do not the validation on insert.
Also, the correct way to skip possible errors is to validate your model before inserting like below:
if($model->validate()){
// VALIDATE, YOU CAN CALL SAVE FUNCTION
}else{
//here you can send an error message via FLASH or you can debug what the exact error is like below:
CVarDumper::dump($model->getErrors(),5678,true);
Yii::app()->end();
}
I hope, it help
So simple... I hate Yii sometimes :-)
Had to set the save() to save(false)
$page = new page;
$page->isNewRecord = true;
$page->primaryKey = NULL;
$page->title='sample page';
$page->content='content for the sample page';
$page->save(false);
Thanks for that - I had missed out some columns.. (silly me)
Improve the function even further with the help above..
public function savePage()
{
$page = new page;
$page->isNewRecord = true;
$page->primaryKey = NULL;
$page->user_id = 1;
$page->live = 0;
$page->content='content for the sample page';
$page->date_updated = date('Y-m-d H:i:s');
$page->date_published = date('Y-m-d H:i:s');
$page->title='sample page';
if ($page->validate()) {
$page->save();
} else {
CVarDumper::dump($page->getErrors(),5678,true);
Yii::app()->end();
}
}

Resources