After creating a model and adding it to a repository I want to have the new ID for different purposes (creating a mail, updating other fields outside the Extbase world)
$page = t3lib_div::makeInstance('Tx_MyExt_Domain_Model_Page');
$page->setTitle('Hello World');
$this->pageRepository->add($page);
At this point $page hasn't got an ID yet, uid is null.
$page->getUid(); // returns null
When does it get it? And how can I retrieve in on runtime?
In ExtBase, objects are "managed". This means every persistence transaction (add/remove/update) is simply noted in the underlying logic, but not yet executed until the appropriate time (like the end of processing a request). So, just because you add an object to a repository doesn't mean that it's actually added yet. That actually happens once $persistenceManager->persistAll() is called, which isn't something you need to do manually, ever. The point is, your $page object won't have a UID until it's saved and that's why $page->getUid() returns null. Look here for a great explanation.
I suspect that you are trying to do something outside of the ExtBase object/MVC lifecycle. At least, last time I got null when I tried to get the UID of an object, it was because I wasn't operating within the framework appropriately.
However, if you post some more code and give us a bigger picture of what you're trying to achieve, maybe we can help you get to a point where that object actually has a UID. For instance, if you're in a Controller object, tell us which Action method you're in, or if you're in a Repository object, tell us what you're trying to get from the repository and where/how you plan on using the query results.
EDIT
Just guessing here, but I'm assuming you're executing this code in some action of a controller. Since after the controller is executed a view is rendered, you can just pass the page object to the view:
$this->view->assign('page', $page);
And then in your view you can use the page object in a link:
<f:link.action action="show" arguments="{page:page}">
See this page object
</f:link.action>
And then in the show action of your controller you can show the page:
public function showAction(Tx_MyExt_Domain_Model_Page $page) {
// Do whatever you need to show the page in the `Show.html` template
}
I really am just guessing here. If you can give us a larger picture of what you're trying to do, what your action methods are supposed to do and things like that, we can answer your question a little more confidently.
(I'm also assuming that your page object isn't a replacement for the regular TYPO3 pages and that they are something totally different. It's much easier to deal with those TYPO3 pages through the backend interface than at the php level.)
You can call persistence manager explicitly in Your controller like this
#TYPO3 4.x
$persistenceManager = $this->objectManager->create('Tx_Extbase_Persistence_Manager');
$persistenceManager->persistAll();
#TYPO3 6.x
$persistenceManager = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager');
$persistenceManager->persistAll();
Related
I'm using WooCommerce Subscriptions on a site to provide team-based memberships. I'd like to ensure that the owner of the Subscription matches the owner of the team (one user to rule them all...!)
It's possible to do this via admin by using the customer dropdown fields.
So, I have been trying to set this programmatically. As I understand it, there are getter and setter methods for all the Subscription data (and as a Subscription is extended from WC_Order, those methods should work too). However, I can't figure out what method to use to make this change.
I've tried creating both a subscription and an order instance from a subscription ID, but neither of the methods I've tried below work:
set_user_id(456)
set_customer_id(456)
When I print_r() the Subscription instance, the original customer_id is still there under the data array:
WC_Subscription Object
(
[data:protected] => Array
(
...
[customer_id] => 123
)
...
)
Given that the array is protected, I'm guessing there's a setter method I haven't tried yet. Can someone please help me with what type of instance and setter method I need for this please?
Cheers!
I'm pleased to say I've solved this one myself - posting here to hopefully help someone else from banging their heads against the walls!
Turns out I was doing everything correctly, I just wasn't calling the save() method after I made my changes......! D'oh!
I'm quite used to functions in WordPress having immediate effect - a valid call to update_post_meta, for example, will take effect straight away.
Instead, WooCommerce stores changes via getters/setters within the local instance created through WC_Order (or other abstractions). These are only saved to the database* when you call the save() method. I believe this is to help prevent unnecessary database calls.
*or data store if you're doing something very fancy.
Code example for those who need it, for an order ID '123' and a new user ID '456':
// Create order instance
$order_instance = wc_get_order(123);
// Set new customer id
$order_instance->set_customer_id(456);
// Save changes
$order_instance->save();
// To echo data back, use the get_data() method to create an array of data, which you can assign however needed. For example:
$order_data = $order_instance->get_data();
$customer_id = $order_data['customer_id'];
echo 'customer number = ' . $customer_id;
I found the information about why the data requires manually saving (it's only stored in the local instance) from the very helpful doc at Advanced Woo:
"Setter methods update information in the WC_Data object held in working memory. However, one of the Database Operations Methods must be called to make the change in the database."
https://advancedwoo.com/topic/wc_data-and-data-storage-manipulate/#/setters
I'm trying to create a re-usable script for capturing record changes onSave with Server-side scripting. To do that, I need the model information for a given table, including what type each field is.
I have figured out how to get the model for my table and details for the fields:
var table = "Clients";
var myObject = app.models[table];
// Dump the properties of the 2nd field in the model
console.log("Field 2 properties: " + JSON.stringify(myObject["L"]["fields"]["1"]));
I see this:
{"name":"Client",
"key":"zzzkS1spSPKkRXMn",
"displayName":null,
"description":"Short name for client (must be unique)",
"type":{},
"required":false,
"uid":false,
"defaultValue":null,
"minLength":0,
"maxLength":null,
"integer":false,
"sortable":true,
"minValue":null,
"maxValue":null,
"regexp":null,
"regexpError":null,
"possibleValues":null,
"aggregationType":null
}
"type" looks like an empty property here and I can't seem to figure out how to get any reference to it to tell me what I need.
How do I get usable type information for a given field in a model?
Right now, App Maker doesn't expose an API to access the model metadata.
You snippet is actually accessing App Maker's internal state and might break in future releases (the "L" property is actually obfuscated by a JS compiler and not designed to be accessed from user land).
We know this kind of meta-programming is handy and this is something we might add in the future based on user feedback. Please feel free to submit a request feature in our issue tracker (https://developers.google.com/appmaker/support).
I have an entity type "Post" and I would like to create a view that will show one random Post with a given category. I created a Data pipeline that grabs all posts and I created a view with ListPresentation = a "TemplateSettings" entity type that lets me choose categories.
I planned to use the Razor template to filter the items for those matching the categories in List.Presentation.Categories. But, I can't seem to reference List.Presentation.Categories. I get an error that System.Collections.Generic.List doesn't contain an entry for "Presentation". When I use #ListPresentation, the whole object in null... so #ListPresentation.Toolbar, etc. all throw errors, despite me having set a "Demo Item".
Can anybody see what would be wrong with this setup? How do I reference List Presentation stuff in Razor?
Thanks.
I figured this out... The direct thing seems to be "ListPresentation", but the snippets use "List.Presentation". Still, it wasn't working in my case because I was using a data query that didn't include the module data. So, I had to modify that query to include the module data as well as the full list of entities, regardless of the module. Then, I got the full list from one data stream, and the ListPresentation fields were available.
Note also that you can use ListContent.Presentation - that would be the newest, most consistent API which always places Presentation information as a property of the entity it's describing.
I'd like to know how to access the Request object in an entity (Symfony2) to modify the user locale.
If someone has found a solution for my problem, please let me know.
It's not possible. This is by design: the entity is just a simple object that should know nothing about the request - it's the responsibility of the controller to interpret the request, and manipulate the entity based on that.
Something like:
//inside your controller:
public function fooBarAction(Request $request)
{
$entity = // get entity
$entity->setLocale($request->getSession()->getLocale());
}
The above is just example code, it won't work if you just copy and paste it. It's just to demonstrate the general idea. The entity should just be a very simple object, who's only responsibility is to hold some data. It shouldn't know where the data is coming from - that keeps it flexible (if you want to set the locale based on something else, you only have to change your controller, not all your entities).
It is possible, but...
What you can but never should do is inject the Request object into the entity (Practically turning your entity into service, see here). Also, even worse idea (but which people still do), you could inject the whole container and get Request from there. The reason why you shouldn't do it is you never should have any code that deals with business rules or any system code in your entities.
You can switch your locale directly in your routes by using _locale custom variable (accessible also from the Request). Or you can create a kernel listener, which will do the required functionality for you. This way you keep your code testable and decoupled.
I am building a custom module that will allow my users to do a simple query against an MS SQL database. I've built the form using hook_form() and have gotten validation to work.
I'm planning on retrieving the data from hook_form_submit(), but once I've done that, how do I append it below the form? It does not appear that I have access to $output from hook_form_submit(). I'm at a loss as to what to do next.
Thanks
Dana
When you are rendering the form you should check for $form_state['values'] to see if the user has already submitted a form when you're rendering the form. Then you could paint the form results in the same step as painting the form.
The first time the user loads the form page the $form_state variable won't contain any submitted form info so you can render an empty results table.
There's a good illustration of the Drupal Form API workflow on Drupal.org here: Form API Internal Workflow Illustration
The problem in trying to output data in the hook_form() method is that the method gets invoked twice which clears the post values the second time through. Throw a dpm($form_state) in the hook_form() function and you'll see two sets of post data. One with values and one without.
So after dissecting the built in Search module, which pretty much operates exactly the way I want my form to work, I figured out how this is done. Well, at least one way you can do it.
What Search module does is take the values from $form_state in hook_form_submit() and pastes them into the URL, then it sets the $form_state['redirect'] to that new URL, effectively storing those variables in the URL and changing the POST to a GET.
Now, in the callback, they extract those values from the URL, do the search on them, THEN they call drupal_get_form(), append the results to the end and return it.
There's another solution HERE where they use SESSION to store the values until the second trip through. Weird, but it works.