Empty result with findAll in FlexForm UserFunc in TYPO3 7.6.15 - repository

I get an empty result with findAll in FlexForm UserFunc in TYPO3 7.6.15.
The storagePid is set and in Frontend I get all results with findAll.
Here is my UserFunc-Method:
public function getBuldingOptions(&$config)
{
/** #var ObjectManager $om */
$om = GeneralUtility::makeInstance(ObjectManager::class);
/** #var BuildingRepository $repo */
$repo = $om->get(BuildingRepository::class);
$building = $repo->findAll();
DebuggerUtility::var_dump($building, '$building'); // Output: TYPO3\CMS\Extbase\Persistence\Generic\QueryResultprototypeobject (empty)
// add empty value option
$config['items'][] = [LocalizationUtility::translate('BuildingUserFunc.building.emtpyValue', $this->extName), 0];
/** #var Building $entity */
foreach ($building as $entity) {
$config['items'][] = [$entity->getName(), $entity->getUid()];
}
return $config;
}
What can by still wrong? Anybody an idea?

I've found the problem and a suitable solution.
The problem is, that the configured storagePid does not work in plugin configuration scope. You have to solve the storagePid manually.
I have wrote a service for that and added to EXT:xm_tools:
https://github.com/xima-media/xm_tools/blob/rc-1.0.0/Classes/Extensionmanager/ExtensionUtility.php
And my repository have a initializeObject method:
use TYPO3\CMS\Extbase\Persistence\Generic\Typo3QuerySettings;
use TYPO3\CMS\Extbase\Persistence\Repository;
use Xima\XmTools\Extensionmanager\ExtensionUtility;
class BaseRepository extends Repository
{
private $extName = 'my_extension_key';
public function initializeObject()
{
$pluginSetup = ExtensionUtility::getTypoScriptPluginSetup($this->extName);
/** #var Typo3QuerySettings $querySettings */
$querySettings = $this->objectManager->get(Typo3QuerySettings::class);
$querySettings->setStoragePageIds(array_merge($querySettings->getStoragePageIds(), explode(',', $pluginSetup['persistence']['storagePid'])));
$this->setDefaultQuerySettings($querySettings);
}
}

Related

Symfony, PHPUnit : Client Webdriver Authentication

I need to authenticate my WebDriver Client for functional tests.
For example,
In my integration tests, i'm doing something like that :
namespace Tests\Controller;
use App\Entity\Donor;
use App\Entity\User;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Tools\SchemaTool;
use SebastianBergmann\Type\RuntimeException;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
class DonorTest extends WebTestCase
{
private static $client;
/**
* #var EntityManager
*/
private $entityManager;
/**
* #var SchemaTool
*/
private $schemaTool;
public function __construct(?string $name = null, array $data = [], string $dataName = '')
{
parent::__construct($name, $data, $dataName);
static::ensureKernelShutdown();
if (!self::$client) {
self::$client = static::createClient([], [
'PHP_AUTH_USER' => 'Same Old User',
'PHP_AUTH_PW' => 'Same Old Password',
]);
}
$this->entityManager = self::bootKernel()
->getContainer()
->get('doctrine')
->getManager();
$this->schemaTool = new SchemaTool($this->entityManager);
/** Safeguard */
$connection = $this->entityManager->getConnection()->getParams();
if ($connection['driver'] != 'pdo_sqlite' || $connection['path'] != '/tmp/test_db.sqlite') {
throw new RuntimeException('Wrong database, darling ! Please set-up your testing database correctly. See /config/packages/test/doctrine.yaml and /tests/README.md');
}
}
I'm just passing the credentials in paramaters, and it works.
But, in my functional tests, i'm using the WebDriver. It didn't accept credentials in arguments :
<?php
namespace App\Tests\Functional\Entities\Donor;
use App\Entity\Donor;
use App\Tests\Functional\Helpers\Carrier\CarrierHelper;
use App\Tests\Functional\Helpers\Donor\DonorHelper;
use Doctrine\ORM\EntityManager;
use Facebook\WebDriver\WebDriverBy;
use Symfony\Component\Finder\Finder;
use Symfony\Component\Panther\PantherTestCase;
use Symfony\Component\Panther\Client;
class DonorTest extends PantherTestCase
{
/**
* #var EntityManager
*/
private $entityManager;
/**
* #var CarrierHelper
*/
private $helper;
/**
* #var Client
*/
private $client;
public function __construct(?string $name = null, array $data = [], string $dataName = '')
{
parent::__construct($name, $data, $dataName);
$this->entityManager = self::bootKernel()
->getContainer()
->get('doctrine')
->getManager();
$this->helper = new DonorHelper();
}
public static function setUpBeforeClass(): void
{
// Do something
}
public function setUp(): void
{
parent::setUp(); // TODO: Change the autogenerated stub
$this->client = Client::createChromeClient();
$this->client->manage()->window()->maximize();
}
I can't pass any login arguments in createChromeClient() method.
I think i have to play with cookies in cookieJar, or token, but i don't know how.
Feel free to ask me my ahtentication method, but i've followed the documentation :
https://symfony.com/doc/current/security/form_login_setup.html
EDIT
I've just tried something else. Log in with my browser, for generate a cookie, and tried to handcraft an other with same PHPSESSID
public function setUp(): void
{
parent::setUp(); // TODO: Change the autogenerated stub
$this->client = Client::createChromeClient();
$this->client->manage()->window()->maximize();
$cookie = new Cookie('PHPSESSID', 'pafvg5nommcooa60q14nqhool0');
$cookie->setDomain('127.0.0.1');
$cookie->setHttpOnly(true);
$cookie->setSecure(false);
$cookie->setPath('/');
$this->client->manage()->addCookie($cookie);
}
But get this error :
Facebook\WebDriver\Exception\InvalidCookieDomainException: invalid cookie domain
Domain is good, same as my web browser.
I will update as my investigations progressed.
EDIT 2
Ok... Got It.
According to this thread : Unable to set cookies in Selenium Webdriver
For setting-up cookie['domain'], you have to request firstly on the domain, THEN set-up the cookie...
SO, this is almost working :
public function setUp(): void
{
parent::setUp(); // TODO: Change the autogenerated stub
$this->client = Client::createChromeClient();
$this->client->manage()->window()->maximize();
$this->client->request('GET', 'http://127.0.0.1/randompage');
$handcookie = Cookie::createFromArray([
'name' => 'PHPSESSID',
'value' => 'pcvbf3sjlla16rfb1b1274qk01',
'domain' => '127.0.0.1',
'path' => '/'
]);
$this->client->manage()->addCookie($handcookie);
}
Next step : Find a way to generate a permanent cookie, without lifetime.
I think nobody will read this but i will update it in case someone else gets stuck.

Symfony 2: How to use the ParamConverter with a PUT method to get or create an entity object

I need to implement an API with a PUT method and I would like to use the ParamConverter in my Controller to find an existing entity object, or if the entity object doesn't exist, to create a new one.
However the standard Symfony ParamConverter returns an exception if it doesn't find the entity object in the repository.
Do you have any ideas to do that in a nice and clean way ? Thx.
Here is an example of what I would like to do (I use FOS REST Bundle to handle the PUT request):
/**
* #param Request $request
* #return View
*
* #ParamConverter("video")
*
*/
public function putVideosAction(Request $request, Video $video)
{
try {
return $this->getHandlerVideos()->put($video, $request->request->all());
} catch (InvalidFormException $e) {
return $e->getForm();
}
}
Here's a solution. Please give me your thoughts on it.
In your controller, I would do that:
/**
* #param Request $request
* #return View
*
* #Rest\Put()
* #Rest\View()
*
* #ParamConverter("video", converter="app_get_or_create_entity_converter", options={"repository_method" = "findOneById"})
*/
public function putVideosAction(Request $request, Video $video)
{
try {
$video = $this->getHandlerVideos()->put($video, $request->request->all());
return $video;
} catch (InvalidFormException $e) {
return $e->getForm();
}
}
I would write a dynamic param converter that way:
class GetOrCreateEntityConverter implements \Sensio\Bundle\FrameworkExtraBundle\Request\ParamConverter\ParamConverterInterface
{
/**
* #var EntityManagerInterface
*/
protected $entityManager;
/**
* #var ManagerRegistry $registry Manager registry
*/
private $registry;
/**
* #param ManagerRegistry $registry
* #param EntityManagerInterface $entityManager
*/
public function __construct(ManagerRegistry $registry, EntityManagerInterface $entityManager)
{
$this->registry = $registry;
$this->entityManager = $entityManager;
}
public function supports(ParamConverter $configuration)
{
if ('app_get_or_create_entity_converter' !== $configuration->getConverter()) {
return false;
}
return true;
}
/**
* {#inheritdoc}
*
* Applies converting
*
* #throws \InvalidArgumentException When route attributes are missing
* #throws NotFoundHttpException When object not found
*/
public function apply(Request $request, ParamConverter $configuration)
{
$name = $configuration->getName();
$options = $configuration->getOptions();
$class = $configuration->getClass();
$repository = $this->entityManager->getRepository($class);
$repositoryMethod = $options['repository_method'];
if (!is_callable([$repository, $repositoryMethod])) {
throw new \BadMethodCallException($repositoryMethod . ' function does not exist.', 405);
}
$entity = $repository->$repositoryMethod($id);
if (null === $entity) {
$entity = new $class;
}
$request->attributes->set($name, $entity);
}
}
If you ask why I return a form in the catch, please go and see https://github.com/liuggio/symfony2-rest-api-the-best-2013-way/blob/master/src/Acme/BlogBundle/Controller/PageController.php
You'll have to create your own custom paramConverter.
First, here is what you want to write in your controller:
/**
* #ParamConverter("video", class = "MyBundle:Video", converter = "my_param_converter")
* #param Request $request
* #param Video $video
* #return \Symfony\Component\HttpFoundation\Response
*/
public function putVideosAction(Request $request, Video $video)
{
// your code..
}
Now let's write the my_param_converter!
use Doctrine\Common\Persistence\ManagerRegistry;
use Sensio\Bundle\FrameworkExtraBundle\Request\ParamConverter\ParamConverterInterface;
// ...
class MyParamConverter implements ParamConverterInterface
{
private $registry;
/**
* #param ManagerRegistry $registry
*/
public function __construct(ManagerRegistry $registry = null)
{
$this->registry = $registry;
}
/**
* Check if object supported by our paramConverter
*
* #param ParamConverter $configuration
*/
public function supports(ParamConverter $configuration)
{
// In this case we can do nothing and just return
if (null === $this->registry || !count($this->registry->getManagers())) {
return false;
}
// Check if the class is set in configuration
if(null === $configuration->getClass()) {
return false;
}
// Get actual entity manager for class
$em = $this->registry->getManagerForClass($configuration->getClass());
// Check what you need to check...
return true;
}
public function apply(Request $request, ParamConverter $configuration)
{
$videoId = $request->attributes->get('video');
if(null === videoId) {
throw new \InvalidArgumentException('Route attribute is missing');
}
// Get actual entity manager for class
$em = $this->registry->getManagerForClass($configuration->getClass());
$repository = $em->getRepository($configuration->getClass());
// Try to find the video
$video = $$repository->findOneById($videoId);
if($video === null || !($video instanceof Video)) {
// Here you can create your new video object
}
// Map video to the route's parameter
$request->attributes->set($configuration->getName(), $video);
}
}
Once your new paramConverter wrote, declare it as a service:
services:
app.param_converter.my_param_converter:
class: YourBundle\Path\To\MyParamConverter
tags:
- { name: request.param_converter, converter: my_param_converter }
arguments:
- #?doctrine
Here you're done!
My answer is largely inspired by this article and hope is helpful.

Laravel Auth Custom Driver Error

FYI : I'm very new to Laravel and doing my best to learn it properly.
Working on an auth driver that uses a soap service to authenticate.
Error I get when trying to test with Auth::attempt()
Symfony \ Component \ Debug \ Exception \ FatalErrorException (E_COMPILE_ERROR)
Declaration of Project\Providers\AuthUserProvider::retrieveByToken() must be compatible with Illuminate\Auth\UserProviderInterface::retrieveByToken($identifier, $token)
Here is the driver...
<?php namespace Project\Providers;
use Illuminate\Auth\UserProviderInterface;
use Illuminate\Auth\GenericUser;
use Illuminate\Auth\UserInterface;
class AuthUserProvider implements UserProviderInterface {
/**
* External webservice for authentication
*/
private $webservice;
/**
* The user object.
*/
private $user;
/**
* Constructor
*
* #return void
*/
public function __construct(\Project\Webservice\AuthCheckApi $webservice)
{
$this->webservice = $webservice;
$this->user = null;
}
/**
* Retrieves a user by id
*
* #param int $identifier
* #return mixed null|array
*/
public function retrieveByID($identifier)
{
$this->user = is_null($this->user) ? $this->webservice->find($identifier) : $this->user;
return $this->user;
}
/**
* Tries to find a user based on the credentials passed.
*
* #param array $crendtials username|password
* #return mixed bool|UserInterface
*/
public function retrieveByCredentials(array $credentials)
{
if(!$user = $this->webservice->byusername($credentials['username'],$credentials['password'])) return false;
return new GenericUser($user);
}
/**
* Validates the credentials passed to the ones in webservice.
*
* #param UserInterface $user
* #param array $credentials
* #return bool
*/
public function validateCredentials(\Illuminate\Auth\UserInterface $user, array $credentials)
{
$validated = $this->webservice->validateCredentials($user,$credentials['username']);
return true;
}
/**
* Needed by Laravel 4.1.26 and above
*/
public function retrieveByToken()
{
return true;
}
/**
* Needed by Laravel 4.1.26 and above
*/
public function updateRememberToken()
{
return false;
}
}
Thanks for any help.
You are implementing the UserProviderInterface so you need to add the complete definition of all functions of the interface, here you are forgetting the arguments for the last two function
public function retrieveByToken($identifier, $token)
{
}
public function updateRememberToken($user, $token)
{
}

Yii Framework - from url to route

I searched, but couldnt find something.
So, I have route rules:
...
'/reg' => '/user/user/registration',
...
in
Yii::app()->request
I couldn find any route information.
So, how can I get in module init function and having only url, route lile
/reg -> user/user/registration
UPD
The route is only available from the running controller. By the time when a module is initialized the controller is not yet available, thus you can't find out the route there. (You can follow CWebApplication::processRequest to see what happens when a request is resolved up to the point where the controller is run.)
It depends on what you try to achieve, but you could override WebModule::beforeControllerAction to do something before the module controller is run.
Today (next day after my question), I could solve this.
I will try to explain:
As Michael wrote, we cant know in module in which controller we are.
But I net get just reversed route, so, its quite esay.
Yii::app()->getUrlManager()->parseUrl('/reg');
This will return my reversed route
user/user/registration
parseUrl
Solution for Yii 1.1.15 workes for me.
class HttpRequest extends CHttpRequest {
protected $_requestUri;
protected $_pathInfo;
public function setUri($uri){
$this->_requestUri = $uri;
}
public function setPathInfo($route){
$this->_pathInfo = $route;
}
public function getPathInfo(){
/* copy from parent */
}
public function getRequestUri(){
/* copy from parent */
}
}
The usage:
$uri_path = 'my/project-alias/wall';
/** #var HttpRequest $request */
$request = clone Yii::app()->getRequest();
$request->setUri($uri_path);
$request->setPathInfo(null);
$route = Yii::app()->getUrlManager()->parseUrl($request);
//$route equals 'project/profile/wall' etc here (like in route rules);
I'm using a slightly different sub-class of CHttpRequest:
class CustomHttpRequest extends \CHttpRequest
{
/**
* #var string
*/
var $pathInfo;
/**
* #var string
*/
private $method;
public function __construct($pathInfo, $method)
{
$this->pathInfo = $pathInfo;
$this->method = $method;
}
public function getPathInfo()
{
return $this->pathInfo; // Return our path info rather than the default
}
public function getRequestType()
{
return $this->method;
}
}
Then to call it (to create a controller, which is what I want):
$request = new CustomHttpRequest($uri, $method); // e.g. 'my/project-alias/wall' and 'GET'
$route = \Yii::app()->getUrlManager()->parseUrl($request);
list($jcontroller, $actionName) = \Yii::app()->createController($route);

Extra Attribute Disappears after it is set successfully

I am trying to get all records that are tied to a parent object through a lookup table, and insert them directly into the model. I have an object, Role, that hasMany() RoleEndpoints. RoleEndpoints belongs to Role and hasMany() Endpoints. All the data is being retrieved exactly as I expect, however, it seems to disappear after I set it.
<?php
class ACL {
private $_di;
public function __construct($di) {
$this->_di = $di;
}
public function createACL() {
if(!$this->_acl) {
$this->_acl = new stdClass();
$roles = $possibleRoles = Roles::find();
/**
* Check if there is at least one role out there
*/
if($roles->count() > 0) {
/**
* Iterate over all of the records
*/
while($roles->valid()) {
$endpoints = array();
/**
* Grab each role's endpoints through the relationship
*/
foreach($roles->current()->getRoleEndpoints() as $roleEndpoint) {
$endpoints[] = Endpoints::findFirst($roleEndpoint->endpoint_id);
}
/**
* At this point, the endpoints exist in the current Role model;
I tried several different approaches; this seemed the best
*/
$roles->current()->endpoints = $endpoints;
}
/**
* Set object to loop through from the beginning
*/
$roles->rewind();
/**
* Here is where my issue lies.
*
* The endpoints attribute, which is set as a public attribute in the model class
* gets unset for some reason
*/
while($roles->valid()) {
echo '<pre>';
var_dump($roles->current());
exit;
}
As the comments say, during the second iteration of the result set, the endpoints attribute drops becomes null for some reason. Am I doing something wrong here? Am I missing a step?
Any help would be appreciated. Thank you!
There is a missing next() in the iterator traversing:
while ($roles->valid()) {
$endpoints = array();
/**
* Grab each role's endpoints through the relationship
*/
foreach ($roles->current()->getRoleEndpoints() as $roleEndpoint) {
$endpoints[] = Endpoints::findFirst($roleEndpoint->endpoint_id);
}
/**
* At this point, the endpoints exist in the current Role model;
* I tried several different approaches; this seemed the best
*/
$roles->current()->endpoints = $endpoints;
//Missing next
$roles->next();
}
Also, you don't need to iterate the cursor in that way, just a foreach is easy to read and maintain:
$roles = Roles::find();
$roleEndpoints = array();
if (count($roles)) {
foreach ($roles as $role) {
$endpoints = array();
/**
* Grab each role's endpoints through the relationship
*/
foreach ($role->getRoleEndpoints() as $roleEndpoint) {
$endpoints[] = Endpoints::findFirst($roleEndpoint->endpoint_id);
}
/**
* At this point, the endpoints exist in the current Role model;
* I tried several different approaches; this seemed the best
*/
$roleEndpoints[$role->id] = $endpoints;
}
}
//Get the endpoints
foreach ($roleEndpoints as $roleId => $endpoint) {
//...
}
Also, If this is a common task you can add a method to your model to reuse that logic:
class Roles extends Phalcon\Mvc\Model
{
public function getEndpoints()
{
$endpoints = array();
foreach ($this->getRoleEndpoints() as $roleEndpoint) {
$endpoints[] = Endpoints::findFirst($roleEndpoint->endpoint_id);
}
return $endpoints;
}
public function initialize()
{
//...
}
}
So you can get your endpoints:
$roles = Roles::find();
if (count($roles)) {
foreach ($roles as $role) {
$endpoints = $role->getEndpoints();
}
}