I know that I can make two different field types and assign different roles to them.
Because of using views, custom searches, and gmaps, and because this will be applied to Field collection I really need this kind of approach to the problem.
I tried to crate custom module that will limit role staff to only be able to insert two field_text into node but administrator can insert as many as he wont. field_text Number of values is set to Unlimited and Content type name is youtube.
I found this for drupal 6 but I don't know how to code it in drupal 7.
function myformlimit_form_alter(&$form, &$form_state, $form_id) {
if ($form_id == 'youtube') {
global $user;
// Only allow to insert 2 text for role = staff
if (in_array('staff', $user->roles)) {
$text_limit = 2;
$form['#field_info']['field_text']['multiple'] = $text_limit;
$i = 1;
foreach ($form['field_text'] as $key => $value) {
if (is_numeric($key)) {
if ($i > $text_limit) {
unset($form['field_text'][$key]);
}
$i++;
}
}
}
}
}
Well you are half way there. You can use the following code to get you the idea.
Kindly note that I named my field field_test_field, you can replace that with your field's name.
function myformlimit_form_alter(&$form, &$form_state, $form_id)
{
if($form_id == 'youtube_node_form')
{
global $user;
if(in_array('staff', $user->roles))
{
if($form_state['field']['field_test_field'][LANGUAGE_NONE]['items_count'] >= 2)
{
unset($form['field_test_field'][LANGUAGE_NONE]['add_more']);
}
}
}
}
Related
I'm working on a project and my task is : set up a page to edit my user account information. For this, I have to use the TYPO3 extension femanager.
I installed the extension and put the plugin on my page. I have 4 fields that are displayed (photo, phone numbers and email). But when i submit my form, I have this error :
Argument 2 passed to
In2code\Femanager\Utility\FrontendUtility::forceValues() must be of
the type array, null given, called in
/home/dev/rta/htdocs/typo3conf/ext/femanager/Classes/Controller/EditController.php
on line 69
I tried to look for someone with a similar problem on the Internet but couldn't find anything. I looked at the code, but since it's the base extension code, I don't think that's where the problem comes from. The users are stored in the fe_users table in my database and the fields pre-fill nicely with my existing data.
I just learned TYPO3 3 weeks ago so I have a lot of gaps and I'm not very familiar with it yet.
If it can help, here is my EditController.php (lines 66 to 79) :
public function updateAction(User $user)
{
$this->redirectIfDirtyObject($user);
$user = FrontendUtility::forceValues($user, $this->config['edit.']['forceValues.']['beforeAnyConfirmation.']);
$this->emailForUsername($user);
UserUtility::convertPassword($user, $this->settings['edit']['misc']['passwordSave']);
$this->signalSlotDispatcher->dispatch(__CLASS__, __FUNCTION__ . 'BeforePersist', [$user, $this]);
if (!empty($this->settings['edit']['confirmByAdmin'])) {
$this->updateRequest($user);
} else {
$this->updateAllConfirmed($user);
}
$this->redirect('edit');
}
And here is my FrontendUtility class (used in my EditController at line 69) :
public static function forceValues(User $user, array $settings)
{
foreach ((array)$settings as $field => $config) {
$config = null;
if (stristr($field, '.')) {
continue;
}
// value to set
$value = self::getContentObject()->cObjGetSingle($settings[$field], $settings[$field . '.']);
if ($field === 'usergroup') {
// need objectstorage for usergroup field
$user->removeAllUsergroups();
$values = GeneralUtility::trimExplode(',', $value, true);
$userGroupRepository = self::getUserGroupRepository();
foreach ($values as $usergroupUid) {
/** #var UserGroup $usergroup */
$usergroup = $userGroupRepository->findByUid($usergroupUid);
$user->addUsergroup($usergroup);
}
} else {
// set value
if (method_exists($user, 'set' . ucfirst($field))) {
$user->{'set' . ucfirst($field)}($value);
}
}
}
return $user;
}
If anyone has an idea, I'm interested!
PS : I use TYPO3 v9.5.8
I've got woocommerce registration form with two sections:
- One for private person,
- the other for company.
In company option there is two additional fields. I can switch between private and company by radio buttons and then I see relevant fields.
Problem: When I fill the form (as private user) and make some mistake, form reload and show where is the error (that is ok).
But unfortunately, after reload, it loads the form with all fields (the ones with additional company fields too). So I need to click 2 times between private and company to restore the right behavior.
How can i fix this? I mean after this error reloading, to display the form as initially.
I don't be sure that this is code responsible for this, but let's try:
add_filter('woocommerce_registration_errors', 'rs_registration_form_validation', 10, 3);
function rs_registration_form_validation($reg_errors, $sanitized_user_login, $user_email)
{
global $woocommerce;
$company_fields_required = (!empty($_POST['registration_type']) && 'company' === $_POST['registration_type']);
$shipp_to_different_address = (!empty($_POST['register_ship_to_different_address']) && 1 == $_POST['register_ship_to_different_address']);
$errors = false;
$fields = rs_registration_form_fields();
if ($shipp_to_different_address) {
$fields += rs_registration_form_fields_address();
}
if (!$company_fields_required) {
unset($fields['billing_company']);
unset($fields['billing_nip']);
}
//Validate required
foreach ($fields as $field => $settings) {
if (false === isset($settings['required']) || true === $settings['required']) {
if (empty($_POST[$field])) {
$errors = true;
wc_add_notice('Pole: <strong>'.$settings['label'].'</strong> jest wymagane.', 'error');
}
}
}
if ($errors) {
return new WP_Error('registration-error', 'Proszę poprawić błędy w formularzu');
}
return $reg_errors;
}
add_action('woocommerce_created_customer', 'rs_registration_form_submit');
function rs_registration_form_submit($user_id)
{
$fields = rs_registration_form_fields();
$fields += rs_registration_form_fields_address();
foreach ($fields as $field => $settings) {
if (isset($_POST[$field]) && !empty($_POST[$field])) {
update_user_meta($user_id, $field, $_POST[$field]);
}
}
}
add_filter('register_form', 'rs_registration_form');
function rs_registration_form()
{
$fields = rs_registration_form_fields();
include '_rs_registration_form.php';
}
add_filter('register_form_address', 'rs_registration_form_address');
function rs_registration_form_address()
{
$fields = rs_registration_form_fields_address();
include '_rs_registration_form.php';
}
add_filter('woocommerce_edit_address_slugs', 'rs_fix_address_slugs');
function rs_fix_address_slugs($slugs)
{
$slugs['billing'] = 'billing';
$slugs['shipping'] = 'shipping';
return $slugs;
}
function rs_rejestracja_url()
{
return get_permalink(244);
}
function rs_logowanie_url()
{
return get_permalink(20);
}
function rs_show_checkout_progress_bar($step = '')
{
include '_checkout_progress_bar.php';
}
function rs_order_form_buttons()
{
include '_order_form_buttons.php';
}
add_filter('woocommerce_get_checkout_url', 'rs_get_checout_url');
function rs_get_checout_url($url) {
if (is_user_logged_in()) {
$url .= '#step1';
}
return $url;
}
include 'src/RS_Search.php';
I don't know WooCommerce, but I think the error results because of these lines:
$company_fields_required = (!empty($_POST['registration_type']) && 'company' === $_POST['registration_type']);
and
if (!$company_fields_required) {
unset($fields['billing_company']);
unset($fields['billing_nip']);
}
After you submitted your "private" form and the validation failed, your fields are loaded again. Could it now be, that in your $_POST variable the registration_type is somehow set to 'company'? You can test this if you just print_r your $_POST['registration_type'] at the beginning of the function. If that is not the case, then I'm pretty sure the bug happens in another function, because this makes sense to me so far.
EDIT: After taking another look on your code, I think none of the posted functions is responsible for the misbehaviour. The first function is only responsible to check if some of the posted values are missing and to say "hey, here is an error". There has to be another function which is responsible for the fields which later are displayed in your HTML. I think you need to find this function.
My comments on articles have a required Fivestar rating field called 'Stars' and I hid it with the following custom module (see: https://drupal.stackexchange.com/questions/90629/how-to-hide-rating-field-when-adding-comment-to-own-node):
function hiderating_form_alter(&$form, &$form_state, $form_id) {
global $user;
if ($form_id == "comment_node_article_form") {
if ($form['#node']->uid == $user->uid) {
unset($form['field_stars']);
}
}
}
As an administrator, I've permission to edit comments from other users. Suppose that a user commented on his own article. That means he didn't have to set the 'Stars' field, due to the code above. But when I try to edit that comment, I do have to select a value for the 'Stars'.
How can I prevent this? It's sufficient to check that the uid from the user who wrote the comment differs from the uid from the user who edits the comment. Finally, mark that the obligation to select stars when I leave a new comment myself must be preserved!
Edit: I tried the following code:
function hiderating_form_alter(&$form, &$form_state, $form_id) {
global $user;
$comment->uid = $form_state['values']['uid'];
if ($form_id == "comment_node_article_form") {
if ($comment->uid != $user->uid) {
unset($form['field_stars']);
}
}
}
Apparently, $form_state['values'] isn't well defined, because I get the following error:
"Notice: Undefined index: values in hiderating_form_alter()".
What's the correct code?
The code in the edit doesn't work, because $form_state['values'] isn't present before the submit. This is the correct code:
function hiderating_form_alter(&$form, &$form_state, $form_id) {
global $user;
if ($form_id == "comment_node_article_form") {
if ($form['uid']['#value'] != $user->uid AND $form['uid']['#value'] != 0) {
unset($form['field_stars']);
}
}
}
Using dpm($form), I discovered that $form['uid']['#value'] returns the uid from the user who wrote the comment. The value is only different from 0 if a comment is edited. When a user writes a new comment, the uid from the form is 0. That's why the AND in the second if is necessary.
I need to loop all Moodle registered users and get their usernames, in order to compare their values with the data I extracted from https://clip.unl.pt/sprs?lg=pt&year=2013&uo=97747&srv=rsu&p=1&tp=s&md=3&rs=8145&it=1030123459
The data that I want is the values inside Identificador.
The Requires:
require_once('../../config.php');
require_once('../../lib/accesslib.php');
require_once($CFG->libdir.'/adminlib.php');
require_once($CFG->dirroot.'/'.$CFG->admin.'/user/lib.php');
require_once('lib.php');
require_login();
if (!isset($SESSION->bulk_users)) {
$SESSION->bulk_users = array();
}
function buildURL($year, $period, $typeperiod,$course)
{
return 'https://clip.unl.pt/sprs?lg=pt&year='.$year.'&uo=97747&srv=rsu&p='.$period.'&tp='.$typeperiod.'&md=3&rs='.$course.'&it=1030123459';
}
function doRequest_with_FileGetContents($url)
{
return file_get_contents($url);
}
This is getting me the values inside Identificador tags
function processXML($xmlContent){
$xmlObj= new SimpleXMLElement($xmlContent);
foreach($xmlObj->unidade_curricular->inscritos->aluno as $aluno){
$result= $aluno->identificador."<br/>";
return $result;
}
This gets me all Moodle users
function getallUsers(){
global $DB;
$users= $DB->get_records('user');
foreach($users as $user){
$allusers= $user->username."<br/>";
return $allusers;
}
}
Test values:
$year='2013';
$period='1';
$typeperiod='s';
$course='8145';
I need to compare their usernames with the values inside Identificador. Only the matchable ( on Moodle) will be enrolled,in bulk, on Moodle course page, without any sort of form.
I've tried to build the idea, but not sure if i'm heading on the right track.
$url=buildURL($year,$period,$typeperiod,$course);
$content_b=doRequest_with_FileGetContents($url);
$results = array();
$allUsers= array();
$allUsers= getallUsers(); //getting all users on Moodle
$dataClip= array();
$dataClip= processXML($content_b); //getting all identificadores from xml file ?
$courseid= required_param('id', PARAM_INT);
$context= get_context_instance(CONTEXT_COURSE, $courseid);//Getting students who are already enrolled
$students= get_role_users(5,$context);
// comparing usernames(identificador values) between Clip and Moodle
if(is_array($dataClip)){ //eliminates warnings of Invalid Argument in foreach
foreach($dataClip as $newdata){
$duplicate=false;
if(is_array($allUsers)){
foreach($allUsers as $dataMoodle){
// if there is a match
if($newdata===$dataMoodle){
// if student not enrolled yet on moodle course page.
if(!$students){
$duplicate=false;
$temp_object= clone $dataMoodle;
$results= $temp_object;
/*
* some code from user_bulk.php
*/
foreach($results as $userid) {
if ($userid == -1) {
continue;
}
if (!isset($SESSION->bulk_users[$userid])) {
$SESSION->bulk_users[$userid] = $userid;
}
}
}
// if there is a match and student already enrolled on moodle course page
$duplicate=true;
continue;
}
//no match. student not on moodle
$duplicate= false;
continue;
}
}
}
}
//after processing redirects back to course page
$urltogo = new moodle_url('/course/view.php', array('id'=>$courseid));
redirect($urltogo);
And this doesn't work. I have developer mode On and no errors/warnings. And no enrolled students neither.
I have users' table users, where I store information like post_count and so on. I want to have ~50 badges and it is going to be even more than that in future.
So, I want to have a page where member of website could go and take the badge, not automatically give him it like in SO. And after he clicks a button called smth like "Take 'Made 10 posts' badge" the system checks if he has posted 10 posts and doesn't have this badge already, and if it's ok, give him the badge and insert into the new table the badge's id and user_id that member couldn't take it twice.
But I have so many badges, so do I really need to put so many if's to check for all badges? What would be your suggestion on this? How can I make it more optimal if it's even possible?
Thank you.
optimal would be IMHO the the following:
have an object for the user with functions that return user specific attributes/metrics that you initialise with the proper user id (you probably wanna make this a singleton/static for some elements...):
<?
class User {
public function initUser($id) {
/* initialise the user. maby load all metrics now, or if they
are intensive on demand when the functions are called.
you can cache them in a class variable*/
}
public function getPostCount() {
// return number of posts
}
public function getRegisterDate() {
// return register date
}
public function getNumberOfLogins() {
// return the number of logins the user has made over time
}
}
?>
have a badge object that is initialised with an id/key and loads dependencies from your database:
<?
class Badge {
protected $dependencies = array();
public function initBadge($id) {
$this->loadDependencies($id);
}
protected function loadDependencies() {
// load data from mysql and store it into dependencies like so:
$dependencies = array(array(
'value' => 300,
'type' => 'PostCount',
'compare => 'greater',
),...);
$this->dependencies = $dependencies;
}
public function getDependencies() {
return $this->dependencies;
}
}
?>
then you could have a class that controls the awarding of batches (you can also do it inside user...)
and checks dependencies and prints failed dependencies etc...
<?
class BadgeAwarder {
protected $badge = null;
protected $user = null;
public function awardBadge($userid,$badge) {
if(is_null($this->badge)) {
$this->badge = new Badge; // or something else for strange freaky badges, passed by $badge
}
$this->badge->initBadge($badge);
if(is_null($this->user)) {
$this->user = new User;
$this->user->initUser($userid);
}
$allowed = $this->checkDependencies();
if($allowed === true) {
// grant badge, print congratulations
} else if(is_array($failed)) {
// sorry, you failed tu full fill thef ollowing dependencies: print_r($failed);
} else {
echo "error?";
}
}
protected function checkDependencies() {
$failed = array();
foreach($this->badge->getDependencies() as $depdency) {
$value = call_user_func(array($this->badge, 'get'.$depdency['type']));
if(!$this->compare($value,$depdency['value'],$dependency['compare'])) {
$failed[] = $dependency;
}
}
if(count($failed) > 0) {
return $failed;
} else {
return true;
}
}
protected function compare($val1,$val2,$operator) {
if($operator == 'greater') {
return ($val1 > $val2);
}
}
}
?>
you can extend to this class if you have very custom batches that require weird calculations.
hope i brought you on the right track.
untested andp robably full of syntax errors.
welcome to the world of object oriented programming. still wanna do this?
Maybe throw the information into a table and check against that? If it's based on the number of posts, have fields for badge_name and post_count and check that way?