[
'tag' => function(){...},
'tag' => [MyShortcode::class, 'widget'],
'tag' => [
'callback' => [],
'tooltip' => '',
'config' => [],
]
]
@param BaseShortcode $pluginClass
@throws \Exception
507047
public function populate($pluginClass)
    {
        foreach ($pluginClass::shortcodes() as $tag => $item) {
            if ($tag) {
                if (is_callable($item)) {
                    $data = [
                        'app_id' => $this->checkApp($pluginClass),
                        'handler_class' => $pluginClass,
                        'tag' => $tag,
                        'tooltip' => "[$tag]",
                        'data' => null
                    ];
                } else {
                    if (!isset($item['callback'])) {
                        throw new \Exception("Callback is empty in shortcode $tag");
                    }
                    if (!is_callable($item['callback'])) {
                        throw new \Exception("Callback is not callable in shortcode $tag");
                    }
                    $data = [
                        'app_id' => $this->checkApp($pluginClass),
                        'handler_class' => $pluginClass,
                        'tag' => $tag,
                        'tooltip' => ArrayHelper::getValue($item, 'tooltip', "[$tag]"),
                        'data' => ArrayHelper::getValue($item, 'config'),
                    ];
                }
                $this->_data[] = $data;
            }
        };
    }
1242467
public function add(
        $tag,
        $controllerClass
    )
    {
        // Add shortcode support for widgets
        add_shortcode($tag, function ($tagAttributes, $tagContent = null) use ($tag, $controllerClass) {

            $attributes = array(
                'tag' => $tag,
                'parameters' => (is_array($tagAttributes) ? $tagAttributes : array()),
                'content' => $tagContent,
            );


            $this->plugin->when($controllerClass)
                ->needs('$attributes')
                ->give(function() use ($attributes){
                	return $attributes;
                });

	        ob_start();
	            $this->plugin->make($controllerClass);
            return ob_get_clean();
        });
    }
361534
public function registerComponent($className, $code = null, $plugin = null)
    {
        if (!$this->classMap) {
            $this->classMap = [];
        }

        if (!$this->codeMap) {
            $this->codeMap = [];
        }

        if (!$code) {
            $code = Str::getClassId($className);
        }

        if ($code == 'viewBag' && $className != 'Cms\Components\ViewBag') {
            throw new SystemException(sprintf(
                'The component code viewBag is reserved. Please use another code for the component class %s.',
                $className
            ));
        }

        $className = Str::normalizeClassName($className);
        $this->codeMap[$code] = $className;
        $this->classMap[$className] = $code;
        if ($plugin !== null) {
            $this->pluginMap[$className] = $plugin;
        }
    }
331466
public function init()
    {
        $extensions = [];

        if (empty($this->extensionClasses) && empty($this->userConfig)) {
            return;
        }

        foreach ($this->extensionClasses as $extensionClass) {
            if (!class_exists($extensionClass)) {
                throw new \InvalidArgumentException(sprintf(
                    'Extension class "%s" does not exist',
                    $extensionClass
                ));
            }

            $extension = new $extensionClass();

            if (!$extension instanceof ExtensionInterface) {
                throw new \InvalidArgumentException(sprintf(
                    // add any manually specified extensions
                    'Extension "%s" must implement the PhpBench\\Extension interface',
                    get_class($extension)
                ));
            }

            $extensions[] = $extension;

            $this->config = array_merge(
                $this->config,
                $extension->getDefaultConfig()
            );
        }

        $diff = array_diff(array_keys($this->userConfig), array_keys($this->config));

        if ($diff) {
            throw new \InvalidArgumentException(sprintf(
                'Unknown configuration keys: "%s". Permitted keys: "%s"',
                implode('", "', $diff), implode('", "', array_keys($this->config))
            ));
        }

        $this->config = array_merge(
            $this->config,
            $this->userConfig
        );

        foreach ($extensions as $extension) {
            $extension->load($this);
        }
    }
104375
protected function getPluginRowsHtml($pluginWrapperRows)
    {
        $html = '';
        foreach ($pluginWrapperRows as $pluginRow) {
            $html .= $this->getPluginRowHtml($pluginRow);
        }

        return $html;
    }
167569
function dynamic_init( array $plugin_info ) {
            $this->_logger->entrance();

            $this->parse_settings( $plugin_info );

            if ( is_admin() && $this->is_theme() && $this->is_premium() && ! $this->has_active_valid_license() ) {
                $this->add_ajax_action(
                    'delete_theme_update_data',
                    array( &$this, '_delete_theme_update_data_action' )
                );
            }

            if ( ! self::is_ajax() ) {
                if ( ! $this->is_addon() || $this->is_only_premium() ) {
                    add_action(
                        ( $this->_is_network_active && fs_is_network_admin() ? 'network_' : '' ) . 'admin_menu',
                        array( &$this, '_prepare_admin_menu' ),
                        WP_FS__LOWEST_PRIORITY
                    );
                }
            }

            if ( $this->should_stop_execution() ) {
                return;
            }

            if ( ! $this->is_registered() ) {
                if ( $this->is_anonymous() ) {
                    // If user skipped, no need to test connectivity.
                    $this->_has_api_connection = true;
                    $this->_is_on              = true;
                } else {
                    if ( ! $this->has_api_connectivity() ) {
                        if ( $this->_admin_notices->has_sticky( 'failed_connect_api_first' ) ||
                             $this->_admin_notices->has_sticky( 'failed_connect_api' )
                        ) {
                            if ( ! $this->_enable_anonymous || $this->is_premium() ) {
                                // If anonymous mode is disabled, add firewall admin-notice message.
                                add_action( 'admin_footer', array( 'Freemius', '_add_firewall_issues_javascript' ) );

                                $ajax_action_suffix = $this->_slug . ( $this->is_theme() ? ':theme' : '' );
                                add_action( "wp_ajax_fs_resolve_firewall_issues_{$ajax_action_suffix}", array(
                                    &$this,
                                    '_email_about_firewall_issue'
                                ) );

                                add_action( "wp_ajax_fs_retry_connectivity_test_{$ajax_action_suffix}", array(
                                    &$this,
                                    '_retry_connectivity_test'
                                ) );

                                /**
                                 * Currently the admin notice manager relies on the module's type and slug. The new AJAX actions manager uses module IDs, hence, consider to replace the if block above with the commented code below after adjusting the admin notices manager to work with module IDs.
                                 *
                                 * @author Vova Feldman (@svovaf)
                                 * @since  2.0.0
                                 */
                                /*$this->add_ajax_action( 'resolve_firewall_issues', array(
                                    &$this,
                                    '_email_about_firewall_issue'
                                ) );

                                $this->add_ajax_action( 'retry_connectivity_test', array(
                                    &$this,
                                    '_retry_connectivity_test'
                                ) );*/
                            }
                        }

                        return;
                    } else {
                        $this->_admin_notices->remove_sticky( array(
                            'failed_connect_api_first',
                            'failed_connect_api',
                        ) );

                        if ( $this->_anonymous_mode ) {
                            // Simulate anonymous mode.
                            $this->_is_anonymous = true;
                        }
                    }
                }
            }

            /**
             * This should be executed even if Freemius is off for the core module,
             * otherwise, the add-ons dialogbox won't work properly. This is esepcially
             * relevant when the developer decided to turn FS off for existing users.
             *
             * @author Vova Feldman (@svovaf)
             */
            if ( $this->is_user_in_admin() &&
                'plugin-information' === fs_request_get( 'tab', false ) &&
                 $this->should_use_freemius_updater_and_dialog() &&
                 (
                     ( $this->is_addon() && $this->get_slug() == fs_request_get( 'plugin', false ) ) ||
                     ( $this->has_addons() && $this->get_id() == fs_request_get( 'parent_plugin_id', false ) )
                 )
            ) {
                require_once WP_FS__DIR_INCLUDES . '/fs-plugin-info-dialog.php';

                new FS_Plugin_Info_Dialog( $this->is_addon() ? $this->get_parent_instance() : $this );
            }

            // Check if Freemius is on for the current plugin.
            // This MUST be executed after all the plugin variables has been loaded.
            if ( ! $this->is_registered() && ! $this->is_on() ) {
                return;
            }

            if ( $this->has_api_connectivity() ) {
                if ( self::is_cron() ) {
                    $this->hook_callback_to_sync_cron();
                } else if ( $this->is_user_in_admin() ) {
                    /**
                     * Schedule daily data sync cron if:
                     *
                     *  1. User opted-in (for tracking).
                     *  2. If skipped, but later upgraded (opted-in via upgrade).
                     *
                     * @author Vova Feldman (@svovaf)
                     * @since  1.1.7.3
                     *
                     */
                    if ( $this->is_registered() ) {
                        if ( ! $this->is_sync_cron_on() && $this->is_tracking_allowed() ) {
                            $this->schedule_sync_cron();
                        }
                    }

                    /**
                     * Check if requested for manual blocking background sync.
                     */
                    if ( fs_request_has( 'background_sync' ) ) {
                        $this->run_manual_sync();
                    }
                }
            }

            if ( $this->is_registered() ) {
                $this->hook_callback_to_install_sync();
            }

            if ( $this->is_addon() ) {
                if ( $this->is_parent_plugin_installed() ) {
                    // Link to parent FS.
                    $this->_parent = self::get_instance_by_id( $this->_plugin->parent_plugin_id );

                    // Get parent plugin reference.
                    $this->_parent_plugin = $this->_parent->get_plugin();
                }
            }

            if ( $this->is_user_in_admin() ) {
                if ( $this->is_addon() ) {
                    if ( ! $this->is_parent_plugin_installed() ) {
                        $parent_name = $this->get_option( $plugin_info, 'parent_name', null );

                        if ( isset( $plugin_info['parent'] ) ) {
                            $parent_name = $this->get_option( $plugin_info['parent'], 'name', null );
                        }

                        $this->_admin_notices->add(
                            ( ! empty( $parent_name ) ?
                                sprintf( $this->get_text_x_inline( '%s cannot run without %s.', 'addonX cannot run without pluginY', 'addon-x-cannot-run-without-y' ), $this->get_plugin_name(), $parent_name ) :
                                sprintf( $this->get_text_x_inline( '%s cannot run without the plugin.', 'addonX cannot run...', 'addon-x-cannot-run-without-parent' ), $this->get_plugin_name() )
                            ),
                            $this->get_text_x_inline( 'Oops', 'exclamation', 'oops' ) . '...',
                            'error'
                        );

                        return;
                    } else {
                        if ( $this->_parent->is_registered() && ! $this->is_registered() ) {
                            // If parent plugin activated, automatically install add-on for the user.
                            $this->_activate_addon_account( $this->_parent );
                        } else if ( ! $this->_parent->is_registered() && $this->is_registered() ) {
                            // If add-on activated and parent not, automatically install parent for the user.
                            $this->activate_parent_account( $this->_parent );
                        }

                        // @todo This should be only executed on activation. It should be migrated to register_activation_hook() together with other activation related logic.
                        if ( $this->is_premium() ) {
                            // Remove add-on download admin-notice.
                            $this->_parent->_admin_notices->remove_sticky( array(
                                'addon_plan_upgraded_' . $this->_slug,
                                'no_addon_license_' . $this->_slug,
                            ) );
                        }

//						$this->deactivate_premium_only_addon_without_license();
                    }
                }

                add_action( 'admin_init', array( &$this, '_admin_init_action' ) );

//				if ( $this->is_registered() ||
//				     $this->is_anonymous() ||
//				     $this->is_pending_activation()
//				) {
//					$this->_init_admin();
//				}
            }

            /**
             * Should be called outside `$this->is_user_in_admin()` scope
             * because the updater has some logic that needs to be executed
             * during AJAX calls.
             *
             * Currently we need to hook to the `http_request_host_is_external` filter.
             * In the future, there might be additional logic added.
             *
             * @author Vova Feldman
             * @since  1.2.1.6
             */
            if (
                $this->should_use_freemius_updater_and_dialog() &&
                (
                    $this->is_premium() ||
                    /**
                     * If not premium but the premium version is installed, also instantiate the updater so that the
                     * plugin information dialog of the premium version will have the information from the server.
                     *
                     * @author Leo Fajardo (@leorw)
                     * @since 2.2.3
                     */
                    ( file_exists( fs_normalize_path( WP_PLUGIN_DIR . '/' . $this->premium_plugin_basename() ) ) )
                ) &&
                $this->has_release_on_freemius()
            ) {
                FS_Plugin_Updater::instance( $this );
            }

            $this->do_action( 'initiated' );

            if ( $this->_storage->prev_is_premium !== $this->_plugin->is_premium ) {
                if ( isset( $this->_storage->prev_is_premium ) ) {
                    $this->apply_filters(
                        'after_code_type_change',
                        // New code type.
                        $this->_plugin->is_premium
                    );
                } else {
                    // Set for code type for the first time.
                    $this->_storage->prev_is_premium = $this->_plugin->is_premium;
                }
            }

            if ( ! $this->is_addon() ) {
                if ( $this->is_registered() ) {
                    // Fix for upgrade from versions < 1.0.9.
                    if ( ! isset( $this->_storage->activation_timestamp ) ) {
                        $this->_storage->activation_timestamp = WP_FS__SCRIPT_START_TIME;
                    }

                    $this->do_action( 'after_init_plugin_registered' );
                } else if ( $this->is_anonymous() ) {
                    $this->do_action( 'after_init_plugin_anonymous' );
                } else if ( $this->is_pending_activation() ) {
                    $this->do_action( 'after_init_plugin_pending_activations' );
                }
            } else {
                if ( $this->is_registered() ) {
                    $this->do_action( 'after_init_addon_registered' );
                } else if ( $this->is_anonymous() ) {
                    $this->do_action( 'after_init_addon_anonymous' );
                } else if ( $this->is_pending_activation() ) {
                    $this->do_action( 'after_init_addon_pending_activations' );
                }
            }
        }
939019
function classAnnotation() {
    $annotation_class_path = explode('\\', $this->component_data['plugin_type_data']['plugin_definition_annotation_name']);
    $annotation_class = array_pop($annotation_class_path);

    // Special case: annotation that's just the plugin ID.
    if (!empty($this->component_data['plugin_type_data']['annotation_id_only'])) {
      $annotation = ClassAnnotation::{$annotation_class}($this->component_data['plugin_name']);

      $annotation_lines = $annotation->render();

      return $annotation_lines;
    }

    $annotation_variables = $this->component_data['plugin_type_data']['plugin_properties'];

    $annotation_data = [];
    foreach ($annotation_variables as $annotation_variable => $annotation_variable_info) {
      if ($annotation_variable == 'id') {
        $annotation_data['id'] = $this->component_data['plugin_name'];
        continue;
      }

      // Hacky workaround for https://github.com/drupal-code-builder/drupal-code-builder/issues/97.
      if (isset($annotation_variable_info['type']) && $annotation_variable_info['type'] == '\Drupal\Core\Annotation\Translation') {
        // The annotation property value is translated.
        $annotation_data[$annotation_variable] = ClassAnnotation::Translation("TODO: replace this with a value");
        continue;
      }

      // It's a plain string.
      $annotation_data[$annotation_variable] = "TODO: replace this with a value";
    }

    $annotation = ClassAnnotation::{$annotation_class}($annotation_data);
    $annotation_lines = $annotation->render();

    return $annotation_lines;
  }
305660
public function setExtbaseConfiguration($pluginName, $controllerClass, $actionName, $extensionName = null)
    {
        // Validate the extension name
        if (!empty($extensionName)) {
            $extensionName = GeneralUtility::camelCaseToLowerCaseUnderscored(trim($extensionName));
            if (!in_array($extensionName, ExtensionManagementUtility::getLoadedExtensionListArray())) {
                throw new \RuntimeException(sprintf('Extension "%s" is not available', $extensionName), 1481645834);
            }
            $this->extbaseExtensionName = $extensionName;
        }

        // Validate the plugin name
        $pluginName = trim($pluginName);
        if (empty($pluginName)) {
            throw new \RuntimeException(sprintf('Invalid plugin name "%s"', $pluginName), 1481646376);
        }
        $this->extbasePlugin = $pluginName;

        // Validate the controller name
        $controllerClass = trim($controllerClass);
        if (empty($controllerClass)
            || !class_exists($controllerClass)
            || !($controllerReflection = new \ReflectionClass($controllerClass))->implementsInterface(
                ControllerInterface::class
            )
        ) {
            throw new \RuntimeException(sprintf('Invalid controller class "%s"', $controllerClass), 1481646376);
        }
        $this->extbaseControllerClass = $controllerClass;
        $this->extbaseController      = preg_replace('/Controller$/', '', $controllerReflection->getShortName());

        // Validate the controller action
        $actionName = trim($actionName);
        if (empty($actionName) || !is_callable([$this->extbaseControllerClass, $actionName.'Action'])) {
            throw new \RuntimeException(sprintf('Invalid controller action "%s"', $actionName), 1481646569);
        }
        $this->extbaseAction = $actionName;

        // Construct the controller argument request prefix
        $this->controllerArgumentRequestPrefix = 'tx_'.strtolower(str_replace('_', '', $this->extbaseExtensionName)).
                                                 '_'.strtolower($this->extbasePlugin);

        // Construct and set the controller request arguments
        $this->request->setControllerObjectName($this->extbaseControllerClass);
        $this->request->setControllerExtensionName($this->extbaseExtensionName);
        $this->request->setControllerName($this->extbaseController);
        $this->request->setControllerActionName($this->extbaseAction);
        $this->request->setPluginName($this->extbasePlugin);
        $this->request->setArgument(
            $this->controllerArgumentRequestPrefix,
            [
                'controller' => $this->extbaseController,
                'action'     => $this->extbaseAction,
            ]
        );

        // Determine the default controller settings
        /** @var ConfigurationManagerInterface $configurationManager */
        $configurationManager     = $this->objectManager->get(ConfigurationManagerInterface::class);
        $this->controllerSettings = $configurationManager->getConfiguration(
            ConfigurationManagerInterface::CONFIGURATION_TYPE_SETTINGS,
            GeneralUtility::underscoredToUpperCamelCase($this->extbaseExtensionName),
            $this->extbasePlugin
        );
    }
111440
function class_declaration() {
    if (isset($this->component_data['parent_plugin_class'])) {
      $this->component_data['parent_class_name'] = '\\' . $this->component_data['parent_plugin_class'];
    }
    elseif (isset($this->component_data['plugin_type_data']['base_class'])) {
      $this->component_data['parent_class_name'] = '\\' . $this->component_data['plugin_type_data']['base_class'];
    }

    // Set the DI interface if needed.
    $use_di_interface = FALSE;
    // We need the DI interface if this class injects services, unless a parent
    // class also does so.
    if (!empty($this->injectedServices)) {
      $use_di_interface = TRUE;

      if (isset($this->component_data['parent_plugin_class'])) {
        // TODO: violates DRY; we call this twice.
        $parent_construction_parameters = \DrupalCodeBuilder\Utility\CodeAnalysis\DependencyInjection::getInjectedParameters($this->component_data['parent_plugin_class'], 3);
        if (!empty($parent_construction_parameters)) {
          $use_di_interface = FALSE;
        }
      }
      elseif (!empty($this->component_data['plugin_type_data']['construction'])) {
        $use_di_interface = FALSE;
      }
    }

    if ($use_di_interface) {
      $this->component_data['interfaces'][] = '\Drupal\Core\Plugin\ContainerFactoryPluginInterface';
    }

    return parent::class_declaration();
  }
386865
protected function process_membership_tag($tagcontents) {
        global $DB;

        // Get plugin configs.
        $truncatecoursecodes = $this->get_config('truncatecoursecodes');
        $imscapitafix = $this->get_config('imscapitafix');

        $memberstally = 0;
        $membersuntally = 0;

        // In order to reduce the number of db queries required, group name/id associations are cached in this array.
        $groupids = array();

        $ship = new stdClass();

        if (preg_match('{<sourcedid>.*?<id>(.+?)</id>.*?</sourcedid>}is', $tagcontents, $matches)) {
            $ship->coursecode = ($truncatecoursecodes > 0)
                ? substr(trim($matches[1]), 0, intval($truncatecoursecodes))
                : trim($matches[1]);
            $ship->courseid = $DB->get_field('course', 'id', array('idnumber' => $ship->coursecode));
        }
        if ($ship->courseid && preg_match_all('{<member>(.*?)</member>}is', $tagcontents, $membermatches, PREG_SET_ORDER)) {
            $courseobj = new stdClass();
            $courseobj->id = $ship->courseid;

            foreach ($membermatches as $mmatch) {
                $member = new stdClass();
                $memberstoreobj = new stdClass();
                $matches = array();
                if (preg_match('{<sourcedid>.*?<id>(.+?)</id>.*?</sourcedid>}is', $mmatch[1], $matches)) {
                    $member->idnumber = trim($matches[1]);
                }

                $matches = array();
                if (preg_match('{<role\s+roletype=["\'](.+?)["\'].*?>}is', $mmatch[1], $matches)) {
                    // 01 means Student, 02 means Instructor, 3 means ContentDeveloper, and there are more besides.
                    $member->roletype = trim($matches[1]);
                } else if ($imscapitafix && preg_match('{<roletype>(.+?)</roletype>}is', $mmatch[1], $matches)) {
                    // The XML that comes out of Capita Student Records seems to contain a misinterpretation of
                    // the IMS specification! 01 means Student, 02 means Instructor, 3 means ContentDeveloper,
                    // and there are more besides.
                    $member->roletype = trim($matches[1]);
                }

                $matches = array();
                if (preg_match('{<role\b.*?<status>(.+?)</status>.*?</role>}is', $mmatch[1], $matches)) {
                    // 1 means active, 0 means inactive - treat this as enrol vs unenrol.
                    $member->status = trim($matches[1]);
                }

                $recstatus = ($this->get_recstatus($mmatch[1], 'role'));
                if ($recstatus == self::IMSENTERPRISE_DELETE) {
                    // See above - recstatus of 3 (==delete) is treated the same as status of 0.
                    $member->status = 0;
                }

                $timeframe = new stdClass();
                $timeframe->begin = 0;
                $timeframe->end = 0;
                $matches = array();
                if (preg_match('{<role\b.*?<timeframe>(.+?)</timeframe>.*?</role>}is', $mmatch[1], $matches)) {
                    $timeframe = $this->decode_timeframe($matches[1]);
                }

                $matches = array();
                if (preg_match('{<role\b.*?<extension>.*?<cohort>(.+?)</cohort>.*?</extension>.*?</role>}is',
                        $mmatch[1], $matches)) {
                    $member->groupname = trim($matches[1]);
                    // The actual processing (ensuring a group record exists, etc) occurs below, in the enrol-a-student clause.
                }

                // Add or remove this student or teacher to the course...
                $memberstoreobj->userid = $DB->get_field('user', 'id', array('idnumber' => $member->idnumber));
                $memberstoreobj->enrol = 'imsenterprise';
                $memberstoreobj->course = $ship->courseid;
                $memberstoreobj->time = time();
                $memberstoreobj->timemodified = time();
                if ($memberstoreobj->userid) {

                    // Decide the "real" role (i.e. the Moodle role) that this user should be assigned to.
                    // Zero means this roletype is supposed to be skipped.
                    $moodleroleid = $this->rolemappings[$member->roletype];
                    if (!$moodleroleid) {
                        $this->log_line("SKIPPING role $member->roletype for $memberstoreobj->userid "
                            ."($member->idnumber) in course $memberstoreobj->course");
                        continue;
                    }

                    if (intval($member->status) == 1) {
                        // Enrol the member.

                        $einstance = $DB->get_record('enrol',
                            array('courseid' => $courseobj->id, 'enrol' => $memberstoreobj->enrol));
                        if (empty($einstance)) {
                            // Only add an enrol instance to the course if non-existent.
                            $enrolid = $this->add_instance($courseobj);
                            $einstance = $DB->get_record('enrol', array('id' => $enrolid));
                        }

                        $this->enrol_user($einstance, $memberstoreobj->userid, $moodleroleid, $timeframe->begin, $timeframe->end);

                        $this->log_line("Enrolled user #$memberstoreobj->userid ($member->idnumber) "
                            ."to role $member->roletype in course $memberstoreobj->course");
                        $memberstally++;

                        // At this point we can also ensure the group membership is recorded if present.
                        if (isset($member->groupname)) {
                            // Create the group if it doesn't exist - either way, make sure we know the group ID.
                            if (isset($groupids[$member->groupname])) {
                                $member->groupid = $groupids[$member->groupname]; // Recall the group ID from cache if available.
                            } else {
                                $params = array('courseid' => $ship->courseid, 'name' => $member->groupname);
                                if ($groupid = $DB->get_field('groups', 'id', $params)) {
                                    $member->groupid = $groupid;
                                    $groupids[$member->groupname] = $groupid; // Store ID in cache.
                                } else {
                                    // Attempt to create the group.
                                    $group = new stdClass();
                                    $group->name = $member->groupname;
                                    $group->courseid = $ship->courseid;
                                    $group->timecreated = time();
                                    $group->timemodified = time();
                                    $groupid = $DB->insert_record('groups', $group);
                                    $this->log_line('Added a new group for this course: '.$group->name);
                                    $groupids[$member->groupname] = $groupid; // Store ID in cache.
                                    $member->groupid = $groupid;
                                    // Invalidate the course group data cache just in case.
                                    cache_helper::invalidate_by_definition('core', 'groupdata', array(), array($ship->courseid));
                                }
                            }
                            // Add the user-to-group association if it doesn't already exist.
                            if ($member->groupid) {
                                groups_add_member($member->groupid, $memberstoreobj->userid,
                                    'enrol_imsenterprise', $einstance->id);
                            }
                        }

                    } else if ($this->get_config('imsunenrol')) {
                        // Unenrol member.

                        $einstances = $DB->get_records('enrol',
                            array('enrol' => $memberstoreobj->enrol, 'courseid' => $courseobj->id));
                        foreach ($einstances as $einstance) {
                            // Unenrol the user from all imsenterprise enrolment instances.
                            $this->unenrol_user($einstance, $memberstoreobj->userid);
                        }

                        $membersuntally++;
                        $this->log_line("Unenrolled $member->idnumber from role $moodleroleid in course");
                    }

                }
            }
            $this->log_line("Added $memberstally users to course $ship->coursecode");
            if ($membersuntally > 0) {
                $this->log_line("Removed $membersuntally users from course $ship->coursecode");
            }
        }
    }
10953
def class_rules
      [
        Rule.new(:error, 4..6, "Description Markdown", "Above your class you need documentation that covers the scope, and the usage of your plugin.", proc do |json|
          json[:body_md] && json[:body_md].empty?
        end),
        Rule.new(:warning, 30, "Tags", "This plugin does not include `@tags tag1, tag2` and thus will be harder to find in search.", proc do |json|
          json[:tags] && json[:tags].empty?
        end),
        Rule.new(:warning, 29, "References", "Ideally, you have a reference implementation of your plugin that you can show to people, add `@see org/repo` to have the site auto link it.", proc do |json|
          json[:see] && json[:see].empty?
        end),
        Rule.new(:error, 8..27, "Examples", "You should include some examples of common use-cases for your plugin.", proc do |json|
          json[:example_code] && json[:example_code].empty?
        end)
      ]
    end
125993
protected function plugin_extend_coursemodule_standard_elements() {
        $callbacks = get_plugins_with_function('coursemodule_standard_elements', 'lib.php');
        foreach ($callbacks as $type => $plugins) {
            foreach ($plugins as $plugin => $pluginfunction) {
                // We have exposed all the important properties with public getters - and the callback can manipulate the mform
                // directly.
                $pluginfunction($this, $this->_form);
            }
        }
    }
440356
protected function analysePluginTypeBaseClass(&$data) {
    // Work over each plugin of this type, finding a suitable candidate for
    // base class with each one.
    $potential_base_classes = [];

    $service = \Drupal::service($data['service_id']);
    $definitions = $service->getDefinitions();

    // Keep track of the classes we've seen, so we can skip derivative plugins
    // that have the same class.
    $plugin_classes = [];

    foreach ($definitions as $plugin_id => $definition) {
      if (is_array($definition)) {
        // We can't work with plugins that don't define a class: skip the whole
        // plugin type.
        if (empty($definition['class'])) {
          return;
        }

        $plugin_class = $definition['class'];
      }
      elseif ($definition instanceof Drupal\Component\Plugin\Definition\PluginDefinition) {
        $plugin_class = $definition->getClass();
      }
      else {
        // Skip the whole plugin type: no idea how to handle it.
        return;
      }

      // Skip classes we've seen already.
      if (isset($plugin_classes[$plugin_class])) {
        continue;
      }
      $plugin_classes[$plugin_class] = TRUE;

      // Skip any class that we can't attempt to load without a fatal. This will
      // typically happen if the plugin is meant for use with another module,
      // and inherits from a base class that doesn't exist in the current
      // codebase.
      if (!$this->codeAnalyser->classIsUsable($plugin_class)) {
        $data['broken_plugins'][$plugin_id] = 'crashes';

        continue;
      }

      // Babysit modules that have a broken plugin class. A number of things can
      // go wrong, including the namespace being incorrect for the file
      // location, preventing the class from being autoloaded.
      try {
        if (!class_exists($plugin_class)) {
          $data['broken_plugins'][$plugin_id] = 'no class';

          // Skip just this plugin.
          continue;
        }
      }
      catch (\Throwable $ex) {
        $data['broken_plugins'][$plugin_id] = 'exception';

        continue;
      }

      $plugin_component_namespace = $this->getClassComponentNamespace($plugin_class);

      // Get the full ancestry of the plugin's class.
      // Build a lineage array, from youngest to oldest, i.e. closest parents
      // first.
      $lineage = [];

      $plugin_class_reflection = new \ReflectionClass($plugin_class);

      $class_reflection = $plugin_class_reflection;
      while ($class_reflection = $class_reflection->getParentClass()) {
        $lineage[] = $class_reflection->getName();
      }

      // Try to get the nearest ancestor in the same namespace whose class
      // name ends in 'Base'.
      foreach ($lineage as $ancestor_class) {
        $parent_class_component_namespace = $this->getClassComponentNamespace($ancestor_class);
        if ($parent_class_component_namespace != $data['service_component_namespace']) {
          // No longer in the plugin manager's component: stop looking.
          break;
        }

        if (substr($ancestor_class, - strlen('Base')) == 'Base') {
          $potential_base_classes[] = $ancestor_class;

          // Done with this plugin.
          goto next_plugin;
        }
      } // foreach lineage

      // If we failed to find a class called FooBase in the same component.
      // Ue the youngest ancestor which is in the same component as the
      // plugin manager.
      // Getting the youngest ancestor accounts for modules that define
      // multiple plugin types and have a common base class for all of them
      // (e.g. Views), but unfortunately sometimes gets us a base class that
      // is too specialized in modules that provide several base classes,
      // for example a general base class and a more specific one. The next
      // step addresses that.
      foreach ($lineage as $ancestor_class) {
        $parent_class_component_namespace = $this->getClassComponentNamespace($ancestor_class);

        if ($parent_class_component_namespace == $data['service_component_namespace']) {
          // We've found an ancestor class in the plugin's hierarchy which is
          // in the same namespace as the plugin manager service. Assume it's
          // a good base class, and move on to the next plugin type.
          // TODO: don't take this if the class itself is a plugin.
          $potential_base_classes[] = $ancestor_class;

          // Done with this plugin.
          goto next_plugin;
        }
      } // foreach lineage

      // End of the loop for the current plugin.
      next_plugin:
        // This is a noop line to stop the PHP linting in my IDE from
        // complaining that this label has no statements, grrr...
        assert(true);
    } // foreach $definitions

    // If we found nothing, we're done.
    if (empty($potential_base_classes)) {
      return;
    }

    // We now have an array of several base classes, potentially as many as one
    // for each plugin.
    // Collapse this down to unique values.
    $potential_base_classes_unique = array_unique($potential_base_classes);

    // If that leaves us with only one base class, return that.
    if (count($potential_base_classes_unique) == 1) {
      return reset($potential_base_classes_unique);
    }

    // If we have more than one base class, it's most likely because there are
    // specialized base classes in addition to the main one (e.g. if our plugins
    // were animals, AnimalBase and FelineBase). Now organize the classes by
    // ancestry, and take the oldest one.

    // Try to form an ancestry chain of the potential base classes.
    // Start by partitioning the set of base classes into sets of classes that
    // are related by ancestry, so we can pick the largest set, and then sort
    // it by ancestry.
    $ancestry_sets = [];
    $current_set = [];
    foreach ($potential_base_classes_unique as $class) {
      // If the current set is empty, then the class goes in as it's trivially
      // related to itself.
      if (empty($current_set)) {
        $current_set[] = $class;
        continue;
      }

      // Get a sample class from the set. It doesn't matter which.
      $other_class = reset($current_set);

      if (is_subclass_of($class, $other_class) || is_subclass_of($other_class, $class)) {
        // If the current class is related to a class in the current set, add
        // it to the set.
        $current_set[] = $class;
      }
      else {
        // The current class is not related. Stash the current set, as we are
        // done with it, and start a new one.
        $ancestry_sets[] = $current_set;

        $current_set = [];
        $current_set[] = $class;
      }
    }
    // Once we're done with the loop, our current set remains: put it into the
    // partition list.
    $ancestry_sets[] = $current_set;

    // If there is more than one partition, take the largest.
    if (count($ancestry_sets) > 1) {
      $ancestry_sets_counts = [];
      foreach ($ancestry_sets as $index => $set) {
        $ancestry_sets_counts[$index] = count($set);
      }

      // Find the index of the largest set.
      // (If more than one are joint largest, it doesn't matter which one we
      // take as we have no way of choosing anyway.)
      // (Also note that in core, the only plugin type that produces more than
      // one set is archiver, which is hardly going to be used much.)
      $max_count = max($ancestry_sets_counts);
      $max_index = array_search($max_count, $ancestry_sets_counts);

      $set = $ancestry_sets[$max_index];
    }
    else {
      // There is only one set; take that.
      $set = $ancestry_sets[0];
    }

    // Sort the array of classes by parentage, youngest to oldest.
    usort($set, function($a, $b) {
      if (is_subclass_of($a, $b)) {
        return -1;
      }
      else {
        return 1;
      }
      // We filtered the array for uniqueness, so the 0 case won't ever happen,
      // and we partitioned the array, so we know the classes are always
      // related.
    });

    // Return the oldest parent, as this is the most generic of the found base
    // classes.
    $base_class = end($set);

    return $base_class;
  }
10345
function hook_code($hook_short_name, $parameters_string) {
    $parameters = explode(', ', $parameters_string);
    $parameters_doc_lines = array();
    foreach ($parameters as $parameter) {
      $parameters_doc_lines[] = " * @param $parameter\n" .
                                " *   TODO: document this parameter.";
    }
    if (!empty($parameters_doc_lines)) {
      $parameters_doc = " *\n" . implode("\n", $parameters_doc_lines);
    }

    return <<<EOT
/**
 * TODO: write summary line.
 *
 * TODO: longer description.
$parameters_doc
 *
 * @return
 *   TODO: Document return value if there is one.
 */
function hook_$hook_short_name($parameters_string) {
  // TODO: write sample code.
}

EOT;
  }
1013516
protected function callClassBasedExtension($callback, $parameters)
    {
        list($class, $method) = explode('@', $callback);

        return call_user_func_array([$class, $method], $parameters);
    }
942919
public List getPlugins(final Class pluginClass) {
        synchronized (pluginMap) {
            List pluginList = new ArrayList(pluginMap.size());
            Iterator iter = pluginMap.values().iterator();

            while (iter.hasNext()) {
                Object plugin = iter.next();

                if (pluginClass.isInstance(plugin)) {
                    pluginList.add(plugin);
                }
            }
            return pluginList;
        }
    }
339513
public function ShortcodeForm()
    {
        Config::inst()->update('SSViewer', 'theme_enabled', false);
        $classes = Shortcodable::get_shortcodable_classes_fordropdown();
        $classname = $this->shortcodableclass;

        if ($this->isnew) {
            $headingText = _t('Shortcodable.EDITSHORTCODE', 'Edit Shortcode');
        } else {
            $headingText =  sprintf(
                _t('Shortcodable.EDITSHORTCODE', 'Edit %s Shortcode'),
                singleton($this->shortcodableclass)->singular_name()
            );
        }

        // essential fields
        $fields = FieldList::create(array(
            CompositeField::create(
                LiteralField::create(
                    'Heading',
                    sprintf('<h3 class="htmleditorfield-shortcodeform-heading insert">%s</h3>', $headingText)
                )
            )->addExtraClass('CompositeField composite cms-content-header nolabel'),
            LiteralField::create('shortcodablefields', '<div class="ss-shortcodable content">'),
            DropdownField::create('ShortcodeType', _t('Shortcodable.SHORTCODETYPE', 'Shortcode type'), $classes, $classname)
                ->setHasEmptyDefault(true)
                ->addExtraClass('shortcode-type')
        ));

        // attribute and object id fields
        if ($classname && class_exists($classname)) {
            $class = singleton($classname);
            if (is_subclass_of($class, 'DataObject')) {
                if (singleton($classname)->hasMethod('getShortcodableRecords')) {
                    $dataObjectSource = singleton($classname)->getShortcodableRecords();
                } else {
                    $dataObjectSource = $classname::get()->map()->toArray();
                }
                $fields->push(
                    DropdownField::create('id', $class->singular_name(), $dataObjectSource)
                        ->setHasEmptyDefault(true)
                );
            }
            if (singleton($classname)->hasMethod('getShortcodeFields')) {
                if ($attrFields = singleton($classname)->getShortcodeFields()) {
                    $fields->push(
                        CompositeField::create($attrFields)
                            ->addExtraClass('attributes-composite')
                            ->setName('AttributesCompositeField')
                    );
                }
            }
        }

        // actions
        $actions = FieldList::create(array(
            FormAction::create('insert', _t('Shortcodable.BUTTONINSERTSHORTCODE', 'Insert shortcode'))
                ->addExtraClass('ss-ui-action-constructive')
                ->setAttribute('data-icon', 'accept')
                ->setUseButtonTag(true)
        ));

        // form
        $form = Form::create($this, 'ShortcodeForm', $fields, $actions)
            ->loadDataFrom($this)
            ->addExtraClass('htmleditorfield-form htmleditorfield-shortcodable cms-dialog-content');

        $this->extend('updateShortcodeForm', $form);

        $fields->push(LiteralField::create('shortcodablefieldsend', '</div>'));

        if ($data = $this->getShortcodeData()) {
            $form->loadDataFrom($data['atts']);

            // special treatment for setting value of UploadFields
            foreach ($form->Fields()->dataFields() as $field) {
                if (is_a($field, 'UploadField') && isset($data['atts'][$field->getName()])) {
                    $field->setValue(array('Files' => explode(',', $data['atts'][$field->getName()])));
                }
            }
        }

        return $form;
    }