Symfony CMF Dynamic Router no contentDocument - symfony

Following the Dynamic Router doc, I can:
Create a route linked to my content (Page entity)
Persist it with ORM
Load my controller matching the route
But as my controller should expect the $contentDocument parameter, I have nothing.
Here's how I create my route and my entity:
$page = new Page();
$page->setTitle('My Content')
->setBackground(1)
->setDescription('My description')
->setContent('<h1>Hello</h1>');
$manager->persist($page);
$manager->flush(); // flush to be able to use the generated id
$contentRepository = $this->container->get('cmf_routing.content_repository');
$route = new Route();
$route->setName('my-content');
$route->setStaticPrefix('/my-content');
$route->setDefault(RouteObjectInterface::CONTENT_ID, $contentRepository->getContentId($page));
$route->setContent($page);
$page->addRoute($route); // Create the backlink from content to route
$manager->persist($page);
$manager->flush();
Here's my config section:
cmf_routing:
chain:
routers_by_id:
router.default: 200
cmf_routing.dynamic_router: 100
dynamic:
enabled: true
persistence:
orm:
enabled: true
generic_controller: AppBundle:Default:showPage
templates_by_class:
AppBundle\Entity\Page: AppBundle:Default:index.html.twig
My controller:
public function showPageAction($page)
{
return $this->render('default/index.html.twig');
}
And the error:
Controller "AppBundle\Controller\DefaultController::showPageAction()" requires that you provide a value for the "$page" argument. Either the argument is nullable and no null value has been provided, no default value has been provided or because there is a non optional argument after this one.

Dynamic routing puts the content document into the request with the name "contentDocument". You need to explicitly use that name:
public function showPageAction($contentDocument)
{
return $this->render('default/index.html.twig');
}
if you do not need to do anything in your controller, you don't need to specify the generic_controller. template_by_class will make the bundle provided controller render that template with the page instance found in $contentDocument.

Related

there is no default value + symfony2 + crud

sf 2.8.4 with sylius 0.17
i had generated a controller and routes with generate:doctrine:crud
i can list all datas, but on show and edit, always got this error:
Controller "St\AppBundle\Controller\TranslationDomainController::showAction()" requires that you provide a value for the "$translationdomain" argument (because there is no default value or because there is a non optional argument after this one).
here the show action
public function showAction(TranslationDomain $translationdomain)
{
$deleteForm = $this->createDeleteForm($translationdomain->getId(), 'administration_translations_domain_delete');
return $this->render('StAppBundle:TranslationDomain:show.html.twig', array(
'translationdomain' => $translationdomain,
'delete_form' => $deleteForm->createView(), ));
}
and the route
administration_translations_domain_show:
pattern: /{id}/show
defaults: { _controller: "StAppBundle:TranslationDomain:show", id : 1 }
requirements:
id : \d+
_method : get
You are using a param converter
http://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/annotations/converters.html
You have to disable the auto-conversion of type-hinted method arguments feature by setting the auto_convert flag to false.
Look at:
# app/config/config.yml
sensio_framework_extra:
request:
converters: true
auto_convert: false
Change to:
sensio_framework_extra:
request:
converters: true
auto_convert: true
At the end you should always request for an object identifier. It's safe and semantic correct. You want to 'show/edit/update/delete' concrete entity.
If you really wants to have a default show for your set of entities create route like a '/show/default' and use this route with 'show/choose default' link.

Payum omnipay and Skrill

I'm trying to implement payment in my app using Payum 1.0, Payum Bundle 1.0 and Omnipay bridge with omnipay-skrill bundle as skrill is not supported out-of-the-box.
payum.yml
payum:
security:
token_storage:
XXX\PaymentBundle\Entity\PaymentToken: { doctrine: orm }
storages:
XXX\PaymentBundle\Entity\Payment: { doctrine: orm }
gateways:
skrill:
omnipay:
type: Skrill
options:
email: me#me.net
notifyUrl: /payment/skrill
testMode: true
This is my controller prepare action:
public function prepareAction()
{
$paymentName = 'skrill';
$storage = $this->get('payum')->getStorage('XXX\PaymentBundle\Entity\Payment');
$payment = $storage->create();
$payment->setNumber(uniqid($this->container->getParameter('shoppingCart')));
$payment->setCurrencyCode('EUR');
$payment->setTotalAmount($this->container->getParameter('price_of_xxx'));
$payment->setDescription('desc');
$payment->setClientId($this->getUser()->getId());
$payment->setClientEmail($this->getUser()->getEmail());
$payment->setLanguage('EN');
$storage->update($payment);
$captureToken = $this->get('payum.security.token_factory')->createCaptureToken(
$paymentName,
$payment,
'xxx_buy_premium_done' // the route to redirect after capture
);
return $this->redirect($captureToken->getTargetUrl());
}
So, when i visit the link associated with prepare action i get the Payum credit card form. But when i enter all data as response i get an error saying language parameter must be provided. I can't figure out why is it happening since i tried putting the language parameter in config file and setting payment language field. I suppose it has to be sent in form data as hidden field.
Is it possible to redirect user to https://pay.skrill.com/app/?sid=
with parameters and get response from Skrill servers to captureDoneAction?
Try to set language to the details like this:
$payment->setDetails(array(
'language' => 'EN',
));

creating custom repository fos elastic search

im trying to make a simple custom repository in order to understand how elastic search repository works. the documentation is pretty straight forward but i still dont understand how it works, im getting this error ´The service definition "fos_elastica.manager" does not exist.´. so far i think my problem is in the controller since i dont understand how to intialize them, also i would like to know if im in the right way in my configuration of the custom repository and the simple query i made.
im getting this error with this configuration whenever i try to make a search,
The service definition "fos_elastica.manager" does not exist.
this is my configuration so far:
//app/config.yml
fos_elastica:
clients:
default: { host: localhost, port: 9200 }
indexes:
sava:
client: default
types:
blog:
mappings:
id:
type: integer
body : ~
title : ~
tags: ~
persistence:
identifier: id
driver: orm
model: sava\BlogBundle\Entity\TblPost
finder: ~
provider: ~
listener: ~
repository: sava\BlogBundle\SearchRepository\TblPostRepository
this is my controller action:
namespace sava\BlogBundle\Controller;
//custom querys
use FOS\ElasticaBundle\Manager\RepositoryManager;
use FOS\ElasticaBundle\Repository;
//
use Symfony\Component\DependencyInjection\ContainerBuilder;
class TblPostController extends Controller
{
public function getPostAction(Request $request)
{
$container = new ContainerBuilder();
$repositoryManager = $container->get('fos_elastica.manager');
$repository = $repositoryManager->getRepository('BlogBundle:TblPost');
$items2 = $repository->matchExact($categoria,$searchQuery );
return $this->render('savaBlogBundle:TblPost:index.html.twig', array(
'results' => $items2, 'entities' => $items2
));
}
this is my post repository:
<?php
namespace sava\BlogBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use FOS\ElasticaBundle\Repository;
class TblPostRepository extends FOS\ElasticaBundle\Repository
{
public function matchExact($campo, $searchQuery) {
//$finder = $this->get('fos_elastica.finder.sava.blog');
$query = new Query();
if($searchQuery=='')
{
$innerQuery = new Query\MatchAll();
}
else{
$innerQuery = new Query\Match();
$innerQuery->setField( $campo , array('query' => $searchQuery));
}
$query->setQuery($innerQuery);
$query->setSize(1000000);
$query->setExplain(true);
return $this->find($query);
}
}
and since im using yml this is my tblpost.orm, i did generate my entities.
whenever i do the get postaction it throws me that it cant find the container, and i dont see an example in how to properly intiaze it, also is this is how you make a custom query?
EDIT 1:
so i changed this:
$container = new ContainerBuilder();
$repositoryManager = $container->get('fos_elastica.manager');
to this:
$elastica = $this->container->get('fos_elastica.manager');// single entry point, no fancy services
$SearchRepository = $elastica->getRepository('savaBlogBundle:TblPostRepository');// single type
and im getting this error:
No search finder configured for sava\BlogBundle\Entity\TblPostRepository
I've just had the same issue, the soultion is that instead of savaBlogBundle:TblPostRepository you should use your entity, for example:
$SearchRepository = $elastica->getRepository('savaBlogBundle:TblPost`)
According your fatal error in title of the issue enter link description here
The main problem why did you get that mistake is that, you assigned the same TblPostRepository in (doctrine config for entity) and in fos_elastica.

Symfony2 multi-level dynamic router

I have a current project that has to displays both defined pages with specific entities, what is very easy to manage with Symfony2, and content pages on different layouts, what is - I guess - a bit less common.
I get in trouble trying to build the routing system.
For instance, if I have to display a page with some news,
I would like to update the router of my bundle with a new route like :
my_bundle_news_page:
pattern: /news
defaults:
_controller: MyBundle:NewsController:indexAction
But how to manage a dynamic router that could have a totally custom URL on many levels ?
Let's imagine I've got a "Page" Entity, that is self-references for an optionnal "parent-child" relation.
I don't think I can just use any config YAML file for this specific routing ?!
my_bundle_custom_page:
pattern: /{slug}
defaults:
_controller: MyBundle:PageController:showAction
This would bind all the first-level pages:
/projects
/about
/contact
/our-project
What about a page that would be displayed with, for instance, a slug like:
/our-project/health
In fact any URL...
/{slug-level1}/{slug-level2}/{slug-level3} etc.
Cause the pages are supposed to change and be updated from webmastering.
I guess the best way would be to have a router that compare the {slug} with a database field (entity property)
I read in the Symfony-CMF doc that it is possible to write a service based a route provider:
namespace MyBundle\Routing;
use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Routing\Route as SymfonyRoute;
use MyBundle\Entity\PageRepository;
class RouteProvider extends PageRepository {
public function findPageBySlug($slug)
{
// Find a page by slug property
$page = $this->findOneBySlug($slug);
if (!$page) {
// Maybe any custom Exception
throw $this->createNotFoundException('The page you are looking for does not exists.');
}
$pattern = $page->getUrl(); // e.g. "/first-level/second-level/third-level"
$collection = new RouteCollection();
// create a new Route and set our page as a default
// (so that we can retrieve it from the request)
$route = new SymfonyRoute($pattern, array(
'page' => $page,
));
// add the route to the RouteCollection using a unique ID as the key.
$collection->add('page_'.uniqid(), $route);
return $collection;
}
}
But how to set it up as a service ? Are there some requirements ?
How could this kind of thing work, does it add a route to the RouteCollection when request is called ?
And will I be able to bind any route in this way ?
EDIT : services.yml of my bundle
parameters:
cmf_routing.matcher.dummy_collection.class: Symfony\Component\Routing\RouteCollection
cmf_routing.matcher.dummy_context.class: Symfony\Component\Routing\RequestContext
cmf_routing.generator.class: Symfony\Cmf\Bundle\RoutingBundle\Routing\ContentAwareGenerator
cmf_routing.nested_matcher.class: Symfony\Cmf\Component\Routing\NestedMatcher\NestedMatcher
cmf_routing.url_matcher.class: Symfony\Cmf\Component\Routing\NestedMatcher\NestedMatcher
fsbcms.chain_router.class: Symfony\Cmf\Component\Routing\ChainRouter
fsbcms.route_provider.class: FSB\CMSBundle\Routing\RouteProvider
fsbcms.dynamic_router.class: Symfony\Cmf\Component\Routing\DynamicRouter
fsbcms.route_entity.class: null
services:
fsbcms.router:
class: %fsbcms.chain_router.class%
arguments:
- "#logger"
calls:
- [setContext, ["router.request_context"]]
fsbcms.route_provider:
class: "%fsbcms.route_provider.class%"
arguments:
- "#doctrine"
cmf_routing.matcher.dummy_collection:
class: "%cmf_routing.matcher.dummy_collection.class%"
public: "false"
cmf_routing.matcher.dummy_context:
class: "%cmf_routing.matcher.dummy_context.class%"
public: false
cmf_routing.generator:
class: "%cmf_routing.generator.class%"
arguments:
- "#fsbcms.route_provider"
- "#logger"
calls:
- [setContainer, ["service_container"]]
- [setContentRepository, ["cmf_routing.content_repository"]]
cmf_routing.url_matcher:
class: "%cmf_routing.url_matcher.class%"
arguments: ["#cmf_routing.matcher.dummy_collection", "#cmf_routing.matcher.dummy_context"]
cmf_routing.nested_matcher:
class: "%cmf_routing.nested_matcher.class%"
arguments: ["#fsbcms.route_provider"]
calls:
- [setFinalMatcher, ["cmf_routing.url_matcher"]]
fsbcms.dynamic_router:
class: "%fsbcms.dynamic_router.class%"
arguments:
- "#router.request_context"
- "#cmf_routing.nested_matcher"
- "#cmf_routing.generator"
tags:
- { name: router, priority: 300 }
I suggest taking a look at the Symfony CMF routing component and the CmfRoutingBundle (to implement the component in symfony).
The Routing component uses a chain router, which is irrelevant for this question but it's good to know. The chain router chains over a queue of routers. The component provides a DynamicRouter that uses a NestedMatcher. That's exactly what you want.
The NestedMatcher uses a Route provider to get the routes from a dynamic source (e.g. a database). You are showing an example of a Route provider in your question.
Furthermore, it uses a FinalMatcher to match the route. You can just pass an instance of Symfony\Cmf\Component\Routing\NestedMatcher\UrlMatcher, as you are doing not too difficult things.
Take a look at the docs of the RoutingBundle to learn how to activate the chain router and then create a route provider which loads the routes, make a service:
acme_routing.route_provider:
class: Acme\RoutingBundle\Provider\DoctrineOrmProvider
arguments: ["#doctrine"]
Now, you can create a NestedMatcher service:
acme_routing.url_matcher:
class: Symfony\Cmf\Component\Routing\NestedMatcher\UrlMatcher
arguments: ["#cmf_routing.matcher.dummy_collection", "#cmf_routing.matcher.dummy_context"]
acme_routing.nested_matcher:
class: Symfony\Cmf\Component\Routing\NestedMatcher
arguments: ["#acme_routing.route_provider"]
calls:
- [setFinalMatcher, ["acme_routing.url_matcher"]]
Now, register the DynamicRouter and put it in the chain:
acme_routing.dynamic_router:
class: Symfony\Cmf\Component\Routing\DynamicRouter
arguments:
- "#router.request_context"
- "#acme_routing.nested_matcher"
- "#cmf_routing.generator"
tags:
- { name: router, priority: 300 }
Now, it should work and should load the routes from the database and match them against the request.

Symfony 2.1 Doctrine filters (enable/disable)

I'm currently implementing Doctrine filters in my Symfony2.1 project with the following setup:
<?php
namespace Acme\Bundle\Entity;
class Article {
/**
* #ORM\Column(type="string")
*/
private $status;
...
}
//app/config/config.yml
doctrine:
orm:
filters:
status:
class: Acme\Bundle\Filter\StatusFilter
enabled: false
....
//src/Acme/Bundle/Filter/StatusFilter.php
namespace Acme\Bundle\Filter;
use Acme\Bundle\Entity\Status;
class StatusFilter extends SQLFilter {
public function addFilterConstraint(ClassMetadata $target, $alias)
{
$filter =
$target->reflClass->implementsInterface('Acme\Bundle\Entity\Status')?
$alias . '.status = ' . Status::PUBLISHED : '';
return $filter;
}
}
Where Acme\Bundle\Entity\Status is just an interface.
The code is working as expected when the filter is enabled in config.yml.
The problem is that I cannot retrieve all articles for administration!
Is there a way to enable this filter for a certain bundle?
p.s. I know how to enable and disable the filter with the EntityManager,
I just cannot find the proper place to do it for the frontend Bundle.
my admin section is accessible by route prefix myadmin
www.example.com/myadmin/ -> admin section = disable filter (disabled by default in config)
www.example.com/... -> anything else = enable filter.
Looking at the Doctrine code, there are methods to enable and disable filters.
Once you have defined your filter in the config.yml file, you can enable/disable in a controller or service:
// 'status' is the unique name of the filter in the config file
$this->getDoctrine()->getManager()->getFilters()->enable('status');
$this->getDoctrine()->getManager()->getFilters()->disable('status');
Note: this was taken from Symfony 2.3. You would need to test this with previous versions of Symfony/Doctrine.
there is no notion of bundle at Doctrine level. The only way I see would be to detect which controller is used, by parsing its className (reflection, ...) during a kernel.request event, or a kernel.controller event.
Then, if you detect that your controller is in FrontendBundle, just disable/enable your doctrine filter.
If you prefer using routing to detect when to disable/enable, just use kernel.request event. You will have access to all request parameters, via $event->getRequest()->attributes->get('_controller') for example.

Resources