Laravel: Can't get post form - php

Me and my partner have been working a combined period of almost 11 hours trying to figure this out but we just can't seem to crack it.
We're building a web forum application in which users are able to make their own threads. We managed to get edit to work, although redirect still doesn't work right yet. We have an online preview over at http://detune-niuwang.c9users.io/
If you try using the 'New Thread' page and click on the submit button, it will just delete anything typed into the form and checking back on the Frontpage, no threads would have been created. The Edit functionality works though.
Here are some snippets of our code:
Routes.php
Route::resource('posts', 'Channel\Post\Posts');
Route::get('/', 'Channel\Post\Posts#index');
Controllers\Channel\Post\Posts.php
/**
* Show the form for creating a new post.
*
* #return Response
*/
public function create()
{
return view('posts.create');
}
/**
* Store the newly created post
*
* #param PostRequest $request
* #return Response
*/
public function store(PostRequest $request)
{
$postData = $this->post->create(['title', 'content']);
if($this->post->create($postData)) {
return redirect()->back()->withSuccess('Post successfully created.');
}
return redirect()->back()->withError($postData);
}
create.blade.php
#extends('_shared.master')
#section('title')
Create New Post
#endsection
#section('content')
<div class="panel panel-default">
<div class="panel-heading">New Thread</div>
<div class="panel-body">
{!! Form::open(['route' => 'posts.store', 'class' => 'form-horizontal'])!!}
#include('posts.form')
{!! Form::close() !!}
</div>
</div>
#stop
Models\Channel\Post\Post.php
<?php
namespace Detune\Models\Channel\Post;
use Illuminate\Database\Seeder;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
/**
* The database table used by the Model.
*
* #var string
*/
protected $table = 'posts';
/**
* The attributes that are mass assignable
*
* #var array
*/
protected $fillable = ['title', 'content', 'created_at'];
}
Repositories\PostRepository.php
<?php
namespace Detune\Repositories\Post;
use Detune\Models\Channel\Post\Post;
use Illuminate\Database\Eloquent\Collection;
/**
* Class PostRepository
* #Package Detune\Repository
*/
class PostRepository implements PostRepositoryInterface {
/**
* #var Post;
*/
protected $post;
/**
* #param Post $post
*/
public function __construct(Post $post)
{
$this->post = $post;
}
/**
* Create New Post
*
* #param array $postData
* #return Post|null
*/
public function create(array $postData)
{
return $this->post->create($postData);
}
/**
* Post Pagination
*
* #param array $filter
* #return collection
*/
public function paginate(array $filter)
{
return $this->post->paginate($filter['limit']);
}
/**
* Get Post by ID
*
* #param $id
* #return Post
*/
public function find($id)
{
return $this->post->find($id);
}
}
Repositories\PostRepositoryInterface.php
<?php
namespace Detune\Repositories\Post;
use Detune\Models\Channel\Post;
use Illuminate\Database\Eloquent\Collection;
/**
* Interface PostRepositoryInterface
* #package Detune\Repository
*/
interface PostRepositoryInterface {
/**
* Create New Post\
*
* #param array $postData
* #return Post
*/
public function create(array $postData);
/**
* Post Pagination
*
* #param array $filter
* #return collection
*/
public function paginate(array $filter);
/**
* Get Post by ID
* #param $post_id
* #return Post
*/
public function find($id);
}
Services\Post\PostService.php
<?php
namespace Detune\Services\Post;
use Detune\Services\Service;
use Illuminate\Contracts\Logging\Log;
use Illuminate\Support\ServiceProvider;
use Detune\Repositories\Post\PostRepositoryInterface;
/**
* Class PostService
* #package Detune\Services\Post
*/
class PostService extends Service {
/**
* #var PostRepositoryInterface
*/
protected $post;
/**
* #var Log
*/
protected $logger;
/**
* #param PostRepositoryInterface $post
* #param Log $logger
*/
public function __construct(PostRepositoryInterface $post, Log $logger)
{
$this->post = $post;
$this->logger = $logger;
}
/**
* Create New Post
*
* #param array $postData
* #return Post | null
*/
public function create()
{
try{
return $this->post->create($postData);
} catch (\Exception $e) {
$this->logger->error('Post->create: ' . $e->getMessage());
return null;
}
}
/**
* Post Pagination
*
* #param array $filter
* #return collection
*/
public function paginate(array $filter =[])
{
$filter['limit'] = 20;
return $this->post->paginate($filter);
}
/**
* Update the Post
*
* #param array $id
* #param array $postData
* #return bool
*/
public function update($id, array $postData)
{
try{
$post = $this->post->find($id);
$post->title = $postData['title'];
$post->content = $postData['content'];
return $post->save();
} catch (\Exception $e) {
$this->logger->error('Post->update: ' . $e->getMessage());
return false;
}
}
/**
* Delete Post
*
* #param $id
* #return mixed
*/
public function delete($id)
{
try {
$post = $this->post->find($id);
return $post->delete();
} catch (\Exception $e){
$this->logger->error('Post->delete: ' . $e->getMessage());
return false;
}
}
/**
* Get Post by ID
*
* #param $id
* #return Post
*/
public function find($id)
{
try {
return $this->post->find($id);
} catch (\Exception $e) {
$this->logger->error('Post->find: ' .$e->getMessage());
return null;
}
}
}
Any help with this are appreciated :)

The create method on an Eloquent model is normally a static method. In your code it seems to be called as if it's an instance method.
I believe you have (at least) 3 options.
Change your create call into an insert call. (I don't think this will return an instance of the Post model, just a boolean).
Call it statically Post::create($postData);
Use the newInstance method
$post = $this->post->newInstance($postData);
return $post->save() ? $post : null;

Related

Laravel model pass to view

Im using this library: https://www.laravelplay.com/packages/ycs77::laravel-wizard
I did all steps and have the same result like in the example.
Im trying to get data from database to each step.
Model (App/steps/intro/DropboxStep.php):
<?php
namespace App\Steps\Intro;
use Illuminate\Http\Request;
use Ycs77\LaravelWizard\Step;
use DB;
class DropboxStep extends Step
{
/**
* The step slug.
*
* #var string
*/
protected $slug = 'dropbox';
/**
* The step show label text.
*
* #var string
*/
protected $label = 'Dropbox';
/**
* The step form view path.
*
* #var string
*/
protected $view = 'steps.intro.dropbox';
/**
* Set the step model instance or the relationships instance.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Database\Eloquent\Model|\Illuminate\Database\Eloquent\Relations\Relation|null
*/
public function model(Request $request)
{
//
}
/**
* Save this step form data.
*
* #param \Illuminate\Http\Request $request
* #param array|null $data
* #param \Illuminate\Database\Eloquent\Model|\Illuminate\Database\Eloquent\Relations\Relation|null $model
* #return void
*/
public function saveData(Request $request, $data = null, $model = null)
{
//
}
/**
* Validation rules.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function rules(Request $request)
{
return [];
}
public function getOptions()
{
$stepa2 = DB::table('tutorials')->where('id', '2')->first();
return [
'stepa2' => $stepa2,
'Lucas',
];
}
}
View:
<div class="form-group">
{{ $stepa2 }}
</div>
Result:
Undefined variable: stepa2
Tried also through controller (IntroWizardController.php)
This is default controller:
<?php
namespace App\Http\Controllers;
use App\Steps\Intro\DropboxStep;
use App\Steps\Intro\H2NStep;
use App\Steps\Intro\PT4Step;
use Ycs77\LaravelWizard\Wizardable;
use DB;
class IntroWizardController extends Controller
{
use Wizardable;
/**
* The wizard name.
*
* #var string
*/
protected $wizardName = 'intro';
/**
* The wizard title.
*
* #var string
*/
protected $wizardTitle = 'Intro';
/**
* The wizard options.
*
* #var array
*/
protected $wizardOptions = [];
/**
* The wizard steps instance.
*
* #var array
*/
protected $steps = [
DropboxStep::class,
H2NStep::class,
PT4Step::class,
];
}
I added:
public function getOptions()
{
$stepa2 = DB::table('tutorials')->where('id', '2')->first();
return [
'stepa2' => $stepa2,
'Lucas',
];
}
Tried also in controller return to view, but then I get result from database in blank page, not with other parts.
Is it possible to pass database query to view with this library?
Thanks
EDIT:
With this routes:
Route::get('wizard/intro/dropbox', 'IntroWizardController#step1a', 'wizard.intro.dropbox');
Wizard::routes('wizard/intro', 'IntroWizardController', 'wizard.intro');
I get my result from database, but like I said before in white blank page:
But I want to get in this view like others (without query):
To pass any data from controller to blade view simply use these 2 options
option 1:
public function someFunction()
{
$model = DB::table('model_table')->where('id', '2')->first();
return view('blade_view_name', compact('model'));
}
option 2:
public function someFunction()
{
$model = DB::table('model_table')->where('id', '2')->first();
return view('blade_view_name')->with('model', $model);
}
if you have more or want more of variables you can chain the with() method like this:
return view('blade_view_name')
->with('model', $model)
->with('variable', 'Some other variable');

Laravel Policy bug

I have used Laravel Policies successfully in the past but am having issues with one currently.
In an ArticleController I have the following method:
/**
* Show the form for creating a new resource.
*
* #return \Illuminate\Http\Response
*/
public function create()
{
$this->authorize('create', Article::class);
$categories = $this->categories;
return view('editable.news.create', compact('categories'));
}
My ArticlePolicy looks like this:
<?php
namespace App\Policies;
use Illuminate\Auth\Access\HandlesAuthorization;
use App\User;
use App\Article;
class ArticlePolicy
{
use HandlesAuthorization;
/**
* Create a new policy instance.
*
* #return void
*/
public function __construct()
{
//
}
/**
* Determine whether the user can view the post.
*
* #param \App\User $user
* #param \App\Post $post
* #return mixed
*/
public function show(User $user, Article $article)
{
// If the article is published
if ($article->published) {
return true;
}
// A user with permission can view unpublished articles
if ($user->can('view unpublished articles')) {
return true;
}
// Authors can view their own unpublished posts
if ($user->username === $article->author->username) {
return true;
}
}
/**
* Determine whether the user can create posts.
*
* #param \App\User $user
* #return mixed
*/
public function create(User $user)
{
return true;
}
/**
* Determine whether the user can update the post.
*
* #param \App\User $user
* #param \App\Post $post
* #return mixed
*/
public function update(User $user, Article $article)
{
if ($user->can('edit own articles')) {
return $user->username === $article->author->username;
}
if ($user->can('edit any articles')) {
return true;
}
}
/**
* Determine whether the user can delete the post.
*
* #param \App\User $user
* #param \App\Post $post
* #return mixed
*/
public function delete(User $user, Article $article)
{
// A user can delete their own articles
if ($user->can('delete own articles')) {
return $user->username === $article->author->username;
}
// A user with permission can delete any article
if ($user->can('delete any articles')) {
return true;
}
}
}
You can see in the create method I am just returning true, this is deliberate.
Whenever I hit the create blade I always receive a 403 error.
I also have an accompanying test:
/** #test */
public function a_user_with_permission_can_create_an_article()
{
$this->setupPermissions();
$user = factory(User::class)->create();
$user->assignRole('news contributor');
$article = factory(Article::class)->raw(['excerpt' => null]);
$this->actingAs($user)
->get(route('thanos.articles.create'))
->assertStatus(200);
$this->post(route('thanos.articles.store'), $article);
$this->assertDatabaseHas('articles', [
'user_username' => $user->username,
'title' => $article['title']
]);
}

Error while inserting into db using doctrine ORM

I am trying to insert data into db ,but it shows some error like this
My model Entity
Request.php
is here `<?php
namespace EvolisClientRequest\Model\Entities;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
*/
class Request
{
/**
* #var \Ramsey\Uuid\Uuid
* #ORM\Id
* #ORM\Column(type="uuid")
* #ORM\GeneratedValue(strategy="CUSTOM")
* #ORM\CustomIdGenerator(class="Ramsey\Uuid\Doctrine\UuidGenerator")
*/
protected $id;
/**
* #ORM\ManyToMany(targetEntity="Salesperson", inversedBy="request")
* #ORM\JoinTable(name="request_salesperson")
* #var Salesperson
*/
private $salesperson;
/**
* #ORM\ManyToOne(targetEntity="Client", inversedBy="request")
* #var Client
*/
private $client;
/**
* #ORM\ManyToMany(targetEntity="Status", inversedBy="request")
* #ORM\JoinTable(name="request_status")
* #var Status
*/
private $status;
/**
* #ORM\Column(type="integer")
* #var Qualification
*/
private $qualification;
/**
* #return \Ramsey\Uuid\Uuid
*/
public function getId()
{
return $this->id;
}
/**
* #return Salesperson
*/
public function getSalesperson()
{
return $this->salesperson;
}
/**
* #param Salesperson $salesperson
*/
public function setSalesperson($salesperson)
{
$this->salesperson = $salesperson;
}
/**
* #return Client
*/
public function getClient()
{
return $this->client;
}
/**
* #param Client $client
*/
public function setClient($client)
{
$this->client = $client;
}
/**
* #return Status
*/
public function getStatus()
{
return $this->status;
}
/**
* #param Status $status
*/
public function setStatus($status)
{
$this->status = $status;
}
/**
* #return Qualification
*/
public function getQualification()
{
return $this->qualification;
}
/**
* #param Qualification $qualification
*/
public function setQualification($qualification)
{
$this->qualification = $qualification;
}
public function __construct($salesperson, $client, $status, $qualification) {
$this->salesperson = $salesperson;
$this->client = $client;
$this->status = $status;
$this->qualification = $qualification;
}
}`
Also my
DAO "RequestBaseDao.php" is here,which is automatically generated.
<?php
/*
* This file has been automatically generated by Mouf/ORM.
* DO NOT edit this file, as it might be overwritten.
* If you need to perform changes, edit the RequestDao class instead!
*/
namespace EvolisClientRequest\Model\DAOs;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\NonUniqueResultException;
use Mouf\Doctrine\ORM\Event\SaveListenerInterface;
use EvolisClientRequest\Model\Entities\Request;
/**
* The RequestBaseDao class will maintain the persistence of Request class into the request table.
*
* #method Request findByQualification($fieldValue, $orderBy = null, $limit = null, $offset = null)
* #method Request findOneByQualification($fieldValue, $orderBy = null)
* #method Request findBySurfaceMin($fieldValue, $orderBy = null, $limit = null, $offset = null)
* #method Request findOneBySurfaceMin($fieldValue, $orderBy = null)
* #method Request findBySurfaceMax($fieldValue, $orderBy = null, $limit = null, $offset = null)
* #method Request findOneBySurfaceMax($fieldValue, $orderBy = null)
* #method Request findByPriceMin($fieldValue, $orderBy = null, $limit = null, $offset = null)
* #method Request findOneByPriceMin($fieldValue, $orderBy = null)
* #method Request findByPriceMax($fieldValue, $orderBy = null, $limit = null, $offset = null)
* #method Request findOneByPriceMax($fieldValue, $orderBy = null)
* #method Request findByRequestDate($fieldValue, $orderBy = null, $limit = null, $offset = null)
* #method Request findOneByRequestDate($fieldValue, $orderBy = null)
*/
class RequestBaseDao extends EntityRepository
{
/**
* #var SaveListenerInterface[]
*/
private $saveListenerCollection;
/**
* #param EntityManagerInterface $entityManager
* #param SaveListenerInterface[] $saveListenerCollection
*/
public function __construct(EntityManagerInterface $entityManager, array $saveListenerCollection = [])
{
parent::__construct($entityManager, $entityManager->getClassMetadata('EvolisClientRequest\Model\Entities\Request'));
$this->saveListenerCollection = $saveListenerCollection;
}
/**
* Get a new persistent entity
* #param ...$params
* #return Request
*/
public function create(...$params) : Request
{
$entity = new Request(...$params);
$this->getEntityManager()->persist($entity);
return $entity;
}
/**
* Peforms a flush on the entity.
*
* #param Request
* #throws \Exception
*/
public function save(Request $entity)
{
foreach ($this->saveListenerCollection as $saveListener) {
$saveListener->preSave($entity);
}
$this->getEntityManager()->flush($entity);
foreach ($this->saveListenerCollection as $saveListener) {
$saveListener->postSave($entity);
}
}
/**
* Peforms remove on the entity.
*
* #param Request $entity
*/
public function remove(Request $entity)
{
$this->getEntityManager()->remove($entity);
}
/**
* Finds only one entity. The criteria must contain all the elements needed to find a unique entity.
* Throw an exception if more than one entity was found.
*
* #param array $criteria
*
* #return Request
*/
public function findUniqueBy(array $criteria) : Request
{
$result = $this->findBy($criteria);
if (count($result) === 1) {
return $result[0];
} elseif (count($result) > 1) {
throw new NonUniqueResultException('More than one Request was found');
} else {
return;
}
}
/**
* Finds only one entity by Qualification.
* Throw an exception if more than one entity was found.
*
* #param mixed $fieldValue the value of the filtered field
*
* #return Request
*/
public function findUniqueByQualification($fieldValue)
{
return $this->findUniqueBy(array('qualification' => $fieldValue));
}
}
My RequestDao.php where i can write queries.
<?php
namespace EvolisClientRequest\Model\DAOs;
use EvolisClientRequest\Model\Entities\Request;
/**
* The RequestDao class will maintain the persistence of Request class into the request table.
*/
class RequestDao extends RequestBaseDao {
/*** PUT YOUR SPECIFIC QUERIES HERE !! ***/
public function setdata()
{
/*$product = new Request();
$product->setStatus('Keyboard');
$product->setClient('000000001ae10dda000000003c4667a6');
$product->setSalesperson('Ergonomic and stylish!');
$product->setQualification('1111');
//var_dump($r);die();
$em = $this->getEntityManager();
$em->persist($product);
$em->flush();*/
$product= $this->create('Keyboard','000000001ae10dda000000003c4667a6','Ergonomic and stylish!','1111');
$this->save($product);
}
}
Finally my Controller "ContactController.php"
<?php
namespace EvolisClientRequest\Controllers;
use EvolisClientRequest\Model\DAOs\ClientDao;
use EvolisClientRequest\Model\Entities\Client;
use EvolisClientRequest\Model\Entities\Clients;
use EvolisClientRequest\Model\DAOs\RequestDao;
use EvolisClientRequest\Model\Entities\Request;
use EvolisClientRequest\Model\Entities\Requests;
use EvolisClientRequest\Model\DAOs\SalespersonDao;
use EvolisClientRequest\Model\Entities\Salesperson;
use EvolisClientRequest\Model\Entities\Salespersons;
use Mouf\Mvc\Splash\Annotations\Get;
use Mouf\Mvc\Splash\Annotations\Post;
use Mouf\Mvc\Splash\Annotations\Put;
use Mouf\Mvc\Splash\Annotations\Delete;
use Mouf\Mvc\Splash\Annotations\URL;
use Mouf\Html\Template\TemplateInterface;
use Mouf\Html\HtmlElement\HtmlBlock;
use Psr\Log\LoggerInterface;
use \Twig_Environment;
use Mouf\Html\Renderer\Twig\TwigTemplate;
use Mouf\Mvc\Splash\HtmlResponse;
use Doctrine\DBAL\DriverManager;
use Zend\Diactoros\Response\JsonResponse;
use Doctrine\Common\Collections\ArrayCollection;
/**
* TODO: write controller comment
*/
class ContactController {
/**
* The logger used by this controller.
* #var LoggerInterface
*/
private $logger;
/**
* The template used by this controller.
* #var TemplateInterface
*/
private $template;
/**
* The header of the page.
* #var HtmlBlock
*/
private $header;
/**
* The main content block of the page.
* #var HtmlBlock
*/
private $content;
/**
* The Twig environment (used to render Twig templates).
* #var Twig_Environment
*/
private $twig;
/**
* Controller's constructor.
* #param LoggerInterface $logger The logger
* #param TemplateInterface $template The template used by this controller
* #param HtmlBlock $content The main content block of the page
* #param Twig_Environment $twig The Twig environment (used to render Twig templates)
*/
public function __construct(LoggerInterface $logger, TemplateInterface $template, HtmlBlock $content, HtmlBlock $header, Twig_Environment $twig, ClientDao $clientDao, RequestDao $requestDao, SalespersonDao $salespersonDao) {
$this->logger = $logger;
$this->template = $template;
$this->content = $content;
$this->twig = $twig;
$this->header = $header;
$this->clientDao = $clientDao;
$this->requestDao = $requestDao;
$this->salespersonDao = $salespersonDao;
}
/**
* #URL("new.html")
*/
public function new() {
// TODO: write content of action here
// Let's add the twig file to the template.
$this->content->addHtmlElement(new TwigTemplate($this->twig, 'views/contact/new.twig', array("message"=>"world")));
$this->header->addHtmlElement(new TwigTemplate($this->twig, 'views/root/header.twig', array("message"=>"world")));
return new HtmlResponse($this->template);
}
/**
* #URL("saveData")
* For Saving the data
*/
public function saveData()
{
/*$newClient = $this->clientDao->create('hello', 'sarathchandran#122.com','8907263949');
$this->clientDao->save($newClient);*/
//$data = array();
//$data['salespersonDao']['salesperson'] = 'example#sales.com';
//$data['request']['qualification'] = 'abcdefgh';
//$newClient = $this->requestDao->create($data);
//$newClient = $this->requestDao->setQualification('Keyboard');
// $this->requestDao->save($newClient);
$user_data=$this->requestDao->setdata();
//return new JsonResponse([ "status"=>0 ]);
}
}
I am using Mouf framework.I am stuck with this problem.Someone Please help me to solve this problem.
Thanks in advance
As advised by #rokas, you should really start reading more about Doctrine. This is not a Mouf issue, this is clearly a Doctrine ORM issue so the appropriate doc is here: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/index.html
Here are a few tips:
Your controller calls the setdata method
$user_data=$this->requestDao->setdata();
The setdata method calls:
$product= $this->create('Keyboard','000000001ae10dda000000003c4667a6','Ergonomic and stylish!','1111');
Now, the create method is:
public function create(...$params) : Request
{
$entity = new Request(...$params);
$this->getEntityManager()->persist($entity);
return $entity;
}
This means that it will call the Request constructor with this parameters:
$entity = new Request('Keyboard','000000001ae10dda000000003c4667a6','Ergonomic and stylish!','1111');
Have a look at the Request constructor:
public function __construct($salesperson, $client, $status, $qualification) {
$this->salesperson = $salesperson;
$this->client = $client;
$this->status = $status;
$this->qualification = $qualification;
}
As you can see, the first parameter is $salesperson. You try to put the value "Keyboard" here. The $salesperson attribute is defined this way:
/**
* #ORM\ManyToMany(targetEntity="Salesperson", inversedBy="request")
* #ORM\JoinTable(name="request_salesperson")
* #var Salesperson
*/
private $salesperson;
/**
* #param Salesperson $salesperson
*/
public function setSalesperson($salesperson)
{
$this->salesperson = $salesperson;
}
Now, here is your problem I think.
The $salesperson property is defined as a "ManyToMany" association. So you really cannot put a string in here, it is a collection of Salesperson. By the way, you should not "set" anything either. The setter should be completely removed.
Instead, you should consider using it as per the documentation here: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/working-with-associations.html
For instance:
$request->getSalesPersons()->add($someObjectRepresentingAPerson);
Also, notice that since the $salesperson represents a collection of Salesperson object, your should really name it $salesPersons (plural form)

Wrong instance passed in Laravel DB post request

So I am working on a page in Laravel that generates invite codes upon email submission. I have run into this issue, every time when I enter my email into the form, it is supposed to generate an invite code an input it into my DB then redirect me. Instead I get this error code:
Argument 1 passed to myapp\Repositories\Invite\EloquentInviteRepository::__construct()
must be an instance of Illuminate\Database\Eloquent\Model, instance of
Illuminate\Foundation\Application given, called in /var/www/laravel/bootstrap/compiled.php
on line 4259 and defined
This is my EloquentInviteRepository.php file, apparently line 21 is the line in error:
<?php namespace myapp\Repositories\Invite;
use myapp\Repositories\Crudable;
use Illuminate\Support\MessageBag;
use myapp\Repositories\Repository;
use Illuminate\Database\Eloquent\Model;
use myapp\Repositories\AbstractRepository;
class EloquentInviteRepository extends AbstractRepository implements Repository, Crudable, InviteRepository {
/**
* #var Illuminate\Database\Eloquent\Model
*/
protected $model;
/**
* Construct
*
* #param Illuminate\Database\Eloquent\Model $user
*/
public function __construct(Model $model)
{
parent::__construct(new MessageBag);
$this->model = $model;
}
/**
* Find a valid invite by a code
*
* #param string $code
* #return Illuminate\Database\Eloquent\Model
*/
public function getValidInviteByCode($code)
{
return $this->model->where('code', '=', $code)
->where('claimed_at', '=', null)
->first();
}
/**
* Create
*
* #param array $data
* #return Illuminate\Database\Eloquent\Model
*/
public function create(array $data)
{
$data['code'] = bin2hex(openssl_random_pseudo_bytes(16));
return $this->model->create($data);
}
/**
* Update
*
* #param array $data
* #return Illuminate\Database\Eloquent\Model
*/
public function update(array $data){}
/**
* Delete
*
* #param int $id
* #return boolean
*/
public function delete($id){}
}
In case anyone was curious; the __construct() interface from Illuminate\Database\Eloquent\Model.php:
/**
* Create a new Eloquent model instance.
*
* #param array $attributes
* #return void
*/
public function __construct(array $attributes = array())
{
$this->bootIfNotBooted();
$this->syncOriginal();
$this->fill($attributes);
}
and Illuminate\Foundation\Application.php:
/**
* Create a new Illuminate application instance.
*
* #param \Illuminate\Http\Request $request
* #return void
*/
public function __construct(Request $request = null)
{
$this->registerBaseBindings($request ?: $this->createNewRequest());
$this->registerBaseServiceProviders();
$this->registerBaseMiddlewares();
}
In case these help in debugging the issue!
As per request I have included my controller element used during the post function, this is the part that seems to activate the repository and prompt the error:
<?php
use myapp\Repositories\Invite\InviteRepository;
class InviteController extends BaseController {
/**
* InviteRepository
*
* #var myapp\Repositories\Invite\InviteRepository
*/
protected $repository;
/**
* Create a new instance of the InviteController
*
* #param myapp\Repositories\Invite\InviteRepository
*/
public function __construct(InviteRepository $repository)
{
$this->repository = $repository;
}
/**
* Create a new invite
*
* #return Response
*/
public function store()
{
$invite = $this->repository->create(Input::all());
}
}
RepositoryServiceProvider.php
<?php namespace myapp\Repositories;
use Illuminate\Support\ServiceProvider;
class RepositoryServiceProvider extends ServiceProvider {
/**
* Register
*/
public function register()
{
$this->registerInviteRepository();
}
/**
* Register the Invite Repository
*
* #return void
*/
public function registerInviteRepository()
{
$this->app->bind('myapp\Repositories\Invite\InviteRepository', function($app)
{
return new EloquentInviteRepository( new Invite );
});
}
}
Any idea's as to what I am missing?
Thanks for the help guys,
You've been a great resource so far!
In the file RepositoryServiceProvider.php, replace this
$this->app->bind('myapp\Repositories\Invite\InviteRepository', function($app)
{
return new EloquentInviteRepository( new Invite );
});
With this:
$this->app->bind('myapp\Repositories\Invite\InviteRepository',
'myapp\Repositories\Invite\EloquentInviteRepository');

Symfony 2 - keeping the code DRY - FOSRestBundle

I'm currently using Symfony2 to create (and learn how to) a REST API. I'm using FOSRestBundle and i've created an "ApiControllerBase.php" with the following :
<?php
namespace Utopya\UtopyaBundle\Controller;
use FOS\RestBundle\Controller\FOSRestController;
use FOS\RestBundle\View\View;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormTypeInterface;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
/**
* Class ApiControllerBase
*
* #package Utopya\UtopyaBundle\Controller
*/
abstract class ApiControllerBase extends FOSRestController
{
/**
* #param string $entityName
* #param string $entityClass
*
* #return array
* #throws NotFoundHttpException
*/
protected function getObjects($entityName, $entityClass)
{
$dataRepository = $this->container->get("doctrine")->getRepository($entityClass);
$entityName = $entityName."s";
$data = $dataRepository->findAll();
foreach ($data as $object) {
if (!$object instanceof $entityClass) {
throw new NotFoundHttpException("$entityName not found");
}
}
return array($entityName => $data);
}
/**
* #param string $entityName
* #param string $entityClass
* #param integer $id
*
* #return array
* #throws NotFoundHttpException
*/
protected function getObject($entityName, $entityClass, $id)
{
$dataRepository = $this->container->get("doctrine")->getRepository($entityClass);
$data = $dataRepository->find($id);
if (!$data instanceof $entityClass) {
throw new NotFoundHttpException("$entityName not found");
}
return array($entityClass => $data);
}
/**
* #param FormTypeInterface $objectForm
* #param mixed $object
* #param string $route
*
* #return Response
*/
protected function processForm(FormTypeInterface $objectForm, $object, $route)
{
$statusCode = $object->getId() ? 204 : 201;
$em = $this->getDoctrine()->getManager();
$form = $this->createForm($objectForm, $object);
$form->submit($this->container->get('request_stack')->getCurrentRequest());
if ($form->isValid()) {
$em->persist($object);
$em->flush();
$response = new Response();
$response->setStatusCode($statusCode);
// set the `Location` header only when creating new resources
if (201 === $statusCode) {
$response->headers->set('Location',
$this->generateUrl(
$route, array('id' => $object->getId(), '_format' => 'json'),
true // absolute
)
);
}
return $response;
}
return View::create($form, 400);
}
}
This handles getting one object with a given id, all objects and process a form. But to use this i have to create as many controller as needed. By example : GameController.
<?php
namespace Utopya\UtopyaBundle\Controller;
use FOS\RestBundle\Controller\FOSRestController;
use FOS\RestBundle\Controller\Annotations as Rest;
use FOS\RestBundle\View\View;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Utopya\UtopyaBundle\Entity\Game;
use Utopya\UtopyaBundle\Form\GameType;
/**
* Class GameController
*
* #package Utopya\UtopyaBundle\Controller
*/
class GameController extends ApiControllerBase
{
private $entityName = "Game";
private $entityClass = 'Utopya\UtopyaBundle\Entity\Game';
/**
* #Rest\View()
*/
public function getGamesAction()
{
return $this->getObjects($this->entityName, $this->entityClass);
}
/**
* #param int $id
*
* #return array
* #throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
* #Rest\View()
*/
public function getGameAction($id)
{
return $this->getObject($this->entityName, $this->entityClass, $id);
}
/**
* #return mixed
*/
public function postGameAction()
{
return $this->processForm(new GameType(), new Game(), "get_game");
}
}
This sound not so bad to me but there's a main problem : if i want to create another controller (by example Server or User or Character), i'll have to do the same process and i don't want to since it'll be the same logic.
Another "maybe" problem could be my $entityName and $entityClass.
Any idea or could i make this better ?
Thank-you !
===== Edit 1 =====
I think i made up my mind. For those basics controllers. I would like to be able to "configure" instead of "repeat".
By example i could make a new node in config.yml with the following :
#config.yml
mynode:
game:
entity: 'Utopya\UtopyaBundle\Entity\Game'
This is a very basic example but is it possible to make this and transform it into my GameController with 3 methods routes (getGame, getGames, postGame) ?
I just want some leads if i can really achieve with this way or not, if yes with what components ? (Config, Router, etc.)
If no, what could i do? :)
Thanks !
I'd like to show my approach here.
I've created a base controller for the API, and I stick with the routing that's generated with FOSRest's rest routing type. Hence, the controller looks like this:
<?php
use FOS\RestBundle\Controller\Annotations\View;
use \Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Nelmio\ApiDocBundle\Annotation\ApiDoc;
use Psr\Log\LoggerInterface;
use Symfony\Component\Form\FormFactoryInterface,
Symfony\Bridge\Doctrine\RegistryInterface,
Symfony\Component\Security\Core\SecurityContextInterface,
Doctrine\Common\Persistence\ObjectRepository;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
abstract class AbstractRestController
{
/**
* #var \Symfony\Component\Form\FormFactoryInterface
*/
protected $formFactory;
/**
* #var string
*/
protected $formType;
/**
* #var string
*/
protected $entityClass;
/**
* #var SecurityContextInterface
*/
protected $securityContext;
/**
* #var RegistryInterface
*/
protected $doctrine;
/**
* #var EventDispatcherInterface
*/
protected $dispatcher;
/**
* #param FormFactoryInterface $formFactory
* #param RegistryInterface $doctrine
* #param SecurityContextInterface $securityContext
* #param LoggerInterface $logger
*/
public function __construct(
FormFactoryInterface $formFactory,
RegistryInterface $doctrine,
SecurityContextInterface $securityContext,
EventDispatcherInterface $dispatcher
)
{
$this->formFactory = $formFactory;
$this->doctrine = $doctrine;
$this->securityContext = $securityContext;
$this->dispatcher = $dispatcher;
}
/**
* #param string $formType
*/
public function setFormType($formType)
{
$this->formType = $formType;
}
/**
* #param string $entityClass
*/
public function setEntityClass($entityClass)
{
$this->entityClass = $entityClass;
}
/**
* #param null $data
* #param array $options
*
* #return \Symfony\Component\Form\FormInterface
*/
public function createForm($data = null, $options = array())
{
return $this->formFactory->create(new $this->formType(), $data, $options);
}
/**
* #return RegistryInterface
*/
public function getDoctrine()
{
return $this->doctrine;
}
/**
* #return \Doctrine\ORM\EntityRepository
*/
public function getRepository()
{
return $this->doctrine->getRepository($this->entityClass);
}
/**
* #param Request $request
*
* #View(serializerGroups={"list"}, serializerEnableMaxDepthChecks=true)
*/
public function cgetAction(Request $request)
{
$this->logger->log('DEBUG', 'CGET ' . $this->entityClass);
$offset = null;
$limit = null;
if ($range = $request->headers->get('Range')) {
list($offset, $limit) = explode(',', $range);
}
return $this->getRepository()->findBy(
[],
null,
$limit,
$offset
);
}
/**
* #param int $id
*
* #return object
*
* #View(serializerGroups={"show"}, serializerEnableMaxDepthChecks=true)
*/
public function getAction($id)
{
$this->logger->log('DEBUG', 'GET ' . $this->entityClass);
$object = $this->getRepository()->find($id);
if (!$object) {
throw new NotFoundHttpException(sprintf('%s#%s not found', $this->entityClass, $id));
}
return $object;
}
/**
* #param Request $request
*
* #return \Symfony\Component\Form\Form|\Symfony\Component\Form\FormInterface
*
* #View()
*/
public function postAction(Request $request)
{
$object = new $this->entityClass();
$form = $this->createForm($object);
$form->submit($request);
if ($form->isValid()) {
$this->doctrine->getManager()->persist($object);
$this->doctrine->getManager()->flush($object);
return $object;
}
return $form;
}
/**
* #param Request $request
* #param int $id
*
* #return \Symfony\Component\Form\FormInterface
*
* #View()
*/
public function putAction(Request $request, $id)
{
$object = $this->getRepository()->find($id);
if (!$object) {
throw new NotFoundHttpException(sprintf('%s#%s not found', $this->entityClass, $id));
}
$form = $this->createForm($object);
$form->submit($request);
if ($form->isValid()) {
$this->doctrine->getManager()->persist($object);
$this->doctrine->getManager()->flush($object);
return $object;
}
return $form;
}
/**
* #param Request $request
* #param $id
*
* #View()
*
* #return object|\Symfony\Component\Form\FormInterface
*/
public function patchAction(Request $request, $id)
{
$this->logger->log('DEBUG', 'PATCH ' . $this->entityClass);
$object = $this->getRepository()->find($id);
if (!$object) {
throw new NotFoundHttpException(sprintf('%s#%s not found', $this->entityClass, $id));
}
$form = $this->createForm($object);
$form->submit($request, false);
if ($form->isValid()) {
$this->doctrine->getManager()->persist($object);
$this->doctrine->getManager()->flush($object);
return $object;
}
return $form;
}
/**
* #param int $id
*
* #return array
*
* #View()
*/
public function deleteAction($id)
{
$this->logger->log('DEBUG', 'DELETE ' . $this->entityClass);
$object = $this->getRepository()->find($id);
if (!$object) {
throw new NotFoundHttpException(sprintf('%s#%s not found', $this->entityClass, $id));
}
$this->doctrine->getManager()->remove($object);
$this->doctrine->getManager()->flush($object);
return ['success' => true];
}
}
It has methods for most of RESTful actions. Next, when I want to implement a CRUD for an entity, that's what I do:
The abstract controller is registered in the DI as an abstract service:
my_api.abstract_controller:
class: AbstractRestController
abstract: true
arguments:
- #form.factory
- #doctrine
- #security.context
- #logger
- #event_dispatcher
Next, when I'm implementing a CRUD for a new entity, I create an empty class and a service definition for it:
class SettingController extends AbstractRestController implements ClassResourceInterface {}
Note that the class implements ClassResourceInterface. This is necessary for the rest routing to work.
Here's the service declaration for this controller:
api.settings.controller.class: MyBundle\Controller\SettingController
api.settings.form.class: MyBundle\Form\SettingType
my_api.settings.controller:
class: %api.settings.controller.class%
parent: my_api.abstract_controller
calls:
- [ setEntityClass, [ MyBundle\Entity\Setting ] ]
- [ setFormType, [ %my_api.settings.form.class% ] ]
Then, I'm just including the controller in routing.yml as the FOSRestBundle doc states, and it's done.

Categories