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
Related
I have several entities, each with its form type. I want to be able, instead of saving the entity straight away on save, to save a copy of the changes we want to perform and store it in DB.
We'd send a message to the user who can approve the change, who will review the original and the changed field(s) and will approve or not. If approved the entity would be properly flushed.
To solve the issue I was thinking about:
1) doing a persist
2) getting the changesets (both the one related to "normal" fields, and the one relative to collections)
3) storing it in DB
4) Performing $em->refresh() to discard changes.
Later what I need is to get the changset(s) back, ask the (other) user to approve it and flush it.
Is this doable? What I'm especially concerned about is that the entity manager that generated the first changeset is not the same we are going to use to perform the flush, I basically need to "load" a changeset.
Any idea on how to solve the issue (this way, or another way ;) )
Another solution (working only for "normal" fields, not reference ones that come from other entities to the current one, like a many to many) would be to clone the current entity, store it, and then once approved copy the field(s) from the cloned to the original one. But it does not work for all fields (if the previous solution does not work we'd limit the feature just to "normal" fields).
Thank you!
SN
Well, you could just treat the modifications as entities themselves, so that every change is stored in the database, and then all the changes that were approved are executed against the entity.
So, for example, if you have some Books stored in the database, and you want to make sure that all the modifications made to these are approved, just add a model that would contain the changeset that has to be processed, and a handler that would apply these changes:
<?php
class UpdateBookCommand
{
// If you'll store these commands in a database, perhaps this field would be a relation,
// or you could just store the ID
public $bookId;
public $newTitle;
public $newAuthor;
// Perhaps this field should be somehow protected from unauthorized changes
public $isApproved;
}
class UpdateBookHandler
{
private $bookRepository;
private $em;
public function handle(UpdateBookCommand $command)
{
if (!$command->isApproved) {
throw new NotAuthorizedException();
}
$book = $this->bookRepository->find($command->bookId);
$book->setTitle($command->newTitle);
$book->setAuthor($command->newAuthor);
$this->em->persist($book);
$this->em->flush();
}
}
Next, in your controller you would just have to make sure that the commands are somehow stored (in a database or maybe even in a message queue), and the handler gets called when the changesets could possibly get applied.
P.S. Perhaps I could have explained this a bit better, but mostly the inspiration for this solution comes from the CQRS pattern that's explained quite well by Martin Fowler. However, I guess in your case a full-blown CQRS implementation is unnecessary and a simpler solution should work.
I've got a big Symfony 2 form on a huge collection (over 10k objects). For simple reasons, I cannot display a form of thousands of objects. I am displaying a form of about 300 objects.
I have found no way to filter a collection into a form and thus do the following :
$bigSetOfObjects = array(
'myObject' => $this
->getDoctrine()
->getRepository('MyObject')
->findBy(... )
);
$form = $this->createForm(new MyObjectForm(), $bigSetOfObjects);
// And a little further
if ($this->getRequest()->getMethod() == 'POST') {
$form->bindRequest($this->getRequest());
$this->getDoctrine()->getEntityManager()->flush();
}
Everything works great. Form is displayed with the correct values and the update works fine also. Data is correctly saved to the database. The problem is that Doctrine is executing a single update statement per object meaning the whole page is about 300 SQL statements big causing performance issues.
What I do not understand is that I'm updating only a couple of values of the form, not all of them. So why is Doctrine not able to detect the updated objects and thus update only those objects in the database?
Is there anything I'm doing wrong? I might have forgotten?
By default Doctrine will detect changes to your managed objects on a property-by-property basis. If no properties have changed then it should not be executing an update query for it. You may want to check that the form isn't inadvertently changing anything.
You can, however, change how doctrine determines that an object has changed by modifying the tracking policy. Since you are working with a lot of objects you may want to change to the DEFERRED_EXPLICIT tracking policy. With this method you would specifically call:
$em->persist($object);
on the entities that you want to be updated. You would have to implement your own logic for determining if an object needs to be persisted.
Global $user;
$items = field_get_items('user', $user, 'field_patientid', $user->language);
I have a field on user entity and I always get a value of FALSE in my debug.
In my database I have the correct entity type which is user. Why am I not getting any values?
I am able to pull up value using:
$user_fields->field_patientid['und']['0']['value'];
Why will the above mentioned statement not work?
If you look at the code for field_get_items(), you'll notice that the field information you're looking for needs to already be in the $user object in order for it to be returned by the function.
But global $user does not provide the field data.
From http://api.drupal.org/api/drupal/developer%21globals.php/global/user/7#comment-13744
The global user object contains some basic data from Drupal core. It
does not automatically include data from other modules, including the
core profile module. To get all data in the user object, you need to
do a full user_load().
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();
I'm making a module to allow users to update single fields on in this case, their user entity.
The code below is an example of the method I have initially been using to get it working and test other elements of the module
global $user;
$account = user_load($user->uid);
$edit = (array) $account;
$edit['field_lastname']['und'][0]['value'] = 'test';
user_save($account, $edit);
However this bypasses any field validation defined elsewhere in Drupal. I don't want to reproduce any validation written elsewhere - it's not the Drupal way!
My question is: Is there a function in Drupal 7 that can be called to update the value of a single field. I imagine such a function would clear the appropriate caches, invoke the fields validation etc.
I am aware the solution will be totally different to my current user object based one. I just can't for the life of me find the appropriate function in the API. I wander whether the fact I am looking for a save function alone is the problem - and that there are some other necessary steps that come before.
Any help gratefully appreciated.
Check out the drupal_form_submit function. It lets you submit forms from code. In this case, you could use it to the user edit form, which would then fire the appropriate validation.