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.
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 in searching of the best way of removing business logic from controller and correct usage of model(and maybe services).
Some details below.
Actually, my project is more complicated, but as example I will use Simple Blog application.
I have created my application (Simple Blog) in next steps:
created bundle
generated entities(Topic, Post, Comment)
generated controller for each entity, using doctrine:generate:crud
installed FOSUserBundle and generated User entity
So, I have all needed methods and forms in my controllers. But now I have some troubles:
Admin need to be able see all topics and posts, when simple User can only see
topic and posts where he is owner.
Currently there are indexAction, that return findAll common for any user. As solution, I can check in action, if ROLE_USER or ADMIN and return find result for each condition. But this variant keep some logic at action.
I also can generate action for each role, but what happened if roles amount will increase?
What is the best way to solve this problem with result for each role?
I need to edit some parameters before saving.
For example, I have some scheduler, where I create date in some steps, using features of DateTime.
Before saving I need to do some calculations with date.
I can do it in controller using service or simple $request->params edit.
What is the best way to edit some $request parameters before saving?
My questions I have marked with bold.
Thanks a lot for any help!
What I would do is to create a query which fetches the topics. Afterwards I would have a method argument which specifies if the query should select only the topics for a certain user or all topics. Something like this should do the work in your TopicRepository:
public function findTopics($userId = false)
{
$query = $this->createQueryBuilder('topic');
if($userId) {
$query->join('topic.user', 'user')
->where('user.id = :user_id')
->setParameter(':user_id', $userId)
;
}
return $query->getQuery()->getResult();
}
So, whenever you need to get the topics only by a user, you would pass a $userId to the method and it would return the results only for that user. In your controller you'd have something similar to this code (Symfony 2.6+):
$authorizationChecker = $this->get('security.authorization_checker');
if($authorizationChecker->isGranted('ROLE_ADMIN')){
$results = $this->get('doctrine.orm.entity_manager')->getRepository('TopicRepository')->findTopics();
} else {
$results = $this->get('doctrine.orm.entity_manager')->getRepository('TopicRepository')->findTopics($this->getUser()->getId());
}
You can try using Doctrine Events and create a PreUpdate depending on your case. See the documentation for more information. If you have a TopicFormType, you could also try the form events.
You are not supposed to "edit" a $request, which is why you can't directly do that. You can, however, retrieve a value, save it as a $variable and then do whatever you want with it. You can always create a new Request if you really need it. Could you be more specific what you want to do here and why is this necessary?
Is it possible to perform form fields validation manually, forced?
I have a form. It has a global form validation. Everything works well if user submits data.
But I want to trigger validation before form is displayed to the user - show errors before submit.
Tried to submit using $form->submit([]) method but it doesn't trigger form fields validation.
Any ideas on this issue? Did I something wrong?
Do you need to validate a data only by form? Doesn't a validator service work for you?
Like
$violations = $this->get('validator')->validate($entity);
Reason was quite complicated and simple at once.
// form instantiation
$type = new MyType();
$options = [
'csrf_protection'=>!empty($_POST[$type->getName()])
];
$form = $this->createForm($type, [/* or entity */], $options);
$form->handleRequest($request);
if(!$form->isSubmitted()){
$form->submit([]);
}
And now I can see errors correctly. One of the most tricky part is the fact I wasn't aware Form $options are read-only after creation and empty check is mandatory if you want to leave CSRF protection turned on.
Invoke $form->isValid(); before showing the form.
However If data come from an external service, I would rather prevent (with ws validation, for example) users to submit wrong data through ws (ws = external service)
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 have a node type that should only be edited by users under certain circumstances that go beyond the permissions their role has. I am doing this in a custom module.
I would like to remove the ability to even see the edit tab, and not just add a validation function to the form that will alert the user after the form is submitted.
I need to add some sort of access function. Anyone know how to do this?
Thanks in advance.
--Update--
I now have 2 ways that should work.
1) Using hook_nodeapi:
function mymodule_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
switch($op) {
case 'prepare':
if(!mymodule_access_function($node)) {
$_REQUEST['destination'] = 'my_access_denied_page';
// rest of function
2) I can insert a access callback function into the menu item using hook_menu_alter.
For my purposes, 2 makes more sense. I thought I would spell out the code for (1) though since that was the answer given on this page and it works.
For the tabs visibility you can alter the themed output anywhere from a module hook to a theme template or css patch. Depending on the requirements for data visibility and performance issues some solutions are better than others. We need more details on what kind of processing you need.
For access, hook_nodeapi(), $op is 'prepare', run your custom code against $node at this point, and decide what you want to do (like redirect to another form if a requirement is not present, or to an access denied page).
Edit: Redirecting is usually done with $_REQUEST['destination'] = 'destination/alias' (does not break execution), sometimes drupal_goto('destination/alias') (breaks execution) is suitable but often it doesn't work. Please keep redirects tracked on your project, as with multiple logic conditions you may end up with unwanted and hard to debug behavior.
Every content type has default permission settings in admin/user/permissions for creating,editing ,deleting node . You may assign to anonymous or authenticated users. If you want assign to group then create another role and assign permission as mentioned above.