How do I add an array to Parameter in swagger yii2? - yii2

How to add descriptions of such parameters to body in a request in swagger (yii2).
Composer require
"yii2mod/yii2-swagger": "*"
I try to write a method in api using swagger
That's what he return:
{
"parent_id":"",
"name":"testCategory3",
"position":"0",
"status":"1",
"publish-status":"1",
"charsName":["1","2","3"]
}
My description:
/**
* #SWG\Put(path="/api/createCategory",
* tags={"Category"},
* summary="Create Category",
* #SWG\Parameter(
* name="Authorization",
* in="header",
* description=" ID",
* required=true,
* type="string"
* ),
* #SWG\Parameter(
* name="body",
* in="body",
* required=true,
* #SWG\Schema(
* type="object",
* #SWG\Property(property="parent_id", type="integer" ),
* #SWG\Property(property="status", type="integer" ),
* #SWG\Property(property="publish-status", type="integer" ),
* #SWG\Property(property="position", type="integer" ),
* #SWG\Property(property="name", type="string" ),
* )
* ),
* #SWG\Response(
* response = 200,
* description = "Ok",
* #SWG\Schema(ref = "#/")
* ),
* #SWG\Response(
* response = 400,
* description = "Bad Request",
* #SWG\Schema(ref = "#/")
* ),
* #SWG\Response(
* response = 404,
* description = "Not Found",
* #SWG\Schema(ref = "#/")
* ),
* #SWG\Response(
* response = 500,
* description = "Internal Server Error"
* )
* )
*/
How to add charsName array?
In swagger page

An array property is defined using type="array" and #SWG\Items:
* #SWG\Property(
* property="charsName",
* type="array",
* #SWG\Items(type="string"),
* example={"1","2","3"}
* )

Related

API Platform : Groups with nested entities work only when removing #ApiResource

API platform uses by default IRI's to GET nested entities but I'm trying to GET entity normalized with normalization_context and groups. It work but only when i remove #ApiResource from the nested entity and i need it to expose my CRUD services.
Example
/**
* #ApiResource(
* attributes={
* "normalization_context"={"groups"={"goals-read"}},
* "denormalization_context"={"groups"={"goals-read"}}
* })
*
* )
*
* Goals
* #ApiFilter(OrderFilter::class, properties={"id"}, arguments={"orderParameterName"="order"})
* #ORM\Table(name="goals", indexes={#ORM\Index(name="IDX_C7241E2FA55629DC", columns={"processus_id"})})
* #ORM\Entity
*/
class Goals
{
/**
* #var int
* #Groups("goals-read")
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
// some fields ...
/**
* #var Processus
* #ORM\ManyToOne(targetEntity="Processus")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="processus_id", referencedColumnName="id")
* })
* #Groups({"goals-read"})
* #ApiProperty(readableLink=false, writableLink=false)
*/
private $processus;
/**
* #var Issues
* #ORM\ManyToOne(targetEntity="Issues")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="issues_id", referencedColumnName="id")
* })
* #Groups({"goals-read"})
* #ApiProperty(readableLink=false, writableLink=false)
*/
private $issue;
Processus Class
/**
* Processus
* #ApiResource()
* #ORM\Table(name="processus", indexes={#ORM\Index(name="IDX_EEEA8C1DC35E566A", columns={"family_id"})})
* #ORM\Entity
*/
class Processus
{
/**
* #var int
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
* #Groups({"goals-read"})
*/
private $id;
/**
* #var string|null
* #ORM\Column(name="name", type="string", length=255, nullable=true)
* #Groups({"goals-read"})
*/
private $name;
Response body
{
"#context": "/api/contexts/Goals",
"#id": "/api/goals",
"#type": "hydra:Collection",
"hydra:member": [
{
"#id": "/api/goals/29",
"#type": "Goals",
"id": 29,
"description": "string",
"comment": "string",
"currentState": "string",
"goalToReach": "string",
"advancement": "string",
"indicator": 0,
"q1": "string",
"q2": "string",
"q3": "string",
"q4": "string",
"nextYear": "string",
"nextTwoYear": "string",
"processus": "/api/processuses/2",
"issue": "/api/issues/5"
}
when removing #ApiResource()
// JSON Response
...
...
...
"processus": {
"#type": "Processus",
"#id": "_:938",
"id": 2,
"name": "string"
}
Turns out the solution was right under our noses, with the #ApiProperty(readableLink=false, writableLink=false) annotation being the culprit. The documentation regarding this annotation clearly states that this forces referenced entities to be serialized as IRI's (overruling serialization groups). Removing this annotation from the Goals::$processus property will have API Platform use the goals-write serialization group to serialize the referenced Processus entity.
Here is a working example written in PHP 8 and API Platform 2.6 (as that's what I currently have deployed while writing this, don't think versions here are relevant though):
Goals
<?php declare(strict_types = 1);
//..
/**
* #ORM\Entity
*/
#[ApiResource(
normalizationContext: [
'groups' => [
'goals-read'
]
],
)]
#[ApiFilter(
OrderFilter::class,
properties: ['id'],
arguments: [
'orderParameterName' => 'order'
]
)]
class Goals
{
/**
* #ORM\Id
* #ORM\GeneratedValue(
* strategy="IDENTITY"
* )
* #ORM\Column(
* type="integer",
* nullable=false
* )
* #Groups({
* "goals-read"
* })
*/
private ?int $id = null;
/**
* #ORM\ManyToOne(
* targetEntity="Processus"
* )
* #ORM\JoinColumn(
* name="processus_id",
* referencedColumnName="id"
* )
* #Groups({
* "goals-read"
* })
* NO MORE #ApiProperty ANNOTATION HERE
*/
private ?Processus $processus = null;
}
Processus
<?php declare(strict_types = 1);
//..
/**
* #ORM\Entity
*/
#[ApiResource]
class Processus
{
/**
* #ORM\Id
* #ORM\GeneratedValue(
* strategy="IDENTITY"
* )
* #ORM\Column(
* type="integer",
* nullable=false
* )
* #Groups({
* "goals-read"
* })
*/
private ?int $id = null;
/**
* #ORM\Column(
* name="name",
* type="string",
* length=255,
* nullable=true
* )
* #Groups({
* "goals-read"
* })
*/
private ?string $name = null;
}
The thing is you use wrong construction in class Goals:
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="processus_id", referencedColumnName="id")
* })
The annotation #JoinColumns can be used only for #ManyToMany relationship, inside of #JoinTable annotation.
You can take a look on related Doctrine documentation
So, in your case you have to use:
/**
* #var Processus
*
* #ORM\ManyToOne(targetEntity="Processus")
* #ORM\JoinColumn(name="processus_id", referencedColumnName="id")
*
* #Groups({"goals-read", "goals-write"})
*/
private $processus;
And yes, I've added different serialization group goals-write for denormalization context, as #Jeroen van der Laan suggested to you in his comment.
Hope I can help you.

Laravel adding WHERE to DB::raw and Joins

Here is my code:
return ExportInvoice::join('sold_products', 'sold_products.export_invoice_id', '=', 'export_invoices.id')
->join('products', 'sold_products.product_id', '=', 'products.id')
->select(
'sold_products.product_id',
'products.name',
DB::raw('
round(round(sum(round(sold_products.sold_price * sold_products.quantity * (1 - sold_products.discount / 100), 2))
* (1 - export_invoices.discount / 100), 2) * (1 + IF(export_invoices.tax, 14, 0) / 100), 2)
as total
')
)
->groupBy('sold_products.product_id', 'products.name', 'export_invoices.discount', 'export_invoices.tax')
->orderBy('total', 'DESC')
->limit(100)
->get();
What I am trying to do:
I am trying to add whereNotNull('export_invoices.deleted_at') and whereNotNull('sold_products.deleted_at') because I am using Laravel soft delete and the above query return all data even those who are soft-deleted.
If you are not able to do just ->whereNull('sold_products.deleted_at') and ->whereNull('export_invoices.deleted_at') then try to add this after select statement.
$columns = ['sold_products.deleted_at', 'export_invoices.deleted_at']
->where(function($q) use ($columns){
foreach($columns as $column){
$q->whereNull($columns);
}
})
So it would be:
$columns = ['sold_products.deleted_at', 'export_invoices.deleted_at']
return ExportInvoice::join('sold_products', 'sold_products.export_invoice_id', '=', 'export_invoices.id')
->join('products', 'sold_products.product_id', '=', 'products.id')
->select(
'sold_products.product_id',
'products.name',
DB::raw('
round(round(sum(round(sold_products.sold_price * sold_products.quantity * (1 - sold_products.discount / 100), 2))
* (1 - export_invoices.discount / 100), 2) * (1 + IF(export_invoices.tax, 14, 0) / 100), 2)
as total
')
)->where(function($q) use ($columns){
foreach($columns as $column){
$q->whereNull($columns);
}
})->groupBy('sold_products.product_id', 'products.name', 'export_invoices.discount', 'export_invoices.tax')
->orderBy('total', 'DESC')
->limit(100)
->get();
I hope it helps!

Laravel How Make DB raw can inside funtion

I have problem on laravel. I want to showing percentage on with eloquent, but return null value
This Is My Controller
$group_categories = Proyek::with(['modul' => function($query){
$query->select(DB::raw('((select count(*) from modul where status = 0 and deleted_at IS NULL) /
(select count(*) from modul where deleted_at IS NULL)) *
100 as count' ));
}])->get();
This Is Json return
{
id: "10",
proyek: "JuZka",
created_at: "2018-08-12 01:54:04",
updated_at: "2018-09-23 05:49:13",
modul: [ ]
},
You can use code like this:
$all_models = (new Proyek)->count();
$models = (new Proyek)->where('status', 0)->count();
$percentage = $models / $all_models * 100;
$group_categories = Proyek::wheere('modul', $percentage);

Yii2: How to override the yii\db\Query class to add default conditions with queries

I want to make a cloud-based application where I store the application id and branch_id in session and I want to add the application_id and branch_id to each DB query.
Easy I am overriding the find() using
public static function find()
{
return parent::find()->where([]);
}
But the issue is how i override the query like this
$total_return_price = (new Query())
->select('SUM(product_order.order_price * product_order.quantity) as return_price')
->from('order')
->innerJoin('product_order', 'product_order.order_id = order.id')
->where(['=', 'order.user_id', $user_id])
->andWhere(['=', 'order.status', '4'])
->one();
Well one way is to extend the Query class and override the traits where() from() and select() and change the namespace from the yii\db\Query to common\components\Query overall in the models where you want the condition to be added. But remember it is your responsibility to make sure all those tables have these 2 fields (application_id and branch_id) inside the tables where ever you replace the yii\db\Query with common\components\Query.
Why override where() from() and select() ? you have the possibility of writing queries in the following formats.
Let's say we have a product table with the fields id and name, now consider the following queries.
$q->from ( '{{product}}' )
->all ();
$q->select ( '*' )
->from ( '{{product}}' )
->all ();
$q->from ( '{{product}}' )
->where ( [ 'name' => '' ] )
->all ();
$q->from ( '{{product}}' )
->andWhere ( [ 'name' => '' ] )
->all ();
$q->select ( '*' )
->from ( '{{product}}' )
->where ( [ 'IN' , 'id' , [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 89 , 0 ] ] )
->andwhere ( [ 'name' => '' ] )
->all ();
$q->select ( '*' )
->from ( '{{product}}' )
->where ( [ 'and' ,
[ 'IN' , 'id' , [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 89 , 0 ] ] ,
[ 'name' => '' ]
] )
->all();
The above will generate the following SQL queries
SELECT * FROM `product`
SELECT * FROM `product`
SELECT * FROM `product` WHERE (`name`='')
SELECT * FROM `product` WHERE (`name`='')
SELECT * FROM `product` WHERE (`id` IN (1, 2, 3, 4, 5, 6, 7, 89, 0)) AND (`name`='')
SELECT * FROM `product` WHERE (`id` IN (1, 2, 3, 4, 5, 6, 7, 89, 0)) AND (`name`='')
So you need to add all the above queries with two where conditions by default
create a file name Query inside the common/components and add the following,
Note: I have added conditions with hardcoded values for the columns
like this [ 'application_id' => 1 ] , [ 'branch_id' => 1 ] replace
them with the respective variables from the session before actually using
it for testing purpose you can keep as is.I assume that you want the above two
fields to be added with an and condition in the query.
<?php
namespace common\components;
use yii\db\Query as BaseQuery;
class Query extends BaseQuery {
/**
*
* #param type $condition
* #param type $params
* #return $this
*/
public function where( $condition , $params = array() ) {
parent::where ( $condition , $params );
$defaultConditionEmpty = !isset ( $this->where[$this->from[0] . '.company_id'] );
if ( $defaultConditionEmpty ) {
if ( is_array ( $this->where ) && isset ( $this->where[0] ) && strcasecmp ( $this->where[0] , 'and' ) === 0 ) {
$this->where = array_merge ( $this->where , [ [ $this->from[0] . '.company_id' => 1 ] , [ $this->from[0] . '.branch_id' => 1 ] ] );
} else {
$this->where = [ 'and' , $this->where , [ $this->from[0] . '.company_id' => 1 ] , [ $this->from[0] . '.branch_id' => 1 ] ];
}
}
return $this;
}
/**
*
* #param type $tables
* #return $this
*/
public function from( $tables ) {
parent::from ( $tables );
$this->addDefaultWhereCondition ();
return $this;
}
/**
* Private method to add the default where clause
*/
private function addDefaultWhereCondition() {
if ( $this->from !== null ) {
$this->where = [ 'and' ,
[ $this->from[0] . '.company_id' => 1 ] , [ $this->from[0] . '.branch_id' => 1 ]
];
}
}
}
Now to test it create a test action inside your SiteController like below and access it
public function actionTest() {
$q = new \common\components\Query();
echo $q->from ( '{{product}}' )->createCommand ()->rawSql;
echo "<br>";
echo $q->select ( '*' )->from ( '{{product}}' )->createCommand ()->rawSql;
echo "<br/>";
echo $q->from ( '{{product}}' )->where ( [ 'name' => '' ] )->createCommand ()->rawSql;
echo "<br>";
echo $q->from ( '{{product}}' )->andWhere ( [ 'name' => '' ] )->createCommand ()->rawSql;
echo "<br>";
echo $q->select ( '*' )->from ( '{{product}}' )->where ( [ 'IN' , 'id' , [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 89 , 0 ] ] )->andwhere ( [ 'name' => '' ] )->createCommand ()->rawSql;
echo "<br />";
echo $q->select ( '*' )->from ( '{{product}}' )
->where ( [ 'and' ,
[ 'IN' , 'id' , [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 89 , 0 ] ] ,
[ 'name' => '' ]
] )
->createCommand ()->rawSql;
return;
}
Do not worry about the product table we need to check the query generated so we are not executing the query instead using ->createCommand()->rawSql to print the query built. so access the above action it should now print you the queries with both the columns added like below
SELECT * FROM `product` WHERE (`application_id`=1) AND (`branch_id`=1)
SELECT * FROM `product` WHERE (`application_id`=1) AND (`branch_id`=1)
SELECT * FROM `product` WHERE (`name`='') AND (`application_id`=1) AND (`branch_id`=1)
SELECT * FROM `product` WHERE (`application_id`=1) AND (`branch_id`=1) AND (`name`='')
SELECT * FROM `product` WHERE (`id` IN (1, 2, 3, 4, 5, 6, 7, 89, 0)) AND (`application_id`=1) AND (`branch_id`=1) AND (`name`='')
SELECT * FROM `product` WHERE (`id` IN (1, 2, 3, 4, 5, 6, 7, 89, 0)) AND (`name`='') AND (`application_id`=1) AND (`branch_id`=1)
Hope that helps you out or someone else looking for the same solution
EDIT
I updated the class above and added the fix to the queries using joins, that throws an error
Column 'company_id' in where clause is ambiguous
I have added the first table name available in the from array as all your tables have the field name and adding the condition for the first selected table will work as it would be joined with the next table with ON condition.
And I have removed the select() trait override from the class as we won't be needing it.

Increase ASC limit clause for search results

I would like to be able to list 1000 results, however I am being limited to 20 due to the ASC Limit with the gem thinking sphinx.
How can I increase the ASC Limit 0, 20 to 0, 1000?
SELECT GEODIST(0.5904448859496816, -1.464156709498043, latitude, longitude) AS geodist, *
FROM `location_core`
WHERE `geodist` BETWEEN 0.0 AND 200000.0 AND `sphinx_deleted` = 0
ORDER BY `geodist` ASC
LIMIT 0, 20
Is this something I have to modify with MYSQL?
controller:
def index
location = Location.find_by_zipcode params[:zipcode]
latitude = location.latitude * Math::PI / 180
longitude = location.longitude * Math::PI / 180
location_ids = Location.search_for_ids(
:geo => [latitude, longitude],
:with => {:geodist => 0.0..200_000.0}
)
#users = User.where(:location_id => location_ids)
end
The ASC 0,20 is fine.
Change
:geo => [latitude, longitude],
:with => {:geodist => 0.0..200_000.0}
to
:geo => [latitude, longitude],
:with => {:geodist => 0.0..200_000.0},
:per_page => 1_000