FOSRestBundle woes with Symfony4, 204 no content response - json

I've made a rest controller for Movie objects with a get action.
My database manager one movies with id:3.
When I try to access localhost:8000/api/movie/3 or any other idea for that matter it goes straight back to the page I came from, with only a hint of no content response.
[Tue May 29 16:06:42 2018] 127.0.0.1:61540 [204]: /api/movie/3
I have the following configurations:
services.yaml
services:
...
sensio_framework_extra.view.listener:
alias: Sensio\Bundle\FrameworkExtraBundle\EventListener\TemplateListener
...
routes/rest.yaml
movies:
type: rest
resource: App\Controller\MovieController
prefix: /api
packages/fos_rest.yaml
fos_rest:
param_fetcher_listener: true
allowed_methods_listener: true
routing_loader:
include_format: false
view:
view_response_listener: 'force'
format_listener:
rules:
- { path: '^/api', priorities: ['json'], fallback_format: 'json' }
zone:
- { path: ^/api/* }
packages/framework.yaml:
framework:
...
templating: { engines: ['twig'] }
And the following files:
Controller/MovieController.php
<?php
namespace App\Controller;
use FOS\RestBundle\Controller\Annotations as Rest;
use FOS\RestBundle\Routing\ClassResourceInterface;
use FOS\RestBundle\Controller\FOSRestController;
/**
* #Rest\RouteResource("Movie", pluralize=false)
*/
class MovieController extends FOSRestController implements ClassResourceInterface {
/**
* #Rest\View()
* #Rest\Get("/movie/{id}")
*/
public function getAction(string $id) {}
}
Entity/Movie.php
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass="App\Repository\MovieRepository")
*/
class Movie {
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=32)
*/
private $title;
public function __construct($title) {
$this->title = $title;
}
...
}
Debug router is giving me this result:
$ bin/console debug:router | grep movie
get_movie GET ANY ANY /api/movie/{id}
[update]
Due to earlier wrong configurations I encountered the errors:
1
Warning: ReflectionObject::__construct() expects parameter 1 to be object, null given
2
An instance of Symfony\Bundle\FrameworkBundle\Templating\EngineInterface >must be injected in FOS\RestBundle\View\ViewHandler to render templates.
3
Type error: Argument 2 passed to Twig_Environment::render()
must be of the type array
4
There are no registered paths for namespace "FOSRest".
5
SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON data

I had to edit MovieController to return the object or return an exception.
MovieController.php
<?php
namespace App\Controller;
use App\Repository\MovieRepository;
use Doctrine\ORM\EntityManagerInterface;
use FOS\RestBundle\Controller\Annotations as Rest;
use FOS\RestBundle\Routing\ClassResourceInterface;
use FOS\RestBundle\Controller\FOSRestController;
/**
* #Rest\RouteResource("Movie", pluralize=false)
*/
class MovieController extends FOSRestController implements ClassResourceInterface {
/**
* #var EntityManagerInterface
*/
private $entityManager;
/**
* #var MovieRepository
*/
private $movieRepository;
public function __construct(
EntityManagerInterface $entityManager,
MovieRepository $movieRepository
) {
$this->entityManager = $entityManager;
$this->movieRepository = $movieRepository;
}
public function getAction(string $id) {
$movie = $this->movieRepository->find($id);
if($movie === null) {
throw new NotFoundHttpException();
}
return $this->view($movie);
}
}

you should add populateDefaultVars in the view annotation parameters like this :
/**
*
* #rest\View(populateDefaultVars=false)
*/

Related

How to bypass error "Invalid type "json_array""

I have an entity:
<?php
namespace App\Entity\Aero;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass="App\Repository\Aero\ScheduleRepository")
*/
class Schedule
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="date")
*/
private $dateOfFlight;
/**
* #ORM\Column(type="json")
*/
private $timeOfFlightAndStations = [];
public function getId(): ?int
{
return $this->id;
}
public function getDateOfFlight(): ?\DateTimeInterface
{
return $this->dateOfFlight;
}
public function setDateOfFlight(\DateTimeInterface $dateOfFlight): self
{
$this->dateOfFlight = $dateOfFlight;
return $this;
}
public function getTimeOfFlightAndStations(): ?array
{
return $this->timeOfFlightAndStations;
}
public function setTimeOfFlightAndStations(array $timeOfFlightAndStations): self
{
$this->timeOfFlightAndStations = $timeOfFlightAndStations;
return $this;
}
}
When I try to add field with type json_array via con make:entity it shows me error:
[ERROR] Invalid type "json_array".
My computer says that type "json_array" is invalid, but also says that it is in the list of valid types. How is it possible?
Please, help me, how to deal with this error?
Solved it by adding "json_array" manually instead of "json" in:
/**
* #ORM\Column(type="json_array")
*/

Trying to get property of non-object ErrorException (E_NOTICE)

I am trying to isert data in mysql using laravel, while I am getting the error ErrorException (E_NOTICE)
Trying to get property of non-object, where is the problem I dont know please help me.
my controller code is PublicationController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\publication;
use Auth;
class PublicationController extends Controller
{
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index()
{
//
return view('publications');
}
/**
* Show the form for creating a new resource.
*
* #return \Illuminate\Http\Response
*/
public function create()
{
//
}
/**
* Store a newly created resource in storage.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function store(Request $request)
{
//
publications::create([
'user_id' => Auth::user()->id,
'title' => request('title'),
'status' => request('status'),
'year' => request('research_area')
]);
return 'inserted';
}
/**
* Display the specified resource.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function show($id)
{
//
}
/**
* Show the form for editing the specified resource.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function edit($id)
{
//
}
/**
* Update the specified resource in storage.
*
* #param \Illuminate\Http\Request $request
* #param int $id
* #return \Illuminate\Http\Response
*/
public function update(Request $request, $id)
{
//
}
/**
* Remove the specified resource from storage.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function destroy($id)
{
//
}
}
While model code is given publication.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class publication extends Model
{
//
protected $fillable = ['title','status','year'];
}
The code of my route is given.
<?php
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
Route::get('/', function () {
return view('welcome');
});
Auth::routes();
Route::get('/home', 'HomeController#index')->name('home');
Route::get('education', 'EducationController#index');
Route::post('edu', 'EducationController#store');
Route::get('publications','PublicationController#index');
Route::post('pub','PublicationController#store');
The error is given Class ErrorException (E_NOTICE)
Trying to get property of non-object please help if any one know where is the problem
Consider placing PublicationController behind authentication middleware:
class PublicationController extends Controller
{
...
public function __construct()
{
$this->middleware('auth');
}
...
}
You can also use route groups:
Route::middleware(['auth'])->group(function () {
// your routes
});
If Auth::user() is null then Auth::user()->id will give you the exception you mentioned. Placing the routes or controller behind the middleware should solve this.
Edit
This assumes you are using Laravel 5.6 https://laravel.com/docs/5.6. This should work for 5.5 and 5.7.
Finally I found the answer of my question by just including 'user_id' in my model fillable arry and the above code works properly.
İ think you are not logged in so you get error when you try to get Auth::user()-id
Add this contractor to your class i think it should work for you
public function __construct(){
$this->middleware('auth');
}

Create multiple files to differentiate routes in laravel 5.4

This is my RouteServiceProvider that I have changed for creating multiple routes files.
namespace App\Providers;
use Illuminate\Routing\Router;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
class RouteServiceProvider extends ServiceProvider {
/**
* This namespace is applied to your controller routes.
*
* In addition, it is set as the URL generator's root namespace.
*
* #var string
*/
protected $namespace = 'App\Http\Controllers';
/**
* Define your route model bindings, pattern filters, etc.
*
* #return void
*/
public function boot(Router $router) {
//
parent::boot($router);
}
/**
* Define the routes for the application.
*
* #return void
*/
public function map(Router $router) {
$this->mapApiRoutes($router);
$this->mapWebRoutes($router);
//
}
/**
* Define the "web" routes for the application.
*
* These routes all receive session state, CSRF protection, etc.
*
* #return void
*/
protected function mapWebRoutes($router) {
$router->group(['namespace' => $this->namespace, 'middleware' => 'web'], function ($router) {
foreach (glob(app_path('Http/Routes/Web/*.php')) as $eachRoute) {
require $eachRoute;
}
});
}
/**
* Define the "api" routes for the application.
*
* These routes are typically stateless.
*
* #return void
*/
protected function mapApiRoutes($router) {
$router->group(['prefix' => 'api', 'namespace' => $this->namespace, 'middleware' => 'api'], function ($router) {
foreach (glob(app_path('Http/Routes/Api/*.php')) as $eachRoute) {
require $eachRoute;
}
});
}
}
Open your RouteServiceProvider
use Illuminate\Routing\Router; statement top of the file.
/**
* Define the routes for the application.
*
* #return void
*/
public function map(Router $router) {
$this->mapApiRoutes();
$this->mapWebRoutes($router);
//used Router object above in map function
}
This is only for web routes, You can also create for api , you need to create directory to distinguish it.
and finally :
protected function mapWebRoutes($router) {
$router->group(['namespace' => $this->namespace], function ($router) {
foreach (glob(base_path('routes/web/*.php')) as $eachRoute) {
require $eachRoute;
}
});
}

Yii2 missing required parameter in a constructor

I've created a new XmlResponseFormatter and now I want to change the rootTag.
class newXmlResponseFormatter extends XmlResponseFormatter
{
/**
* #var string the name of the root element.
*
*/
public $rootTag;
public function __construct($rootTag) {
parent::__construct();
$this->rootTag = $rootTag;
}
}
From a controller I set that value:
$xmlFormater = new newXmlResponseFormatter('newRootTag');
In the controller that value is available, and it sets in $rootTag but it threw the following exception:
exception 'yii\base\InvalidConfigException' with message 'Missing required parameter "rootTag" when instantiating "app\components\override\newXmlResponseFormatter".' in /var/www/html/Admin/vendor/yiisoft/yii2/di/Container.php:451
Does anyone know what can be a problem?
Thanks in advance!
First parameter in XmlResponseFormatter is $config, because XmlResponseFormatter extends Object class. You are violated liskov substitution principle.
You should rewrite your constructor like this:
class newXmlResponseFormatter extends XmlResponseFormatter
{
/**
* #var string the name of the root element.
*
*/
public $rootTag;
/**
* newXmlResponseFormatter constructor.
*
* #param string $rootTag
* #param array $config
*/
public function __construct($rootTag, $config = [])
{
$this->rootTag = $rootTag;
parent::__construct($config);
}
}
In yii2 you should call parent constructor after your code, and call parent init before your code.
$config need for simple configure model like this:
new newXmlResponseFormatter(['rootTag' => 'newRootTag']);

symfony2: JMSSerializerBundle changes the attribute name from "className" to "class_name"

I'm using the JMSSerializerBundle to serialize my entity.
but I have the following problem: the attribute name is "className" but in my Json object I get a "class_name".
this is my entity:
/**
* Events
*
* #ORM\Table()
* #ORM\Entity
*/
class Events
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
...
/**
* #var string
*
* #ORM\Column(name="className", type="string", length=255)
*/
private $className;
/**
* Set className
*
* #param string $className
* #return Events
*/
public function setClassName($className)
{
$this->className = $className;
return $this;
}
/**
* Get className
*
* #return string
*/
public function getClassName()
{
return $this->className;
}
...
}
this is my controller
class myController extends Controller{
public function loadAction($action){
$request=$this->get('request');
if($request->isXmlHttpRequest())
{
switch( $action ) {
case 'load':
$resultat=$this->getDoctrine()->getManager()->getRepository('ECMUserBundle:Events')
->findAll();
$serializer = $this->get('jms_serializer');
$resultat=$serializer->serialize($resultat, 'json');
echo $resultat;
exit();
break;
...
and this my Json
[{"id":90,"title":"holliday","start":"2014-03-25T01:00:00+0000","end":"2014-03-25T01:00:00+0000","class_name":"label-orange","allday":"true"}]
is this the logical behaviors?
As #mike said, you can use #SerializedName annotation to change serialized property name to arbitrary string.
Also, if you want to change naming strategy on application level. You can use the following workaround:
config.yml
parameters:
jms_serializer.serialized_name_annotation_strategy.class: JMS\Serializer\Naming\IdenticalPropertyNamingStrategy
Also, check this issue.
Check the documentation for the #SerializedName annotation:
http://jmsyst.com/libs/serializer/master/reference/annotations
#SerializedName:
This annotation can be defined on a property to define the serialized name for a property. If this is not defined, the property will be translated from camel-case to a lower-cased underscored name, e.g. camelCase -> camel_case.
If you just want to use the camel case version once, without annotations, use the IdenticalPropertyNamingStrategy:
$serializer = SerializerBuilder::create()->setPropertyNamingStrategy(new IdenticalPropertyNamingStrategy())->build();
Inside Symfony, it make way more sense to use a compiler pass, as it avoid losing the #SerializedName annotation.
<?php
namespace AppBundle\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
class JMSSerializerCompilerPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
$container->getDefinition('jms_serializer.serialized_name_annotation_strategy')
->replaceArgument(0, new Reference('jms_serializer.identical_property_naming_strategy'));
}
}