Slim 3 pagination with Twig view using Eloquent ORM - eloquent

I'm using Twig view for my slim 3 application but I don't know how to make pagination using the eloquent ORM below is my code.
MODEL:
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Todo extends Model
{
protected $table = "todo";
protected $fillable = [
'todo_name',
];
}
and this is my code to render a view
use App\Models\Todo;
$app->get('/', function ($request, $response) {
$data = Todo::all()->paginate(5);
return $this->view->render($response, 'home.twig', [
'title' => 'Home',
'todolist' => $data,
]);
})->setName('homepage');
and I got this error
Method paginate does not exist.

Try $data = Todo::paginate(5);

To use pagination you need illuminate/pagination package. It is not included by default when you include illuminate/database. You can use composer to include it in your project:
composer require illuminate/pagination
And you should not call paginate() method after a call to all() or get(). Try this instead:
$data=Todo::paginate(5);
And please note, for pagination to work correctly, it needs to know current page number otherwise it will always return results for first page. Please have a look at this answer to see how to setup page resolver.

Related

Multiple Slim routes with the same signature

We are looking at using Slim 3 as the framework for our API. I have searched SO and the Slim docs, but cannot find an answer to the issue. If we have different route files (e.g. v1, v2, etc.) and if two routes have the same signature, an error is thrown. Is there any way to cascade the routes so that the last loaded route for a particular signature is used?
For example, say v1.php has a route for GET ("/test") and v2.php also contains this route, can we use the latest version? Even simpler would be if a file of routes contains two routes with the same signature, is there a way of the latter method being used (and no error being thrown)?
A similar question is asked here but this uses hooks (which have been removed from Slim 3 as per here)
I looked at the Slim code and I didn't find a simple way of allowing duplicated routes (preventing the exception).
The new Slim uses FastRoute as dependency. It calls FastRoute\simpleDispatcher and doesn't offer any configuration possiblity. Even if it did allow some configuration, FastRoute doesn't have any built-in option to allow duplicated routes. A custom implementation of a DataGenerator would be needed.
But following the instructions above, we can get a custom DataGenerator by passing to Slim App a custom Router which instantiates some FastRoute::Dispatcher implementation which then uses the custom DataGenerator.
First the CustomDataGenerator (let's go the easy way and do some copy and pasting from \FastRoute\RegexBasedAbstract and \FastRoute\GroupCountBased)
<?php
class CustomDataGenerator implements \FastRoute\DataGenerator {
/*
* 1. Copy over everything from the RegexBasedAbstract
* 2. Replace abstract methods with implementations from GroupCountBased
* 3. change the addStaticRoute and addVariableRoute
* to the following implementations
*/
private function addStaticRoute($httpMethod, $routeData, $handler) {
$routeStr = $routeData[0];
if (isset($this->methodToRegexToRoutesMap[$httpMethod])) {
foreach ($this->methodToRegexToRoutesMap[$httpMethod] as $route) {
if ($route->matches($routeStr)) {
throw new BadRouteException(sprintf(
'Static route "%s" is shadowed by previously defined variable route "%s" for method "%s"',
$routeStr, $route->regex, $httpMethod
));
}
}
}
if (isset($this->staticRoutes[$httpMethod][$routeStr])) {
unset($this->staticRoutes[$httpMethod][$routeStr]);
}
$this->staticRoutes[$httpMethod][$routeStr] = $handler;
}
private function addVariableRoute($httpMethod, $routeData, $handler) {
list($regex, $variables) = $this->buildRegexForRoute($routeData);
if (isset($this->methodToRegexToRoutesMap[$httpMethod][$regex])) {
unset($this->methodToRegexToRoutesMap[$httpMethod][$regex]);
}
$this->methodToRegexToRoutesMap[$httpMethod][$regex] = new \FastRoute\Route(
$httpMethod, $handler, $regex, $variables
);
}
}
Then the custom Router
<?php
class CustomRouter extends \Slim\Router {
protected function createDispatcher() {
return $this->dispatcher ?: \FastRoute\simpleDispatcher(function (\FastRoute\RouteCollector $r) {
foreach ($this->getRoutes() as $route) {
$r->addRoute($route->getMethods(), $route->getPattern(), $route->getIdentifier());
}
}, [
'routeParser' => $this->routeParser,
'dataGenerator' => new CustomDataGenerator()
]);
}
}
and finally instantiate the Slim app with the custom router
<?php
$app = new \Slim\App(array(
'router' => new CustomRouter()
));
The code above, if a duplicated route is detected, removes the previous route and stores the new one.
I hope I didn't miss any simpler way of achieving this result.

Symfony Form Component Standalone Form Type Extension

I have a project using some components from Symfony. Namely Twig, Doctrine, and Form.
I would like to modify all form field types to be able to take a new 'suffix' argument when they are created. It seems like this is usually simple in the full Symfony stack and could be done by extending the existing form type. However I'm not sure how to get the form component to load my custom extension when using the Form Component standalone.
Any help would be great, thank you!
Okay, if I understood your question correctly, what you basically want to do, is add new option to your form builder for given type.
index.php - Basically here, we will just create a FormBuilder instance and add one field for testing purpose.
<?php
use Symfony\Component\Form\Forms;
use Symfony\Component\Form\Extension\HttpFoundation\HttpFoundationExtension;
$formFactory = Forms::createFormFactoryBuilder()
->getFormFactory()
->createBuilder()
->add('test', 'text', array('customAttribute' => true))
->getForm()
->createView();
If we open the browser right now, we will get nice and big error, telling us that "customAttribute" is unknown option.
So, let's create custom form type! As you saw I named it TextCustomType since I will extends "text" form type.
The Type class:
<?php
use Symfony\Component\Form\AbstractTypeExtension;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Symfony\Component\Form\FormView;
use Symfony\Component\Form\FormInterface;
class TextCustomType extends AbstractTypeExtension {
public function getName() {
return "text";
}
public function getExtendedType() {
return "text";
}
public function setDefaultOptions(OptionsResolverInterface $resolver) {
$resolver->setOptional( array('customAttribute') );
$resolver->setDefaults( array('customAttribute' => true) );
}
public function buildView(FormView $view, FormInterface $form, array $options) {
$view->vars['customAttribute'] = $options['customAttribute'];
}
}
Now, we created our custom type, so lets add it to the form factory:
$formFactory = Forms::createFormFactoryBuilder()
->addTypeExtension( new TextCustomType() ) // once the class is loaded simply pass fresh instance to ->addTypeExtension() method.
->getFormFactory()
->createBuilder()
->add('test', 'text', array('customAttribute' => true))
->getForm()
->createView();
Refresh your browser, and you should be good to go! Hope you got the idea.
Updated as per OP's suggestion.
The answer is pretty simple! It was just a matter of looking in the right place. The FormFactoryBuilder is the key:
use Symfony\Form\Component\Form\Forms;
$form = Forms::createFormFactoryBuilder()
->addTypeExtension(new MyExtension())
->getFormFactory()
->create();
This $form variable now knows about my new 'suffix' property.

TYPO3 4.5: How to read constraint(s) in query

I need to use a REST service in order to get some data to a plugin. In order to do so, I have overriden the normal backend interface in typoscript with the following command :
objects.Tx_Extbase_Persistence_Storage_BackendInterface.className = Tx_extensionname_Persistence_Storage_RestBackend
This BackendInterface then returns Query Objects in my repository when I use to following:
Ex:
$query = $this->createQuery();
$query = $query->execute()->toArray();
Here, $query holds the response from the service as a TYPO3 Tx_Extbase_Persistence_QueryInterface object.
The problem is that I need to be able to do a call to the service while passing an ID parameter (appending to the endpoint with /ID). Ideally, I would do it in such a way that this repo function (called in the controller) would return what I want :
public function findById( $id ) {
$query = $this->createQuery();
$query->matching($query->equals('id', $id));
return $query->execute()->toArray();
}
The problem is that I need to be able to access the query constraint within my Tx_extensionname_Persistence_Storage_RestBackend. Normally, I would use the '$query->getConstraint()' method. However, we are using typo3 4.5 and this function is not yet defined for Tx_Extbase_Persistence_QueryInterface.
Modifying the typo3 core to add this function is not an option.
I tried to extend the Query Interface to add this functionnality in a subclass in order to then override the class in typoscript but then realized this wouldn't be portable enough. I need to be able to access the query constraint only using typo3 4.5 native functionnalities.
Well I fixed it. The only thing needed to do was :
Tx_Extbase_Persistence_QueryInterface.className = Tx_MyExtension_Persistence_RestQuery
class Tx_MyExtension_Persistence_RestQuery extends Tx_Extbase_Persistence_Query implements Tx_MyExtension_Persistence_RestQueryInterface
{
}
interface Tx_MyExtension_Persistence_RestQueryInterface extends Tx_Extbase_Persistence_QueryInterface {
public function getConstraint();
}

Zend Frameworks Quickstart find() methods Action and View

I am attempting to extend the Zend Framework Quickstart tutorial by trying to make an individual view for each guestbook entry, but I am missing something and keep getting errors like:
Trying to get property of non-object in C:\wamp\www\quickstart.local\application\views\scripts\guestbook\display.phtml
I get this when trying the following for my displayAction and my display.phtml:
//view
<p><?php echo $this->escape($this->entry->id); ?></strong> <a><?php echo $this->escape($this->entry->comment); ?></a><br>
<?php echo $this->escape($this->entry->email); ?></p>
//action
public function displayAction()
{
$id = $this->getRequest()->getParams('id');
$entry = new Application_Model_GuestbookMapper();
$this->view->entry = $entry->find($id);
}
And the find() function in the mapper is as is from the tutorial.
I have look all over the web and have only found tutorials that omit the quickstart guide's structure altogether. While they are all solid in their own right, I would like to find a solution to this. What am I doing wrong?
I am about mid-level with php and a beginner with zend framework. Please keep that in mind when responding.
If you're following the quickstart verboten, you'll want something like this
public function displayAction()
{
$id = $this->getRequest()->getParam('id');
$model = new Application_Model_Guestbook;
$mapper = new Application_Model_GuestbookMapper;
$mapper->find($id, $model);
if (null === $model->getId()) {
throw new Zend_Controller_Action_Exception(
sprintf('Guestbook entry %d not found', $id), 404);
}
$this->view->entry = $model;
}
in order to use GuestbookMapper with the Find() method you need to supply two items of information to the method, the id and an instance of Guestbook. The instance of guestbook is required because it has all the getters and setters mapper uses to generate the returned data.
//action updated
public function displayAction()
{
$id = $this->getRequest()->getParams('id');
$guestbook = new Application_Model_GuestBook();
$entry = new Application_Model_GuestbookMapper();
$this->view->entry = $entry->find($id, $guestbook);
}
for a detailed explaination of how this works check out chapter 9 of Survive the Deepend

action parameters routing not working in Zend framework routes.ini

I'm trying to set up a route in Zend Framework (version 1.11.11) in a routes.ini file, which would allow be to match the following url:
my.domain.com/shop/add/123
to the ShopController and addAction. However, for some reason the parameter (the number at the end) is not being recognized by my action. The PHP error I'm getting is
Warning: Missing argument 1 for ShopController::addAction(), called in...
I know I could set this up using PHP code in the bootstrap, but I want to understand how to do this type of setup in a .ini file and I'm having a hard time finding any resources that explain this. I should also point out that I'm using modules in my project. What I've come up with using various snippets found here and there online is the following:
application/config/routes.ini:
[routes]
routes.shop.route = "shop/add/:productid/*"
routes.shop.defaults.controller = shop
routes.shop.defaults.action = add
routes.shop.defaults.productid = 0
routes.shop.reqs.productid = \d+
Bootstrap.php:
...
protected function _initRoutes()
{
$config = new Zend_Config_Ini(APPLICATION_PATH . '/configs/routes.ini', 'routes');
$router = Zend_Controller_Front::getInstance()->getRouter();
$router->addConfig( $config, 'routes' );
}
...
ShopController.php
<?php
class ShopController extends Egil_Controllers_BaseController
{
public function indexAction()
{
// action body
}
public function addAction($id)
{
echo "the id: ".$id;
}
}
Any suggestions as to why this is not working? I have a feeling I'm missing something fundamental about routing in Zend through .ini files.
Apparently I'm more rusty in Zend than I thought. A few minutes after posting I realized I'm trying to access the parameter the wrong way in my controller. It should not be a parameter to addAction, instead I should access it through the request object inside the function:
correct addAction in ShopController:
public function addAction()
{
$id = $this->_request->getParam('productid');
echo "the id: ".$id;
}
I also realized I can simplify my route setup quite a bit in this case:
[routes]
routes.shop.route = "shop/:action/:productid"
routes.shop.defaults.controller = shop
routes.shop.defaults.action = index