Phalcon DB Criteria in Model ORM - orm

In Phalcon model is there a way to use SQL "IN" condition and other database criteria? For example, i want to execute this query in phalcon
SELECT user_fullname, user_email FROM tbl_users WHERE user_id IN (1,2,3,4,5)
I know you can use query builder but I want it to be ORM. I want a method in my model getUsersByIds($userIds, $columnsToSelect) that will accept an array of userids and columns that you want to fetch in the table.
See my model below
<?php
use Phalcon\Mvc\Model;
class User extends Model
{
/**
*
* #var integer
*/
public $user_id;
/**
*
* #var string
*/
public $user_email;
/**
*
* #var string
*/
public user_phone;
/**
*
* #var string
*/
public user_fullname;
public function initialize()
{ $this->hasMany('user_id','Store\Bag','user_id');
}
public function getSource()
{
return "tbl_user";
}
public function find($parameters = null)
{
return parent::find($parameters);
}
public function findFirst($parameters = null)
{
return parent::findFirst($parameters);
}
/**
* I want to execute this query in my model
* SELECT user_fullname,user_email from tbl_user where user_id IN (1,2,3,4,5);
*/
public function getUsersByIds($ids=array(), $columns=array())
{
if(!is_array($ids))
$ids = array($ids);
if(!is_array($columns))
$columns = array($columns);
...................................
.........................
..............
}
}

There are two ways of doing this:
Method 1: inWhere('columnName', array('columnValues'))
public function getUsersByIds(array $userIds, $columnsToSelect = '') {
return self::query()
->inWhere('id', $userIds)
->columns($columnsToSelect ?: '*')
->execute();
}
This one goes in your User model
Method 2: conditions => 'id IN ({ids:array})
User::find(['id IN ({ids:array})',
'columns' => $columnsToSelect,
'bind' => array('ids' => $userIds)]);
I am typing on my mobile, so there might be a typo in there.

Related

I get this error when I try to register a new user. 'The department id must be an integer.'

I get this error when I try to register a new user: 'The department id must be an integer'. All the answers I'm receiving are helpful just that I get confused at times. So I've added more codes for clarification purposes. I have been battling around for some hours now. Here is the migration file.
Schema::create('departments', function (Blueprint $table) {
$table->bigIncrements('department_id');
$table->integer('department_name');
$table->integer('department_code')->unique();
$table->text('department_discription')->nullable();
$table->tinyInteger('department_status')->default(1);
$table->softDeletes();
$table->timestamps();
This is the DepartmentController codes
<?php
namespace App\Http\Controllers;
use App\Http\Requests\CreateDepartmentRequest;
use App\Http\Requests\UpdateDepartmentRequest;
use App\Repositories\DepartmentRepository;
use App\Http\Controllers\AppBaseController;
use Illuminate\Http\Request;
use Flash;
use Response;
class DepartmentController extends AppBaseController
{
/** #var DepartmentRepository */
private $departmentRepository;
public function __construct(DepartmentRepository $departmentRepo)
{
$this->departmentRepository = $departmentRepo;
}
/**
* Display a listing of the Department.
*
* #param Request $request
*
* #return Response
*/
public function index(Request $request)
{
$departments = $this->departmentRepository->all();
return view('departments.index')
->with('departments', $departments);
}
/**
* Show the form for creating a new Department.
*
* #return Response
*/
public function create()
{
return view('departments.create');
}
/**
* Store a newly created Department in storage.
*
* #param CreateDepartmentRequest $request
*
* #return Response
*/
public function store(CreateDepartmentRequest $request)
{
$input = $request->all();
$department = $this->departmentRepository->create($input);
Flash::success('Department saved successfully.');
return redirect(route('departments.index'));
}
/**
* Display the specified Department.
*
* #param int $id
*
* #return Response
*/
public function show($id)
{
$department = $this->departmentRepository->find($id);
if (empty($department)) {
Flash::error('Department not found');
return redirect(route('departments.index'));
}
return view('departments.show')->with('department', $department);
}
/**
* Show the form for editing the specified Department.
*
* #param int $id
*
* #return Response
*/
public function edit($id)
{
$department = $this->departmentRepository->find($id);
if (empty($department)) {
Flash::error('Department not found');
return redirect(route('departments.index'));
}
return view('departments.edit')->with('department', $department);
}
/**
* Update the specified Department in storage.
*
* #param int $id
* #param UpdateDepartmentRequest $request
*
* #return Response
*/
public function update($id, UpdateDepartmentRequest $request)
{
$department = $this->departmentRepository->find($id);
if (empty($department)) {
Flash::error('Department not found');
return redirect(route('departments.index'));
}
$department = $this->departmentRepository->update($request->all(), $id);
Flash::success('Department updated successfully.');
return redirect(route('departments.index'));
}
/**
* Remove the specified Department from storage.
*
* #param int $id
*
* #throws \Exception
*
* #return Response
*/
public function destroy($id)
{
$department = $this->departmentRepository->find($id);
if (empty($department)) {
Flash::error('Department not found');
return redirect(route('departments.index'));
}
$this->departmentRepository->delete($id);
Flash::success('Department deleted successfully.');
return redirect(route('departments.index'));
}
}
here is the department code
<?php
namespace App\Models;
use Eloquent as Model;
use Illuminate\Database\Eloquent\SoftDeletes;
/**
* Class Departments
* #package App\Models
* #version September 21, 2020, 4:31 pm UTC
*
* #property integer $department_name
* #property integer $department_code
* #property string $department_discription
* #property boolean $department_status
*/
class Departments extends Model
{
use SoftDeletes;
public $table = 'departments';
const CREATED_AT = 'created_at';
const UPDATED_AT = 'updated_at';
protected $dates = ['deleted_at'];
public $fillable = [
'department_name',
'department_code',
'department_discription',
'department_status'
];
/**
* The attributes that should be casted to native types.
*
* #var array
*/
protected $casts = [
'department_id' => 'integer',
'department_name' => 'integer',
'department_code' => 'integer',
'department_discription' => 'string',
'department_status' => 'boolean'
];
/**
* Validation rules
*
* #var array
*/
public static $rules = [
'department_name' => 'required|integer',
'department_code' => 'required|integer',
'department_discription' => 'nullable|string',
'department_status' => 'required|boolean',
'deleted_at' => 'nullable',
'created_at' => 'nullable',
'updated_at' => 'nullable'
];
}
in your migration, try make 'department_id' the primary key declaratively:
$table->primary('department_id');
then (like sta said in the comment) in your Department model:
protected $primaryKey = "department_id";
or change it's name to just 'id'
you should create a depatment like this:
\App\Models\Department::create([
'department_name' => 1,
'department_code' => 1,
'department_discription' => 'first department',
'department_status' => 1
]);
don't forget to add columns name to fillable variable in your Department model
If I understand your question, you are going to need to change your department_id field in the db.
Create a new migration and for your department_id key, set it like this.
$table->unsignedBigInteger('department_id')->autoIncrement();
That should take care of your issue. What it will do is maintain the integrity of your db in the event that you need to add a relationship because it will create that field the same type as the id on other tables (unsignedBigInteger), but it will also autoIncrement the field.

How to create POST service URL and save data to DB using Laravel 5?

i want to get some data from a mobile app using POST and save it on my laravel 5 application database.
mycontroller
public function postBookingDetails(Request $request)
{
$FodMaps = $request->only('name','fructose');
return $FodMaps;
}
Route::post('booking', 'FodMapController#postBookingDetails');
table Structre:
id (autoincrement)
name varchar
fructose varchar
Model
protected $table = 'food_directory';
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = ['name', 'lactose', 'fructose','polyols','fructan'];
public function postBookingDetails(Request $request)
{
$FodMaps = $request->only('name','fructose');
$FoodDirectory = new FoodDirectory;
$FoodDirectory->name = $request->input('name');
$FoodDirectory->fructose = $request->input('fructose');
$FoodDirectory->save();
return $FoodDirectory;
}
also add to your model:
public $timestamps = false;
And ofcourse dont forget to add to the top of your controller:
use App\FoodDirectory;

Create sql query in sonata admin

I use sonata admin in my project. i created two admin classes exam and student. i want to create an action in exam class that shows all students that should pass the exam after creating a new exam, this is the sql query that i want:
"Select * from student,exam where student.codeAdministration=exam.codeAdministration"
examAdmin.php:
<?php
namespace Exam\ExamBundle\Admin;
use Sonata\AdminBundle\Admin\Admin;
use Sonata\AdminBundle\Datagrid\ListMapper;
use Sonata\AdminBundle\Datagrid\DatagridMapper;
use Sonata\AdminBundle\Validator\ErrorElement;
use Sonata\AdminBundle\Form\FormMapper;
use Sonata\AdminBundle\Show\ShowMapper;
class ExamAdmin extends Admin
{
////
protected function configureFormFields(FormMapper $formMapper)
{
//////
}
protected function configureDatagridFilters(DatagridMapper $datagridMapper)
{
////
}
protected function configureListFields(ListMapper $listMapper)
{
/////
}
protected function configureShowField(ShowMapper $showMapper)
{
//////
}
}
i tried this query without putting the condition of WHERE but it does not work:
protected function configureListFields(ListMapper $listMapper)
{
$query = $this->modelManager->getEntityManager()->createQuery('SELECT s FROM Exam\ExamBundle\Entity\student s');
$listMapper
->add('student', 'sonata_type_model', array('required' => true, 'query' => $query))
}
How can i create this action with this query??
exam.php:
<?php
namespace Exam\ExamBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
class Exam
{
/**
* #var integer
*/
private $idExam
////////
/**
* #var \Examens\ExamensBundle\Entity\Administration
*/
private $codeAdministration;
//////
public function getIdExam()
{
return $this->idExam;
}
///////
public function setCodeAdministration(\Exam\ExamBundle\Entity\Administration $codeAdministration = null)
{
$this->codeAdministration = $codeAdministration;
return $this;
}
/**
* Get codeAdministration
*
* #return \Exam\ExamBundle\Entity\Administration
*/
public function getCodeAdministration()
{
return $this->codeAdministration;
}
///////
}

Table joining using zend2 hydrate

I have a form to insert users to DB, which needs to update two tables # once, user table and user_role_linker table. I am using hydrator (ClassMethod) to map my entities with the relative tables. I use two seperate entities, User and UserRole. The form contains all user fields that map with User table and user role field to map with user_role_linker table. When form submitted, bind the form with the User Entity.
$user = new \ZfcUser\Entity\User();
$form = $this->getRegisterForm();
$form->setHydrator($this->getFormHydrator());
$form->bind($user);
$user = $form->getData();
Inserting is perform in two steps.
$this->getUserMapper()->insert($user);
$user_role_linker->setId($user->getId());
$user_role_linker->setRoleId($data['user_role']);
$this->getUserRoleLinkMapper()->insert($user_role_linker);
First insert the user and return the user_id, then set user_id and user_role in UserRole entity and insert to table.
But now the problem is to fetch two table to one object or one array. I may need to perform a table join to get the solution. But there is no way I could find to join tables with using ClassMethod hydrator.
Please help me to accomplish this.
UserHydrator class
namespace ZfcUser\Mapper;
use Zend\Stdlib\Hydrator\ClassMethods;
use ZfcUser\Entity\UserInterface as UserEntityInterface;
class UserHydrator extends ClassMethods
{
/**
* Extract values from an object
*
* #param object $object
* #return array
* #throws Exception\InvalidArgumentException
*/
public function extract($object)
{
if (!$object instanceof UserEntityInterface) {
throw new Exception\InvalidArgumentException('$object must be an instance of ZfcUser\Entity\UserInterface');
}
/* #var $object UserInterface*/
$data = parent::extract($object);
$data = $this->mapField('id', 'user_id', $data);
//$data = $this->mapField('id', 'username', $data);
return $data;
}
/**
* Hydrate $object with the provided $data.
*
* #param array $data
* #param object $object
* #return UserInterface
* #throws Exception\InvalidArgumentException
*/
public function hydrate(array $data, $object)
{
if (!$object instanceof UserEntityInterface) {
throw new Exception\InvalidArgumentException('$object must be an instance of ZfcUser\Entity\UserInterface');
}
$data = $this->mapField('user_id', 'id', $data);
return parent::hydrate($data, $object);
}
protected function mapField($keyFrom, $keyTo, array $array)
{
$array[$keyTo] = $array[$keyFrom];
unset($array[$keyFrom]);
return $array;
}
}

Adding custom data type (geometry) in Doctrine 2.1.7. Method canRequireSQLConversion() is not called

I am trying to add Geometry type to Doctrine. My Doctrine DBAL version and ORM versions are 2.1.7.
I tried to follow the instructions here:
Doctrine 2 Types - Custom Mapping Types.
I successfully created the new datatype, but I have problems with convertToPHPValueSQL method. I want function ST_AsText(' .. ') to always be called when getting the geometry column from database (database is PostgreSQL 9.1 + PostGIS 2.0.0).
Doctrine DBAL 2.1 documentation says like this:
The job of Doctrine-DBAL is to transform your type into SQL
declaration. You can modify the SQL declaration Doctrine will produce.
At first, you must to enable this feature by overriding the
canRequireSQLConversion method:
<?php
public function canRequireSQLConversion()
{
return true;
}
Then you override the methods convertToPhpValueSQL and
convertToDatabaseValueSQL :
<?php
public function convertToPHPValueSQL($sqlExpr, $platform)
{
return 'MyMoneyFunction(\''.$sqlExpr.'\') ';
}
public function convertToDatabaseValueSQL($sqlExpr, AbstractPlatform $platform)
{
return 'MyFunction('.$sqlExpr.')';
}
Now we have to register this type with the Doctrine Type system and
hook it into the database platform:
<?php
Type::addType('money', 'My\Project\Types\MoneyType');
$conn->getDatabasePlatform()->registerDoctrineTypeMapping('MyMoney', 'money');
I did like this (lot of code is placeholder code, but if I did something stupid, all advice is welcome):
<?php
namespace Minupeenrad\Types;
use Doctrine\DBAL\Types\Type;
use Doctrine\DBAL\Platforms\AbstractPlatform;
/**
* Class for database column "geometry".
*
* #author Rauni Lillemets
*/
class GeometryType extends Type {
const GEOMETRY = 'geometry';
const SRID = 3301;
public function getSqlDeclaration(array $fieldDeclaration, AbstractPlatform $platform) {
return 'geometry';
}
//Should create WKT object from WKT string. (or leave as WKT string)
public function convertToPHPValue($value, AbstractPlatform $platform) {
return $value; //+
}
//Should create WKT string from WKT object. (or leave as WKT string)
public function convertToDatabaseValue($value, AbstractPlatform $platform) {
return $value; //+
}
public function getName() {
return self::GEOMETRY;
}
public function canRequireSQLConversion() {
return true;
}
//Should give WKT
public function convertToPHPValueSQL($sqlExpr, $platform) {
return 'ST_AsText(\''.$sqlExpr.'\') '; //+
}
//Should create WKB
public function convertToDatabaseValueSQL($sqlExpr, AbstractPlatform $platform) {
return 'ST_GeomFromText(\''.$sqlExpr.'\', '.self::SRID.')'; //+
}
}
Now I added Entity that uses this column:
<?php
namespace Minupeenrad\Entities;
/**
* Field
*
* #author Rauni Lillemets
* #Entity
* #Table(name="myfields.fields")
*/
class Field extends GeometryObject {
/**
* #Id
* #Column(type="integer")
* #GeneratedValue
*/
private $id;
/**
* #ManyToOne(targetEntity="User")
*/
private $user;
/**
* #Column(type = "string", length = "40")
*/
private $fieldNumber;
public function getId() {
return $this->id;
}
public function getUser() {
return $this->user;
}
public function setUser($user) {
$this->user = $user;
}
public function getFieldNumber() {
return $this->fieldNumber;
}
public function setFieldNumber($fieldNumber) {
$this->fieldNumber = $fieldNumber;
}
}
?>
But if I do like this:
$entity = $em->find('\Minupeenrad\Entities\Field', 1);
Doctrine does SQL request to database like this:
SELECT t0.id AS id1, t0.fieldNumber AS fieldnumber2, t0.geometry AS geometry3, t0.user_id AS user_id4
FROM myfields.fields t0
WHERE t0.id = ?
Doctrine does not use my convertToPHPValueSQL method, although canRequireSQLConversion() returns true. Furthermore, I added some debug code to see if canRequireSQLConversion() is even called, and it is not called. What am I doing wrong?
PS: I tried to search Stack Overflow, but I only came up with GIS extension for Doctrine 2, which links to Doctrine 2.1.x manual that I already read.
EDIT: I will read here: http://docs.doctrine-project.org/en/latest/cookbook/advanced-field-value-conversion-using-custom-mapping-types.html
EDIT2: Fixed function getSqlDeclaration(), that was wrong in my code. Added comments.
It seems like a more complete tutorial.
Found the answer.
In Doctrine 2.1.7, if I used $em->find(), eventually BasicEntityPersister()_getSelectColumnSQL() was called. It has following code: (taken from https://github.com/doctrine/doctrine2/blob/2.1.x/lib/Doctrine/ORM/Persisters/BasicEntityPersister.php)
/**
* Gets the SQL snippet of a qualified column name for the given field name.
*
* #param string $field The field name.
* #param ClassMetadata $class The class that declares this field. The table this class is
* mapped to must own the column for the given field.
* #param string $alias
*/
protected function _getSelectColumnSQL($field, ClassMetadata $class, $alias = 'r')
{
$columnName = $class->columnNames[$field];
$sql = $this->_getSQLTableAlias($class->name, $alias == 'r' ? '' : $alias) . '.' . $class->getQuotedColumnName($field, $this->_platform);
$columnAlias = $this->_platform->getSQLResultCasing($columnName . $this->_sqlAliasCounter++);
$this->_rsm->addFieldResult($alias, $columnAlias, $field);
return "$sql AS $columnAlias";
}
This code obviously does not respect method "canRequireSQLConversion"
In latest Doctrine version, 2.3.1 (see https://github.com/doctrine/doctrine2/blob/2.3/lib/Doctrine/ORM/Persisters/BasicEntityPersister.php):
/**
* Gets the SQL snippet of a qualified column name for the given field name.
*
* #param string $field The field name.
* #param ClassMetadata $class The class that declares this field. The table this class is
* mapped to must own the column for the given field.
* #param string $alias
*/
protected function _getSelectColumnSQL($field, ClassMetadata $class, $alias = 'r')
{
$sql = $this->_getSQLTableAlias($class->name, $alias == 'r' ? '' : $alias)
. '.' . $this->quoteStrategy->getColumnName($field, $class, $this->_platform);
$columnAlias = $this->getSQLColumnAlias($class->columnNames[$field]);
$this->_rsm->addFieldResult($alias, $columnAlias, $field);
if (isset($class->fieldMappings[$field]['requireSQLConversion'])) {
$type = Type::getType($class->getTypeOfField($field));
$sql = $type->convertToPHPValueSQL($sql, $this->_platform);
}
return $sql . ' AS ' . $columnAlias;
}
So the answer is to update my ORM.