How can I use same code in different functions in Symfony Controller? - function

In my Controller I am using several functions. In this functions I am using similar code.
So I am wondering if there is a possibility outsource this code to not have to write it repeatedly. If this is possible, what would be the best way to do it?
class PagesController extends AbstractController
{
/**
* #Route("/documents/{slug}", name="documents", methods={"GET","POST"})
*/
public function documents($slug, Request $request)
{
$page = $this->getDoctrine()->getRepository(Pages::class)->findOneBy(['slug'=>$slug]);
$entityManager = $this->getDoctrine()->getManager();
$cmf = $entityManager->getMetadataFactory();
$classes = $cmf->getMetadataFor($relation_name);
$fieldMappings = $classes->fieldMappings;
$associationMappings = $classes->associationMappings;
$fields = (object)array_merge((array)$fieldMappings, (array)$associationMappings);
}
/**
* #Route("/blog/{slug}", name="single", methods={"GET","POST"})
*/
public function blog($slug, Request $request)
{
$page = $this->getDoctrine()->getRepository(Pages::class)->findOneBy(['slug'=>$slug]);
$entityManager = $this->getDoctrine()->getManager();
$cmf = $entityManager->getMetadataFactory();
$classes = $cmf->getMetadataFor($relation_name);
$fieldMappings = $classes->fieldMappings;
$associationMappings = $classes->associationMappings;
$fields = (object)array_merge((array)$fieldMappings, (array)$associationMappings);
}
/**
* #Route("/contact/{slug}", name="contact", methods={"POST", "GET"})
*/
public function contact($slug, Request $request)
{
$page = $this->getDoctrine()->getRepository(Pages::class)->findOneBy(['slug'=>$slug]);
$entityManager = $this->getDoctrine()->getManager();
$cmf = $entityManager->getMetadataFactory();
$classes = $cmf->getMetadataFor($relation_name);
$fieldMappings = $classes->fieldMappings;
$associationMappings = $classes->associationMappings;
$fields = (object)array_merge((array)$fieldMappings, (array)$associationMappings);
}
}

You can use private method and call it, but in your case you could use Page typehint right in the parameter:
/**
* #Route("/contact/{slug}", name="contact", methods={"POST", "GET"})
*/
public function contact(Page $slug, Request $request)

The keyword here is services. Move your business logic to a other classes and auto-inject it in your controller using autowiring. This is a Symfony Best Practice:
Symfony follows the philosophy of "thin controllers and fat models".
This means that controllers should hold just the thin layer of
glue-code needed to coordinate the different parts of the application.
You should read about these best practices!
You can inject services in your controller class and in a specific action:
class PagesController extends AbstractController
{
public function __construct(Rot13Transformer $transformer)
{
$this->transformer = $transformer;
}
/**
* #Route("/documents/{slug}", name="documents", methods={"GET","POST"})
*/
public function documents($slug, Request $request, PagesRepository $repo)
{
$page = $repo->findOneBy(['slug'=>$slug]);
$foo = $repo->doSomethingDifferentWithEntities($page)
$bar = $this->transformer->transform($foo);
}
}

#Jarla Additionally to #Stephan Vierkant answer you can use #ParamConverter annotation
In your case, it will be:
/**
* #Route("/documents/{slug}", name="documents", methods={"GET","POST"})
* #ParamConverter("page", options={"mapping": {"slug": "slug"}})
*/
public function documents(Page $page, Request $request)
{
$foo = $repo->doSomethingDifferentWithEntities($page)
$bar = $this->transformer->transform($foo);
}

Related

Controller not defined laravel

the error :
Action App\Http\Controllers\formController#form not defined. (View: C:\xampp\htdocs\ucar3\resources\views\layouts\Form.blade.php) (View: C:\xampp\htdocs\ucar3\resources\views\layouts\Form.blade.php)
I tried changing the route in web.php
web.php
Route::resource('Inscription','inscriController');
Controller
class FormController extends Controller
{
public function show()
{
return view('pages.Inscription');
}
public function insert(Request $request)
{
$Cin = $request->input('Cin');
$nom = $request->input('nom');
$prenom = $request->input('prenom');
$email = $request->input('email');
$telephone = $request->input('telephone');
$specialite = $request->input('specialite');
$typedediplome = $request->input('typedediplome');
$mentiondiplome = $request->input('mentiondiplome');
$redoublement = $request->input('redoublement');
$communication = $request->input('communication');
$publication = $request->input('publication');
$experiencePedagogiqueSecondaire = $request
->input('experiencePedagogiqueSecondaire');
$experiencePedagogiqueSupérieur = $request
->input('experiencePedagogiqueSupérieur');
$data = array(['Cin'=>$Cin,
'nom'=>$nom,
'prenom'=>$prenom,
'email'=>$email,
'telephone'=>$telephone,
'specialite'=>$specialite,
'typedediplome'=>$typedediplome,
'mentiondiplome'=>$mentiondiplome,
'redoublement'=>$redoublement,
'communication'=>$communication,
'publication'=>$publication,
'experiencePedagogiqueSecondaire'=>$experiencePedagogiqueSecondaire,
'experiencePedagogiqueSupérieur'=>$experiencePedagogiqueSupérieur
]);
DB::table('users')->insert($data);
return view('pages.success');
}
}
Model
class form extends Model
{
public $table = "form";
protected $fillable = [
'Cin',
'nom',
'prenom',
'telephone',
'email',
'specialite',
'typedediplome',
'mentiondiplome',
'redoublement',
'communication',
'publication',
'experiencePedagogiqueSecondaire',
'experiencePedagogiqueSupérieur'
];
public $timestamps = true;
}
As the Error says
formController#form not defined.
but in your class you've
FormController extends Controller
Please check if you are calling FormController with lower case 'F'.
I think you have problems with your inscriController and your routes, use the following code:
web.php
use App\Http\Controllers\inscriController;
Route::resource('Inscription', inscriController::class);
app/Http/Controllers.php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
class inscriController extends Controller {
public function __construct() {
$this->middleware('auth');
}
}
Check if you set the correct namespace in the FormController.php
You are also missing a function form inside your FormController.

Larvel Eloquent Model save function is not saving but not error

My problem at the moment is that I want to save some values to the database but the don't get saved and I don't get an error..
Both, either $product-save(); or $product-update(array(...)) are not working and I cannot tell why.. My ASIN Model looks fine and is filled with the right fillable attributes...
You guys know why it isn't working?
My Laravel Version: Laravel Framework 5.5.36
This is my class so far:
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\ASIN;
class CheckPrice extends Command
{
/**
* The name and signature of the console command.
*
* #var string
*/
protected $signature = 'post:CheckPrice';
/**
* Create a new command instance.
*
* #return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* #return mixed
*/
public function handle() {
$product = ASIN::find(1410);
$product->price = "HELLO";
$product->amountSaved = "HELLO";
$product->percentageSaved = "HELLO";
$product->url = "HELLO";
$product->imgUrl = "HELLO";
$product->save();
//$product->update(array("price" => "HELLO", "amountSaved" => "HELLO", "percentageSaved" => "HELLO", "url" => "HELLO", "imgUrl" => "HELLO"));
$this->printProduct(ASIN::find(1410));
}
My ASIN Model so far:
namespace App;
use Illuminate\Database\Eloquent\Model;
class ASIN extends Model
{
protected $connection = 'facebook_amazon';
public $table = "ASINS";
protected $fillable = [
'ASIN',
'price',
'amountSaved',
'percentageSaved',
'category',
'url',
'imgUrl',
'showApp'
];
}
Kind regards and Thank You!
Use this in the handle methode
$product = App\ASIN::find(1410);
Or while impoting ASIN model use this if you want to keep the handle methode same
use App\ASIN as ASIN;
Use Laravel logs:
if(!$product->save()){
foreach($products->errors() as $error){
Log::info($error);
}
}
Hope this help.

Invalid argument in foreach loop using a model

Hey I am making a code in which I m using foreach loop but its giving me error of invalid argument.
Loop of my code is
public function handle($request, Closure $next)
{
foreach(Auth::user()->User as $role){
if($role->role == 'doctor')
{
return $next($request);
}
}
return redirect('');
}
And the model is
<?php
namespace App;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
use Notifiable;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'name', 'email', 'password',
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'password', 'remember_token',
];
}
Please tell me what I am doing wrong.
You can't do a foreach on Auth:user(). If you want to validate the role of a user, you can get the user object that is doing the request and validate the role, for example:
public function handle($request, Closure $next)
{
if($request->user()->rol == 'admin'){
return $next($request);
}
return redirect('/something');
}

How to create nested objects with FOSRestBundle and FormType?

I'm developing an API with symfony2 + FOSRestBundle and I have two errors.
Below is my code:
Property
/**
* Property
*
* #ORM\Table(name="property")
* #ORM\Entity
* #ORM\InheritanceType("JOINED")
* #ORM\DiscriminatorColumn(name="discr", type="string")
* #ORM\DiscriminatorMap({"house" = "House"})
*/
abstract class Property {
/**
* #ORM\OneToMany(targetEntity="Image", mappedBy="property", cascade={"persist"})
* */
private $images;
function getImages() {
return $this->images;
}
function setImages($images) {
$this->images = $images;
}
}
House
class House extends Property
{
/* More code */
}
Image
class Image {
/**
* #ORM\Column(name="content", type="text", nullable=false)
*/
private $content;
/**
* #ORM\ManyToOne(targetEntity="Property", inversedBy="images")
* #ORM\JoinColumn(name="propertyId", referencedColumnName="id")
* */
private $property;
}
PropertyType
class PropertyType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder->add('images');
$builder->get('images')
->addModelTransformer(new CallbackTransformer(
function($images) {
$image = new \Cboujon\PropertyBundle\Entity\Image();
$image->setContent('test of content');
return array($image);
}, function($imagesContents) {
}));
}
HouseRESTController
/**
* #View(statusCode=201, serializerEnableMaxDepthChecks=true)
*
* #param Request $request
*
* #return Response
*
*/
public function postAction(Request $request)
{
$entity = new House();
$form = $this->createForm(new HouseType(), $entity, array("method" => $request->getMethod()));
$this->removeExtraFields($request, $form);
$form->handleRequest($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($entity);
$em->flush();
return $entity;
}
When I create a new house, I send this (simplified) JSON:
{"images":["base64ContentImage_1", "base64ContentImage_2"]}
First Problem: The $images parameter in the first function passed to the CallbackTransformer is NULL. Why?
Second problem: I order to test and understand the first problem, I forced to create an image entity as you can see but I get a JSON response with the error "Entities passed to the choice field must be managed. Maybe persist them in the entity manager?"
Can anyone help me to solve any of two problem?
I have found one solution
I have been created ImageType
public function buildForm(FormBuilderInterface $builder, array $options)
{
parent::buildForm($builder, $options);
$builder
->add('content')
;
}
And also I have been modified PropertyType
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('title')
->add('description')
->add('price')
->add('services')
->add('images', 'collection', array(
'type' => new ImageType(),
'allow_add' => true,
))
;
}
And finally, I was changed the JSON structure of my request:
{"images":[{content: "base64ContentImage_1"}, {content:"base64ContentImage_2"}]}

phpunit mock method called in constructor

I test a config class, which is parsing a config file and allows me to get the various settings for an app.
My goal is to mock the parse() method of the Config class, which is called in the constructor and to set what this method is returning in the constructor.
This way, it prevents file_get_contents() from being called (in the parse() method) and enables me to have a Config class with the config property already set to contain an array of properties.
But I haven't succeeded doing that.
Here is the code:
The config class:
<?php namespace Example;
use Symfony\Component\Yaml\Parser;
class Config
{
private $parser;
private $config;
public function __construct(Parser $parser, $filePath)
{
$this->parser = $parser;
$this->config = $this->parse($filePath);
}
public function parse($filePath)
{
$fileAsString = file_get_contents($filePath);
if (false === $fileAsString) {
throw new \Exception('Cannot get config file.');
}
return $this->parser->parse($fileAsString);
}
public function get($path = null)
{
if ($path) {
$config = $this->config;
$path = explode('/', $path);
foreach ($path as $bit) {
if (isset($config[$bit])) {
$config = $config[$bit];
}
}
return $config;
}
return false;
}
}
The test:
<?php namespace Example;
class ConfigTest extends \PHPUnit_Framework_TestCase
{
private function getConfigTestMock($configAsArray)
{
$parser = $this->getMockBuilder('\Symfony\Component\Yaml\Parser')
->getMock();
$configMock = $this->getMockBuilder('Example\Config')
->setConstructorArgs([$parser, $configAsArray])
->setMethods(['parse', 'get'])
->getMock();
$configMock->expects($this->once())
->method('parse')
->willReturn($configAsArray);
return $configMock;
}
/**
* #test
*/
public function get_returns_false_if_no_path_given()
{
$configMock = $this->getConfigTestMock(['param1' => 'value1']);
// Testing further...
}
}
I suggest you to make a functional test mocking the interaction with the file system, without do partial mocking of the tested class.
I recently discover the vfsStream library used in a great article of William Durand about Symfony2 and DDD.
So you can install this library in your composer.json (I tested the solution with the 1.4 version) and try this example test class:
<?php
namespace Acme\DemoBundle\Tests;
use Acme\DemoBundle\Example\Config;
use org\bovigo\vfs\vfsStream;
use Symfony\Component\Yaml\Parser;
class ConfigTest extends \PHPUnit_Framework_TestCase
{
/**
* #test
*/
public function valid_content()
{
$content = "param1: value1";
$root = vfsStream::setup();
$file = vfsStream::newFile('example.txt')
->withContent($content)
->at($root);
$filepath = $file->url();
$parser = new Parser();
$config = new Config($parser, $filepath);
$this->assertEquals("value1", $config->get("param1"));
}
}
Hope this help
For test the Config class you need to mock only the Parser and use the real Config class. As Example:
<?php
namespace Acme\DemoBundle\Tests;
use Acme\DemoBundle\Example\Config;
class ConfigTest extends \PHPUnit_Framework_TestCase
{
private function getConfigTestMock($configAsArray)
{
$parser = $this->getMockBuilder('\Symfony\Component\Yaml\Parser')
->getMock();
$parser->expects($this->once())
->method('parse')
->willReturn($configAsArray);
$configMock = new Config($parser,"fakePath");
return $configMock;
}
/**
* #test
*/
public function get_returns_false_if_no_path_given()
{
$configMock = $this->getConfigTestMock(['param1' => 'value1']);
$this->assertEquals("value1",$configMock->get("param1"));
// Testing further...
}
}
Hope this help