NelmioApiDocBundle doesn't work “No operations defined in spec!” Symfony 3.4 - symfony-3.4

I want to configure nelmio to my symfony 3 project. I installed the bundle but at the end I get a message of no operations defined !!!!
Whats's wrong? Any ideas?
/**
* List the rewards of the specified user.
*
* This call takes into account all confirmed awards, but not pending or refused awards.
*
* #Route("/product", name="product", methods={"GET"})
* #SWG\Response(
* response=200,
* description="Returns the rewards of an user",
* #SWG\Schema(
* type="array",
* #SWG\Items(ref=#Model(type=Reward::class, groups={"full"}))
* )
* )
* #SWG\Parameter(
* name="order",
* in="query",
* type="string",
* description="The field used to order rewards"
* )
* #SWG\Tag(name="rewards")
* #Security(name="Bearer")
*
*/
public function getProducts()
{
$product = $this->entityManager->getRepository(Product::class)->getProducts();
$productSerializer = $this->serializer->serialize($product, 'json');
return new JsonResponse($productSerializer);
}

Related

call the first feature from the second feature file, failed without specified clue

Run the first.feature file successfully,however, call it from the second.feature failed without any clue to analysis. Do you have any idea help me find the root cause?
The source of my first.feature:
Feature: 采样管理-样本登记
Background: 读取随机生成的条形码、手机号、采样类型等作为入参
* url baseURL
* def randomData = Java.type('utils.RandomData')
* def barcode = randomData.getRandom(11)
* def randomPhone = randomData.getTelephone()
* def sampletype = randomData.getNum(0,1)
Scenario: 输入合法参数进行正常样本登记,确认能够登记成功
Given path 'iEhr/PersonSample'
# * header Content-type = 'application/x-www-form-urlencoded; charset=UTF-8'
* cookies { JSESSIONID: '#(jsessionID)',SESSION: '#(sessionID)', ACMETMP: '#(acmetmpID)'}
* def autoMotherName = "autoMname"+ barcode
# * def confData = {mothername: "#(autoMotherName)", barcode: "#(barcode)", mobile: '#(randomPhone)', sampletype:"#(sampletype)" }
# 设置sampletype为1,已被采样
* def confData = {mothername: "#(autoMotherName)", barcode: "#(barcode)", mobile: '#(randomPhone)', sampletype:"1" }
# 打印入参变量输出
* print confData
# 用例与数据分离
* def paramObj = read('classpath:mainFlow/sampleSaveReqTest.json')
* print paramObj
* form field param = paramObj
When method post
Then status 200
* json result = response[0].result
* def personId = result[0].personid
* def sampleid = result[0].sampleid
* print personId
* print sampleid
The source of my second.feature:
Feature: 提交递送样本
Background:
* def sampleResult = call read('classpath:mainFlow/first.feature')
* print sampleResult
I run the first.feature singly, it works. However, karate reports the error below after running the second.feature. Any idea how can I debug to find the root cause? I have no idea what's wrong with the second read. Many thanks!
* def sampleResult = call read('classpath:mainFlow/first.feature')
-unknown-:14 - javascript evaluation failed: read('classpath:mainFlow/first.feature'), null
Look for some issue with karate-config.js. As Babu said in the comments, it is very hard to make out what the problem is, I suggest you follow this process: https://github.com/intuit/karate/wiki/How-to-Submit-an-Issue
Also try if the latest preview version 0.9.3.RC2 is better at showing what the error is.
If you can replicate the problem as a small example, it will help us - because we really need to do better at showing more useful error logs, instead of just null.

API Platform and custom POST operation with custom body

I hope I'm right to ask this. I've looked at (almost) all similar concern but I ain't satisfied yet.
I'm working on a User entity and for days (weeks actually) now i'm trying to POST a user with a custom body. Here's some part of my entity User :
/**
* #ApiResource(
* normalizationContext={"groups"={"read"}},
* denormalizationContext={"groups"={"write"}},
* itemOperations={
* "get",
* "put",
* "delete",
* "get_active_user"={
* "method"="GET",
* "path"="/users/active/me",
* "controller"=UserReadAction::class,
* "defaults"={"_api_receive"=false},
* "swagger_context"={
* "parameters"={
*
* }
* }
* },
* },
* collectionOperations={
* "change_password"={
* "method"="POST",
* "path"="/users/active/changepassword",
* "controller"=UserChangePasswordAction::class,
* "normalization_context"={"groups"={"afup"}},
* "defaults"={"_api_receive"=false},
* "swagger_context"={
* "summary" = "Change user password",
* "parameters"={
* {
* "name" = "User",
* "in" = "body",
* "schema" = {
* "type" = "object",
* "properties" = {
* "password" = {"type"="string"},
* "nom" = {"type"="string"},
* }
* },
* "required" = "true",
* }
* },
* }
* }
* }
* )
* #ORM\Entity(repositoryClass="App\Repository\UserRepository")
* #ORM\Table(name="users")
*/
class User implements UserInterface
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
* #Groups({"read", "write", "afup"})
*/
private $id;
Here is the controller:
namespace App\Controller\SDK;
use App\Entity\User;
use App\Service\SDK\UserService;
use Symfony\Component\Security\Core\Security;
class UserChangePasswordAction
{
public function __invoke(User $data)
{
var_dump($data);die;
}
}
And the services.yaml (some part) file
services:
# default configuration for services in *this* file
_defaults:
autowire: true # Automatically injects dependencies in your services.
autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
public: false # Allows optimizing the container by removing unused services; this also means
# fetching services directly from the container via $container->get() won't work.
# The best practice is to be explicit about your dependencies anyway.
# makes classes in src/ available to be used as services
# this creates a service per class whose id is the fully-qualified class name
App\:
resource: '../src/*'
exclude: '../src/{DependencyInjection,Entity,Migrations,Tests,Kernel.php}'
# controllers are imported separately to make sure services can be injected
# as action arguments even if you don't extend any base controller class
App\Controller\:
resource: '../src/Controller/*'
tags: ['controller.service_arguments']
When I try this (see var_dump in controller), i get an error saying:
Cannot autowire argument $data of "App\Controller\SDK\UserChangePasswordAction()": it references class "App\Entity\User" no such service exists
I read the official doc and it seems that the _invoke method should automatically retrieve the entity. But it does not work for me.
Notice: I also defined a custom item operation "get_active_user" and it works fine.
Please I would like to understand :
what I did wrong,
how it actually works,
Thank you.
EDIT:
In the collectionOperation definition, i removed the following setting which means that we manually want to handle data (User) retrieval :
"defaults"={"_api_receive"=false},
Now, the controller returns an empty User entity, not an error. I still can't get the submitted data.
The edit of my question fix the concern. Actually, I just needed to remove this annotation from the POST opration definition :')
"defaults"={"_api_receive"=false},
Now, when I submit the data, I get them as on the following image :
This annotation is important when you write custom GET operation.
It is not working because that is a CollectionOperation. In this case, you can get the user through TokenStorageInterface
namespace App\Controller\SDK;
use App\Entity\User;
use App\Service\SDK\UserService;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
class UserChangePasswordAction
{
private $tokenStorage;
public function __construct(TokenStorageInterface $tokenStorage)
{
$this->tokenStorage = $tokenStorage;
}
public function __invoke(Request $request) //Get request if you want o keep args empty
{
var_dump($this->tokenStorage->getToken()->getUser());die;
}
}

Cannot convert to map when re-use one feature on other directory

I have read: https://stackoverflow.com/search?q=%5Bkarate%5Dcannot+convert+to+map and https://github.com/intuit/karate/issues/544
I am using karate-0.8.0
I have one feature which will be re-used on A directory, the content like:
#ignore
Feature:
Background:
* url baseUrl
* def Sign = Java.type('cruiser.token.Sign')
* configure afterScenario =
"""
function() {
if (karate.info.errorMessage != null) {
karate.log(karate.info.errorMessage);
}
}
"""
Scenario:
* def ck = Sign.execute('#(uid)')
* path '/rest/n/rt/upload'
* cookies ck
* multipart fields '#(fo)'
* multipart file rt = { read: 'classpath:cruiser/http/rt/A/123.mp3', filename: '123.mp3', contentType: 'audio/mp3' }
* method post
* status 200
* match response contains { result: 1 }
And have other one feature file on B directory, content like this:
Feature:
Background:
Scenario:
* def fo =
"""
{
'title': '你好!',
'description': '很好听哦'
}
"""
* def x = call read('classpath:cruiser/http/rt/A/upload-base.feature') { uid: 33, fo: '#(fo)' }
* match x.response contains { result: 1 }
* print x.response.feed.id
its runner name is XRunner.java
when mvn test -Dtest=XRunner, the error info:
Running cruiser.http.rt.B.XRunner
11:25:33.138 [main] INFO com.intuit.karate.junit4.Karate - Karate version: 0.8.0
11:25:33.896 [main] ERROR com.intuit.karate - feature call failed: classpath:cruiser/http/rt/A/upload-base.feature
arg: {uid=33, fo={title=你好!, description=很好听哦}}
cannot convert to map: '#(fo)'
Failed scenarios:
cruiser/http/rt/B/x.feature:3 # Scenario:
Both these lines are wrong:
* def ck = Sign.execute('#(uid)')
* multipart fields '#(fo)'
Read this: https://github.com/intuit/karate#rules-for-embedded-expressions
In Karate, expressions are pure JS by default. So just do this:
* def ck = Sign.execute(uid)
* multipart fields fo

Java jsch and resuming file upload after interruption?

I'm currently using in my code the com.jcraft.jsch library so that I can upload a file(or multiple files) from my local machine to a certain remote one. With file sizes of 5KB, 100KB, 200KB I don't have any concerns. However, I have one big concern when I tend to upload a file with file size 500MB , 1GB, 2GB and above, because there is always the possibility that the internet connection could fail on either side (local machine or remote)
I did a little research of my own and found that the Library has a field called RESUME, which refers to "file transfer mode" , but I haven't found an explanation about its proper use.
So my question is : Is there a way if the connection fails , after it is fixed, the file transfer continues from the point it was interrupted ?
I just "solved" this on my application and thought I would share what I learned.
I looked into how the RESUME is working and found that it depends on which methods you are using. For me I was using both a PipedInputStream and a PipedOutputStream since I might be transferring to/from local files or even both to/from remote servers.
I found that for me I provided my PipedOutputStream to the get method with no mode provided (defaults to OVERWRITE) and then provided my PipedInputStream to the put method with a parameter of RESUME. The put method progressed my InputStream the number of bytes equal to the current size of the file I am sending to.
This took a while as I was already progressing my PipedOutputStream X number of bytes and then the PipedInputStream was progressing another X bytes and I was getting significant gaps. I found this out by looking at the ChannelSftp source code
Of course this will be different if you are not doing the exact same thing as me, but if your source or destination are local you may not need to worry about that. I would try looking at the source code if you can't figure out how you are doing it.
I am using Grails so this may not work exactly for you, but here is what I did
/*
* This was initially copied from
* <a href="http://www.intelligrape.com/blog/2013/04/04/using-ftp-with-grails/">
* http://www.intelligrape.com/blog/2013/04/04/using-ftp-with-grails/</a> for
* the basic structure. JavaDoc and additional method were added as needed.
*
* #author Puneet Behl
* #author jonathan.tinsman
*/
class FtpService {
/**
* Gets the file from the server and loads it into the provided output stream
*
* #param outputStream
* - the output stream to have the file loaded to
* #param fileName
* - the desired file
* #param ftpCredential
* -the server credentials
*/
def load(OutputStream outputStream, String fileName, FtpCredential ftpCredential) {
connect(ftpCredential) { ChannelSftp sftp ->
sftp.get fileName, outputStream, new FtpMonitor()
}
}
/**
* Writes the file on the server
*
* #param inputStream
* - the input stream for writing
* #param fileName
* - the file name
* #param mode
* - the mode for the transfer (defaults to {#link ChannelSftp#OVERWRITE}
* #param ftpCredential
* - the server credentials
*/
def save(InputStream inputStream, String fileName, Integer mode = ChannelSftp.OVERWRITE, FtpCredential ftpCredential) {
connect(ftpCredential) { ChannelSftp sftp ->
sftp.put inputStream, fileName, mode
}
}
/**
* Transfers the file from the input server to the output server.
* <p>
* The usage of {#link PipedInputStream} and {#link PipedOutputStream} is
* from OsterMiller.org
*
* #param fileName
* - the file name
* #param inputFtpCredential
* - the input server
* #param outputFtpCredential
* - the output server
* #param mode
* - the mode for the transfer (defaults to {#link ChannelSftp#OVERWRITE}
*/
def transfer(String fileName, FtpCredential inputFtpCredential, FtpCredential outputFtpCredential, Integer mode = ChannelSftp.OVERWRITE) {
// To change the size of the buffer, add an int with the desired pipe
// size. The default is 1024
PipedInputStream input = new PipedInputStream();
PipedOutputStream output = new PipedOutputStream(input);
// Starting in different threads so they do not deadlock each other
new Thread(
new Runnable(){
public void run(){
new FtpService().load output, fileName, inputFtpCredential
}
}
).start();
/*
* only passing the mode to the "save" as the save will progress the
* input stream on it's own.
*
* If we pass the mode to the "load" method, then there will be a gap
* in the data as the "load" will progress the stream xx bytes and the
* "save" will progress it another xx bytes (the size of the existing
* file).
*/
save input, fileName, mode, outputFtpCredential
}
/**
* Connect to the server and call the provided ChannelSftp Closure.
*
* #param ftpCredential
* - the server to connect to
* #param closure
* - the closure to call
* #param disconnectOnFinish
* - to disconnect the Session when the Closure is done (defaults to true)
*/
private def connect(FtpCredential ftpCredential, Closure closure, boolean disconnectOnFinish = true) {
Session session = null
ChannelSftp sftp = null
try {
JSch jSch = new JSch()
session = jSch.getSession ftpCredential?.username, ftpCredential?.server, ftpCredential?.port
session.setConfig "StrictHostKeyChecking", "no"
if (ftpCredential?.password) {
session.password = ftpCredential?.password
} else {
File keyFile = new File("${grailsApplication.config.pathToKeyFile}")
jSch.addIdentity(keyFile?.absolutePath)
}
session.connect()
Channel sFtpChannel = session.openChannel "sftp"
sFtpChannel.connect()
sftp = sFtpChannel as ChannelSftp
sftp.cd ftpCredential?.remoteBaseDir
closure.call sftp
} catch (Exception ex) {
ex.printStackTrace()
} finally {
if (disconnectOnFinish) {
sftp?.exit()
session?.disconnect()
}
}
}
}

zf2 annotation for select element

I'm getting a bit confused with zf2 annotations, I created a few elements based on this tutorial:
/**
* #Annotation\Attributes({"type":"text" })
* #Annotation\Required(false)
* #Annotation\Options({"label":"Cardholder's Name: *:"})
*/
protected $cardholder;
For simple text all is working fine but I'm stuck when try to create a select element.
If you know any tutorial or github repo please let me know.
Problem was in view
so to get select you need
added example for validation and filtering
/**
* #Annotation\Attributes({"type":"text" })
* #Annotation\Options({"label":"Cardholder's Name: *:"})
* #Annotation\Required(false)
* #Annotation\Filters({"name":"StripTags"},{"name":"StringTrim"}})
* #Annotation\Validator({"name":"StringLength","options":{"min":"1", "max":"20"}})
*/
protected $cardholder;
/**
* #Annotation\Type("Zend\Form\Element\Select")
* #Annotation\Options({"label":"Description"})
* #Annotation\Attributes({"options":{"1":"Visa","2":"Maestro"}})
*/
protected $cardType;
and in view
<dt><?php echo $this->formLabel($form->get('cardholder')); ?></dt>
<dd><?php
echo $this->formInput($form->get('cardholder'));
echo $this->formElementErrors($form->get('cardholder'));
?></dd>
<dt><?php echo $this->formLabel($form->get('cardType')); ?></dt>
<dd><?php
echo $this->formSelect($form->get('cardType'));
echo $this->formElementErrors($form->get('cardType'));
?></dd>
Try this:
/**
* #Annotation\Type("Zend\Form\Element\Select")
* #Annotation\Required(false)
* #Annotation\Options({"label":"Cardholder's Name: *:", "value_options":{"1":"VISA", "2":"MASTER CARD", "3":"AMERICAN EXPRESS"}})
*/
protected $cardholder;
Try this
/**
* #Annotation\Type("Zend\Form\Element\Select")
* #Annotation\Required({"required":"false" })
* #Annotation\Filter({"name":"StringTrim"})
*
*
*/