Use of Extbase Repositories in Symfony Command - typo3

Im upgrading an extension to work with TYPO3 v10. Since command controllers can not be used anymore, im migrating them to symfony commands as pointed by the documentation. Everything works smooth as heck except for the usage of extbase repository classes. No matter what i query, i never get a result. Since i can't find any useful information on the web and the documentation i hope this may be just something minor.
After debugging for a while i found out that the pid is not determined correctly while building the query settings. I find that kind of strange since my root template has these lines:
plugin.tx_myext.persistence.storagePid = 15403
module.tx_myext.persistence.storagePid = 15403
The repository instances are correctly injected by injectMyRepository() methods. I've tried using the extbase ObjectManager to fetch the class instances instead but the "error" stays the same.
Am i doing something wrong or is it not possible to use extbase repository classes in symfony commands?

After more research i found out that there is some bootstraping missing which results in extension settings (the storageID in my case) not being loaded. From what i've been reading, that behaviour seems intended to prevent extbase booting, i guess?
There is a reference to something similiar in the official documentation: https://docs.typo3.org/m/typo3/reference-coreapi/master/en-us/ApiOverview/CommandControllers/Index.html#initialize-backend-user
Knowing that, i tried to find a method to initialize the missing settings which i could not find. So this does indeed seem like a missing feature.
I developed a workaround which i'm not too proud of, but it's better than nothing (or rebuilding everything to doctrine for that matter). If you stumble upon the same issue, here you go. Just insert and call this method before you fire your query:
public static function initializeConfigurationManager(): void
{
/** #var ConfigurationManager $configurationManager */
$configurationManager = GeneralUtility::makeInstance(ConfigurationManager::class);
$tmpConfiguration = $configurationManager->getConfiguration(
ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK,
'myExtensionName'
);
$configurationManager->setConfiguration($tmpConfiguration);
}
That approach exploits the singleton state of the ConfigurationManager. You simply inject the static template of your extension manually and every extbase compound (like repositories) will then use these settings from there on. Lovely.
Be aware however, this is prone to break with future internal changes.

Related

Difference between addModule and registerModule in TYPO3

There are 2 functions in TYPO3 which seem to more or less do the same:
ExtensionManagementUtility::addModule
/**
* Adds a module (main or sub) to the backend interface
* FOR USE IN ext_tables.php FILES
ExtensionUtility::registerModule
/**
* Registers an Extbase module (main or sub) to the backend interface.
* FOR USE IN ext_tables.php FILES
So, according to the comments, they basically do the same, but one registers and one adds and for one it's an Extbase module. I have seen examples for both online and seen TYPO3 extensions use one or the other methods.
Which of these methods should be use to create a TYPO3 backend-module and what is the difference?
I can just use one or the other methods, but I would like to get some more guidance on these general things and what is the best practice for the future.
The obvious answer is probably, if you use Extbase, you use registerModule, if not, you use addModule. Ok, but then, why does the core do it this way in some cases and that way in the other?
Another obvious answer is that registerModule calls addModule.
See also this comment.
With addModule you just add a new Module into the left navigation bar.
With registerModule you do some pre-configuration for extbase. Have a look into the code, all controller->action combinations will be registered globally. A vender will be set and please have a look at the very last line: It calls addModule from above.
Additionally, it looks like ExtensionUtility::registerModule() is used for modules based on Extbase, and ExtensionManagementUtility::addModule() otherwise (see BackendModuleApi)

Cache2k: java.lang.UnsupportedOperationException: loader not set

Cache2k looks like a very promising caching implementation. Unfortunately the documentation is very limited, which is why I need some help with the following issue. I am using the latest version 0.26-BETA.
According to the documentation the cache is supposed to be created like this:
Cache<String,String> c =
CacheBuilder.newCache(String.class, String.class).build();
String val = c.peek("something");
assertNull(val);
c.put("something", "hello");
val = c.get("something");
assertNotNull(val);
c.destroy();
Unfortunately at least 2 of these methods are deprecated, including the CacheBuilder class itself. I therefore tried creating the cache like this:
org.cache2k.Cache<String, Object> newCache = Cache2kBuilder.of(String.class, Object.class)
.name(cacheKey.toString())
.entryCapacity(100000)
.eternal(true)
.build();
This however throws the "java.lang.UnsupportedOperationException: loader not set" exception.
The question therefore is: how am I supposed to build the cache so that I do not get this exception?
EDIT:
This gives me the same exception:
org.cache2k.Cache<Object, Object> newCache =
CacheBuilder.newCache(Object.class, Object.class)
.eternal(true)
.build();
EDIT #2:
Just one more note: When I copy&paste the code from the wiki page I get an error - as can be seen in the image below.
With what jdk version are you testing? I'll try just removing the <> that are causing the problem for now.
Thanks very much in advance!
Michael
Cache2k looks like a very promising caching implementation.
Thanks :)
According to the documentation the cache is supposed to be created like this
There are new interfaces in place. The deprecated one is still there to support users of old cache2k versions. That will get cleared up in the next weeks. Sorry for the confusion.
Please take a look here for the latest getting started information:
https://github.com/cache2k/cache2k/blob/master/doc/src/docs/asciidoc/user-guide/sections/_start.adoc
This however throws the "java.lang.UnsupportedOperationException: loader not set" exception.
The question therefore is: how am I supposed to build the cache so that I do not get this exception?
Short answer: Either use cache.peek() or wait for 0.27, since then it is working with cache.get() transparently.
Longer answer: In our own applications I use cache.get() only when a loader is defined and cache.peek() when no loader is defined or when I want to inspect the cache only. Reserving cache.get() only for the read through usage, seemed like a good idea. However, I reasoned that it might be a caveat for new users, so I change that behavior and align it to other cache solutions.
Answer to Edit 2:
For an untyped cache use the factory method Cache2kBuilder.forUnkownTypes(). Constructing the anonymous class is only needed for specific types.

PhpStorm 8.0 - How enable code completion in another file?

I implement MyClass containing the method method() and I store the instance in $_ENV['key'] in test.php. Also in test.php the code completion works when I type $_ENV['key']->.
In test2.php I include test.php and the code completion does not work any more for $_ENV['key']->.
Does anyone know how to enable this in PhpStorm?
AFAIK type tracking for arrays works within the same file only.
You can bypass it via intermediate variable (yes, it's not a nicest solution) and small PHPDoc comment, like this:
/** #var MyClass $myVar */
$myVar = $_ENV['key'];
$myVar->
P.S.
In general, I'd suggest not using global arrays this way (or even not using global vars at all -- only very basic stuff during bootstrap, if possible). Instead (based on your code) I may suggest using some static class (as one of the alternatives) with dedicated field where you can easily give type hint (via PHPDoc) to a class field -- this way IDE will always know hat type it is. Current PHP versions (5.5 and especially 5.6) work with objects nearly as fast as with arrays, even leading in (smaller) memory consumption.
Obviously, such suggestion does not really apply if this code is not yours.

Using Concat in TYPO3 Extbase Query

i am struggling a little challenge and i am wondering what the solution might be as I couldn't find an answer in the documentation.
Here is my current working query (part):
$constraints[] = $query->like('kategorie', '%'.$kategorie.'%');
What I want to do is something like:
$constraints[] = $query->like(CONCAT(',', kategorie, ','), '%,'.$kategorie.',%');
Which obviously doesn't work at all. : -)
Every Help is really appriciated. Hope someone know the right syntax. TYPO3 Version is latest 6.1
Thank's alot!
First of all, Extbase query generation didn't change in 6.0, so it's the same for 4.x and 6.x.
Maybe you misunderstand the way Extbase is builing the query.
$query->like('property', '%value%');
will return an object when %value% is contained in "property". Such a property must be defined in the domain model. You can only query properties that have a "getProperty" method in their domain model.
Looking at your code, I think you're finding a way to query for a value being present in a comma-separated value list? Then you would use
$query->in('kategorien', $kategorie);
EDIT:
Your specific problem seems to be that you are not using a true relation for assigning "Kategorien" to your entity. You're using a comma-separated list to hold references to another model. You're discouraged to do so, but it is technically possible and used in the TYPO3 core: The FrontendUser model has a property "usergroup" that works in the same way.
Please have a look at the FrontendUser model: https://git.typo3.org/Packages/TYPO3.CMS.git/blob/HEAD:/typo3/sysext/extbase/Classes/Domain/Model/FrontendUser.php
The annotation of your Kategorien must be correct, e.g.:
/**
* #var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\My\Extension\Domain\Model\Kategorien>
*/
protected $kategorien;
Also make sure that getKategorien is correct.
If you still have problems, keep in mind that the TCA definition must be working to have Extbase work correctly.
In my opinion, a best practise would be to use the category API introduced in TYPO3 6.0:
http://wiki.typo3.org/TYPO3_6.0#Category

WCF Data Service with EF fails to expose imported functions

(I am also using .NET 4.0 and VS 2010.)
I created a function import returning a complex type, as explained at http://msdn.microsoft.com/en-us/library/bb896231.aspx. The function import and new complex type appear in my .edmx file and in the Designer.cs file. However, the function does not appear when I view the service in the browser, and when I add or update a service reference in the client project, the function does not appear there either - as is to be expected, given the first result.
Creating an imported function and using it seems conceptually very simple and straightforward, and one would think it would just work, as Microsoft's step-by-step instructions appear to suggest: http://msdn.microsoft.com/en-us/library/cc716672.aspx#Y798 (which article shows the SP returning entity types - I tried this also, and it doesn't work for me either).
This blog post shows the addition of a method to the DataService class, which Microsoft's instructions omit: http://www.codegain.com/articles/wcf/miscellaneous/how-to-use-stored-procedure-in-wcf-data-service.aspx I tried adding one method returning a list of entity types and another returning a list of complex types, and still had no success. I still could not access the functions, either directly via the browser or from the client application via a service reference.
Thanks in advance for any help with this.
config.SetServiceOperationAccessRule("*", ServiceOperationRights.All);
MS would do well to add a note to the walkthroughs stating that the above bit of code must be there. (It may be better to enable each operation explicitly than to use "*".)
http://www.codegain.com/articles/wcf/miscellaneous/how-to-use-stored-procedure-in-wcf-data-service.aspx shows that line of code. Also, something it is there in the code, commented out, when one creates the WCF Data Service. Some of us like to delete commented-out code that we aren't using and that seems irrelevant - perhaps doing so a bit prematurely, sometimes.