Im using a the hook
public function processDatamap_afterAllOperations(DataHandler &$pObj)
{
}
I want to read the protected mmHistoryRecords from the DataHandler Class.
How can I do this in my class? My class already extends BackendUtility
You can use reflection to access protected properties or methods. That saves you from XCLASSing.
public function processDatamap_afterAllOperations(\TYPO3\CMS\Core\DataHandling\DataHandler $pObj)
{
try {
$prop = new \ReflectionProperty(
\TYPO3\CMS\Core\DataHandling\DataHandler::class,
'mmHistoryRecords'
);
$prop->setAccessible(true);
$mmHistoryRecords = $prop->getValue($pObj);
} catch (\ReflectionException $e) {
}
}
You can use it on methods and properties.
So in PHP nothing is ever "private"... You need to judge yourself if you should do it, but it's always a possiblity.
I don't see another option than using XCLASS for the DataHandler and adding a getter method for this property.
You can't access a protected property from outside the class it's in. That's the whole idea of protected (and private) properties. You'd need a getter method, so you can either request one from the core developers or xclass DataHandler to add it yourself.
The problem with xclass is that it might not work anymore after an update of TYPO3 if the class you're xclassing is changed, but the chance of that if you're only adding a getter for the protected property you need is pretty small for minor TYPO3 updates.
You can find more on xclass here: https://docs.typo3.org/typo3cms/CoreApiReference/ApiOverview/Xclasses/Index.html
Related
Just a quick question. I'm building some API. I was thinking about creating simple parent class that would deal with form requests.
So for example if you would like to easily handle form request you just extend this class and you get access to request object, request data extracted from that object and bunch of methods that do some things for you out of the box. It doesn't matter what and why exactly.
The problem is:
I send request through postman.
I try to use request object in class that extends parent class but instead of request I get null.
How do I set up the whole thing?:
Now in Symfony every controller is by default registered as a service so I override this definition like this:
#generic api form controller
App\Controller\Api\ApiFormController:
calls:
- [setDependencies, ['#request_stack', '#App\Service\Serialization\Serializer']]
So as you can see I am using setter injection.
I extend above class in my other class. Let's call it PostController. So:
<?php
namespace App\Controller\Api;
use Symfony\Component\HttpFoundation\RequestStack;
class ApiFormController
{
/**
* #var Request
*/
public $request;
/**
* #param RequestStack $requestStack
*/
public function setDependencies(
RequestStack $requestStack
) {
$this->request = $requestStack;
}
}
And now PostController:
public function get(int $post = null)
{
dump($this->request); exit;
}
I was expecting to get access like this and I think I understand why I don't have access to this object. I'm looking for some ideas how I could achieve this goal in cleanest possible way. I'm not expecting ready answers but hints.
I was thinking about using events to set it up in the background?
I also think it has something to do with the way I'm hooking up my controller as a service.
The core of it all: Symfony does not pick up service definition for subclasses. So if you define dependencies for a class and extend it in another class, you have to define the dependencies for this second class too.
The easiest way is to use the parent keyword for this, so your example would work in the following way:
App\Controller\Api\ApiFormController:
calls:
- [setDependencies, ['#request_stack', '#App\Service\Serialization\Serializer']]
PostController:
parent: App\Controller\Api\ApiFormController
If you are using autowiring, you can use #required to make Symfony call the setter automatically. https://symfony.com/doc/current/service_container/autowiring.html#autowiring-other-methods-e-g-setters
/**
* #param RequestStack $requestStack
* #required
*/
public function setDependencies(
RequestStack $requestStack
) {
$this->request = $requestStack;
}
This should do the trick.
I see several problems here.
If you want to inject dependencies in such a way you should define controller as service. You can read more here.
Routing should be something like this:
# config/routes.yaml
get_something:
path: /
defaults: { _controller: App\Controller\Api\PostController:get }
Also, you should define PostController as service, not ApiFormController.
You injected RequestStack but type hint for the attribute is Request.
Instead of:
$this->request = $requestStack;
You need to use:
$this->request = $requestStack->getMasterRequest();
I have this code in my controller, it takes 'procedure_type' from the request and checks to see if a ProcedureType with that name exists. If it does it uses the object, if not it creates a new ProcedureType, then return the new object to use.
// Check the typed in ProcedureType against existing types.
$procedureTypes = $entityManager->getRepository('IncompassSurgeryBundle:ProcedureType')->findBy(array('name' => $request->request->get('procedure_type'), 'vendor' => $vendorId));
if (empty($procedureTypes)) {
// Create Procedure Type
$procedureType = new ProcedureType();
$procedureType->setVendor($vendor)
->setName($request->request->get('procedure_type'))
->setCreated(new \DateTime())
->setUpdated($procedureType->getCreated());
$entityManager->persist($procedureType);
} else {
$procedureType = $procedureTypes[0];
}
I don't think this is the best way to do this, I'd like to move the code into a function, say checkProcedureType(), but I don't know where the best place is to put that. I don't think it could go in the Entity or Repository classes, and moving it to a private function in the controller doesn't feel right.
I'm sure there is a class type that I'm not aware of, that extends the Entity. Or maybe I should just put these functions in my entity classes.
Service are the answer to almost everything in Symfony 2. Create a service like this :
namespace Your\Bundle\Service;
class ProcedureService // Call this the way you want
{
protected $entityManager;
public function __construct($entityManager)
{
$this->entityManager = $entityManager;
}
public function callMeTheWayYouWant($vendorId, $vendor)
{
// Check the typed in ProcedureType against existing types.
$procedureTypes = $this->entityManager->getRepository('IncompassSurgeryBundle:ProcedureType')->findBy(array('name' => $request->request->get('procedure_type'), 'vendor' => $vendorId));
if (empty($procedureTypes)) {
// Create Procedure Type
$procedureType = new ProcedureType();
$procedureType->setVendor($vendor)
->setName($request->request->get('procedure_type'))
->setCreated(new \DateTime())
->setUpdated($procedureType->getCreated());
$this->entityManager->persist($procedureType);
} else {
$procedureType = $procedureTypes[0];
}
// The rest of your code
}
}
In your services.yml file :
your_service:
class: Your\Bundle\Service\ProcedureService
arguments: [#doctrine.orm.entity_manager]
Then use it in your controller :
$this->get('your_service')->callMeTheWayYouWant($vendorId, $vendor);
If logic is somehow related to acessing database I always go for repository. However, if cases like yours, I tend to analyze it's dependency map.
Does your code repeats in some other method within same class, only?
If so, go for private method.
Is this part of code reused somewhere else but does not rely on some services?
You could externalize logic by creating separate class and static method which executes the code. Beware: Tends to get messy really quick
Finally, does your code rely on services/configuration?
Create a separate service, inject the services/configuration and invoke it's method. Adds a bit of overhead, if your abuse it, but you should be fine
Personally, in your example, I would go for private method, but that's just my opinion.
How do I create a template that each time when I create a class that extends MyClass, it will automatically add 3 functions.
EDIT:
In other words I am trying to implement Abstract functionality in AS3. Assume that MyClass have both private and protected methods.
I see the only way to write own code template and call it every time you need, in Flash Builder: window->preference->flash builder->editors->code template->action script->new and give the name to the template, for instance myclass.
You can use existed templates as an example for template syntax.
Template code for MyClass child class with three methods:
import my.package.MyClass
/**
* #author ${user}
*/
public class ${enclosing_type} extends MyClass
{
public function ${enclosing_type}()
{
}
override public function publicMethod():void
{
}
override protected function protectedMethod():void
{
}
override private function privateMethod():void
{
}
${cursor}
}
Usage:
Create new "action script file" or "new class",
remove all file content
type myclass and choose from auto-complete options template myclass
If you are actually extending MyClass, all of MyClass's functions are already available to your descendants. You can also override either of them with old header and desired new body, and still be able to call older versions of those functions via super qualifier. So, you add those functions to MyClass and let them be.
Another way is to make an interface - it's a set of declarations without any function bodies, which you have to implement in any class that wants this interface in its content. A short introduction to interfaces. Then your MyClass will be an interface, with 3 function declarations in it, and whichever class will be declared as implements MyClass will have to provide bodies for these functions.
Check other keywords on that page, including extends and implements.
Hope this helps.
EDIT: There are no abstract classes in AS3, however you can emulate abstract functions in a normal class via exception throwing:
protected function abstractFunction(...params):void {
throw new Error("Abstract!");
}
I am using the extension News System, "news", and while changing the templates, I've noticed that while I can use things like {newsItem.datetime} or {newsItem.uid}, I cant use this with the custom fields i have created when extending the table tx_news_domain_model_news, like {newsItem.mycustomfield}
Edit: I have been pointed to this url and I've followed the instructions, but it's not working. This is my code
News.php
<?php
class Tx_WedoExtendnews_Domain_Model_News extends Tx_News_Domain_Model_News {
/**
* #var string
*/
protected $txWedoextendnewsLocation;
public function getTxWedoextendnewsLocation() {
return "this";
return $this->txWedoextendnewsLocation;
}
public function getWedoextendnewsLocation() {
return "that";
return $this->txWedoextendnewsLocation;
}
}
?>
Since I wasn't getting anything, I changed the returning values to string literals, to see if the problem was in the class and method names, or the property. Im still not getting anything. I think the underscored might be playing tricks on my code.
My extension key is wedo_extendnews and the new field is tx_wedoextendnews_location. Any ideas where the error lies?
Yes. To be able to access an object in fluid, you need the according setters in your model and maybe (not sure right now) an entry in the TCA.
If you want to access {newsItem.mycustomfield} you need an according setter in the model, like public function getMycustomfield() (note the get in get<Myfuncname>, it is mandatory).
Is there a way to get the proxy that editor is editing?
The normal workflow would be:
public class Class implments Editor<Proxy>{
#Path("")
#UiField AntoherClass subeditor;
void someMethod(){
Proxy proxy = request.create(Proxy.class);
driver.save(proxy);
driver.edit(proxy,request);
}
}
Now if i got a subeditor of the same proxy
public class AntoherClass implements Editor<Proxy>{
someMethod(){
// method to get the editing proxy ?
}
}
Yes i know i can just set the proxy to the Child editor with setProxy() after its creation, but i want to know if there is something like HasRequestContext but for the edited proxy.
This usefull when you use for example ListEditor in non UI objects.
Thank you.
Two ways you can get a reference to the object that a given editor is working on. First, some simple data and a simple editor:
public class MyModel {
//sub properties...
}
public class MyModelEditor implements Editor<MyModel> {
// subproperty editors...
}
First: Instead of implementing Editor, we can pick another interface that also extends Editor, but allows sub-editors (LeafValueEditor does not allow sub-editors). Lets try ValueAwareEditor:
public class MyModelEditor2 implements ValueAwareEditor<MyModel> {
// subproperty editors...
// ValueAwareEditor methods:
public void setValue(MyModel value) {
// This will be called automatically with the current value when
// driver.edit is called.
}
public void flush() {
// If you were going to make any changes, do them here, this is called
// when the driver flushes.
}
public void onPropertyChange(String... paths) {
// Probably not needed in your case, but allows for some notification
// when subproperties are changed - mostly used by RequestFactory so far.
}
public void setDelegate(EditorDelegate<MyModel> delegate) {
// grants access to the delegate, so the property change events can
// be requested, among other things. Probably not needed either.
}
}
This requires that you implement the various methods as in the example above, but the main one you are interested in will be setValue. You do not need to invoke these yourself, they will be called by the driver and its delegates. The flush method is also good to use if you plan to make changes to the object - making those changes before flush will mean that you are modifying the object outside of the expected driver lifecycle - not the end of the world, but might surprise you later.
Second: Use a SimpleEditor sub-editor:
public class MyModelEditor2 implements ValueAwareEditor<MyModel> {
// subproperty editors...
// one extra sub-property:
#Path("")//bound to the MyModel itself
SimpleEditor self = SimpleEditor.of();
//...
}
Using this, you can call self.getValue() to read out what the current value is.
Edit: Looking at the AnotherEditor you've implemented, it looks like you are starting to make something like the GWT class SimpleEditor, though you might want other sub-editors as well:
Now if i got a subeditor of the same proxy
public class AntoherClass implements Editor<Proxy>{
someMethod(){
// method to get the editing proxy ?
}
}
This sub-editor could implement ValueAwareEditor<Proxy> instead of Editor<Proxy>, and be guaranteed that its setValue method would be called with the Proxy instance when editing starts.
In your child editor class, you can just implement another interface TakesValue, you can get the editing proxy in the setValue method.
ValueAwareEditor works too, but has all those extra method you don't really need.
This is the only solution I found. It involves calling the context edit before you call the driver edit. Then you have the proxy to manipulate later.