HEX
Server: Apache/2.4.25
System: Linux ion14 4.9.0-8-amd64 #1 SMP Debian 4.9.144-3.1 (2019-02-19) x86_64
User: (10087)
PHP: 7.4.30
Disabled: pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare,system, exec, shell_exec, passthru, popen, proc_open
Upload Files
File: /home/www/web115/wordpress/wp-content/plugins/digimember/application/model/data/page_product.php
<?php

class digimember_PageProductData extends ncore_BaseData
{
    private $postTypes = array();

    private $IGNORED_POST_TYPES = array( 'attachment', 'revision', 'nav_menu_item' );

    public function __construct( ncore_ApiCore $api, $file='', $dir='' )
    {
        parent::__construct( $api, $file, $dir );
    }

    public function isProtected( $page_id )
    {
        $where = array( 'post_id' => $page_id, 'is_active' => 'Y' );

        $all = $this->getAll( $where );

        $this->api->load->model( 'data/product' );

        foreach ($all as $one) {
            $product = $this->api->product_data->get( $one->product_id );
            $is_valid = $product && !$product->deleted && $product->type == 'membership';
            if ($is_valid) {
                return true;
            }
        }


        return false;
    }

    public function getCurrent( $post_type='page')
    {
        $page_id = ncore_getCurrentPageId();

        $candidates = $this->getForPage($post_type, $page_id, $active_only=true );

        if (!$candidates)
        {
            return false;
        }
        elseif (count($candidates)==1)
        {
            $page_product = $candidates[0];

            $this->_storeCurrentPageProduct( $page_product );

            return $page_product;
        }
        else
        {
            $product_id = $this->_getCurrentPageProduct( $page_id );

            $found_products = ncore_elementsWithKey( $candidates, 'product_id', $product_id );
            if ($found_products)
            {
                $found_entry = ncore_findByKey( $candidates, 'product_id', $product_id );
                if ($found_entry)
                {
                    $page_product = $found_entry;
                }
                else
                {
                    $page_product = $found_products[0];
                }
            }
            else
            {
                $page_product = $candidates[0];
            }

            $this->_storeCurrentPageProduct( $page_product );

            return $page_product;
        }
    }

    private function _storeCurrentPageProduct( $page_product )
    {
        $product_id = $page_product->product_id;
    }

    private function _getCurrentPageProduct( $page_id )
    {
        $product_id = false;

        return $product_id;
    }

    public function getForPage( $post_type, $page_id, $active_only=false  )
    {
        $page_products =& $this->pageCache[ $post_type ][ $page_id ];
        if (!isset($page_products))
        {
            $where = array(
                'post_id' => $page_id,
                'post_type' => $post_type,
            );

            $limit = false;

            $order_by = 'id ASC';

            $page_products = $this->getAll( $where, $limit, $order_by );
        }

        if ($active_only)
        {
            $this->api->load->helper( 'array' );
            return ncore_elementsWithKey( $page_products, 'is_active', 'Y' );
        }
        else
        {
            return $page_products;
        }

    }

    public function getAll( $where=array(), $limit=false, $order_by='' )
    {
        $all = parent::getAll( $where, $limit, $order_by );

        $this->api->load->model( 'data/product' );
        $products = $this->api->product_data->options( 'all' );

        $modified = false;

        foreach ($all as $index => $one)
        {
            $have_product = isset( $products[ $one->product_id ] );
            if (!$have_product) {
                unset( $all[ $index ] );
                $modified = true;
            }
        }

        if ($modified) {
            $all = array_values( $all );
        }

        return $all;
    }

    /**
     * @param $product_id
     * @return array
     */
    public function getLectureMenu( $product_id )
    {
        $where = array(
            'product_id' => $product_id,
            'is_active'  => 'Y',
        );

        $limit = false;
        $order_by = 'position ASC, id ASC';
        $page_products = $this->getAll( $where, $limit, $order_by );
        $post = get_post();
        $selected_post_id = $post
            ? $post->ID
            : false;

        /** @var digimember_AccessLogic $accessLogic */
        $accessLogic = $this->api->load->model('logic/access');

        $modified = false;
        foreach ($page_products as $index => $one) {
            if (get_post_status($one->post_id) != 'publish' || $accessLogic->accessType($one->post_type, $one->post_id)[0] == DIGI_ACCESS_NONE) {
                unset($page_products[$index]);
                $modified = true;
            }
        }
        if ($modified) {
            $page_products = array_values($page_products);
        }

        return $this->_getLectureMenu( $page_products, $product_id, $selected_post_id );
    }

    public function getPostsForProduct( $product_id, $post_type, $accessOnly = true)
    {
        $api = $this->api;
        $api->load->helper( 'array' );

        $where = array(
            'product_id' => $product_id,
            'is_active'  => 'Y',
        );

        $limit = false;
        $order_by = 'position ASC, unlock_day ASC, id ASC';

        $page_products = $this->getAll( $where, $limit, $order_by );

        $pages = $this->getAllPosts( $post_type, $accessOnly);

        $options = array();

        $numbers = array( 0 );

        $list_stack = array();

        $list_stack[] =& $options;

        foreach ($page_products as $page_product)
        {
            $page = ncore_findByKey( $pages, 'ID', $page_product->post_id );
            if (!$page || $page->post_type != $page_product->post_type) {
                continue;
            }

            $option = array();

            $parent_index = $page->post_parent
                ? ncore_indexOfByKey( $options, 'parent_id', $page->post_parent )
                : false;

            $option['post_id']      = $page->ID;
            $option['title']        = $page->post_title;
            $option['parent_id']    = $page->post_parent;
            $option['parent_index'] = $parent_index;

            $page_depth = 1+intval($page_product->level);
            $cur_depth  = count($numbers);

            $must_inc_depth = $page_depth > $cur_depth;
            $must_dec_depth = $page_depth < $cur_depth;

            $is_same_level =  !$must_inc_depth && !$must_dec_depth;

            if ($must_inc_depth) {
                $numbers[] = 1;
            }
            if ($must_dec_depth)
            {
                while ($page_depth < count($numbers))
                {
                    array_pop( $numbers );
                }

                $count = count($numbers);
                $numbers[ $count-1 ]++;
            }

            if ($is_same_level) {
                $count = count($numbers);
                $numbers[ $count-1 ]++;
            }

            $number_as_text = implode( '.', $numbers );
            $must_update_number = $number_as_text != $page_product->lecture_number;
            if ($must_update_number) {
                $data = array( 'lecture_number' => $number_as_text );
                $this->update( $page_product, $data );
            }

            $option['is_active']  = $page_product->is_active;
            $option['unlock_day'] = intval($page_product->unlock_day);
            $option['level']      = count($numbers) - 1;
            $option['number']     = $this->renderLectureNumber( $numbers );
            $option['position']   = $page_product->position;

            $option[ 'subpages' ] = array();

            if ($is_same_level)
            {
                $count = count( $list_stack );
                $list = &$list_stack[ $count-1 ];
                $list[] = $option;
            }
            elseif ($must_inc_depth)
            {
                $count     = count( $list_stack );
                $last_list = &$list_stack[ $count-1 ];

                $count     = count( $last_list );
                $last_elem = &$last_list[ $count-1 ];;

                $list = &$last_elem[ 'subpages' ];
                $list_stack[] = &$list;
                $list[] = $option;
            }
            else
            {
                array_pop( $list_stack );
                $count = count( $list_stack );
                $list = &$list_stack[ $count-1 ];
                $list[] = $option;
            }
        }

        $sanitized_options = array();

        $this->_sanitizeProductPostList( $sanitized_options, $options );

        return $sanitized_options;

    }

    public function storePostsForProduct( $product_id, $post_type, $post_recs )
    {
        $api = $this->api;
        $api->load->helper( 'array' );

        $where = array(
            'post_type' => $post_type,
            'product_id' => $product_id,
        );

        $all_entries = $this->getAll( $where );

        $position = 1;

        $numbers = array();

        foreach ($post_recs as $rec)
        {
            $one_post_id     = (int) ncore_retrieve( $rec, array( 'post_id', 'id' ) );
            $one_unlock_day  = (int) ncore_retrieve( $rec, 'unlock_day' );
            $level           = (int) ncore_retrieve( $rec, 'level', 0 );

            if (!$one_post_id)
            {
                continue;
            }

            $index = ncore_indexOfByKey( $all_entries, 'post_id', $one_post_id );

            $have_entry = $index !== false;

            $count = count($numbers);
            $must_add_level = $count <= $level;
            $must_rem_level = max( 0, $count - ($level+1) );

            if ($must_add_level) {
                $numbers[] = 1;
            }
            else
            {
                while ($must_rem_level-->0) {
                    array_pop($numbers);
                }

                $numbers[count($numbers)-1]++;
            }
            $number_as_text = implode( '.', $numbers );

            if ($have_entry)
            {
                $entry = $all_entries[ $index ];

                $data = array(
                    'is_active'      => 'Y',
                    'unlock_day'     => $one_unlock_day,
                    'lecture_number' => $number_as_text,
                    'level'          => $level,
                    'position'       => $position++,
                );

                $this->update( $entry->id, $data );

                unset( $all_entries[ $index ] );
            }
            else
            {
                $data = array(
                    'is_active'      => 'Y',
                    'unlock_day'     => $one_unlock_day,
                    'lecture_number' => $number_as_text,
                    'post_id'        => $one_post_id,
                    'post_type'      => $post_type,
                    'product_id'     => $product_id,
                    'level'          => $level,
                    'position'       => $position++,
                );

                $this->create( $data );

            }

        }

        foreach ($all_entries as $entry)
        {
            $this->delete( $entry->id );
        }
    }

    public function getAllPages($accessOnly = true)
    {
        return $this->getAllPosts( 'page', $accessOnly );
    }

    public function getAllPosts( $post_type, $accessOnly = true )
    {
        if ($accessOnly) {
            $posts = ncore_getPages( $post_type );
            return $posts;
        }
        else {
            $posts = ncore_getAllPages( $post_type );
            return $posts;
        }

    }

    public function savePageProduct( $rec )
    {
        $post_id    = ncore_retrieve( $rec, 'post_id' );
        $post_type  = ncore_retrieve( $rec, 'post_type' );
        $product_id = ncore_retrieve( $rec, 'product_id' );
        $unlock_day = ncore_retrieve( $rec, 'unlock_day' );
        $is_active  = ncore_retrieve( $rec, 'is_active' );

        $where = array(
            'post_id'    => $post_id,
            'post_type'  => $post_type,
            'product_id' => $product_id,
        );

        $data = array();
        $data['unlock_day'] = $unlock_day;
        $data['is_active'] = ($is_active?'Y':'N');

        $all = $this->getAll( $where );

        $is_first = true;
        foreach ($all as $one)
        {
            if ($is_first)
            {
                $is_first = false;
            }
            else
            {
                $this->delete( $one->id );
            }
        }

        $have_entry = (bool) $all;

        if ($have_entry)
        {
            $id = $all[0]->id;
            $this->update( $id, $data );
        }
        else
        {
            $data = array_merge( $data, $where );
            $this->create( $data );
        }

        /** @var ncore_EventSubscriberLogic $model */
        $model = $this->api->load->model( 'logic/event_subscriber' );
        $model->call( 'dm_page_product_changed', $post_id );
    }

    public function postTypes()
    {
        $postTypesChanged = false;
        if (count($this->postTypes) < 1) {
            $this->postTypes = get_post_types();
        }
        else {
            $newPostTypes = get_post_types();
            $diff = array_diff($newPostTypes, $this->postTypes);
            if ( is_array($diff) && count($diff) > 0 ) {
                $this->postTypes = $newPostTypes;
                $postTypesChanged = true;
            }
        }
        return array_keys( $this->postTypeOptions($postTypesChanged) );
    }

    public function postTypeOptions($forceRebuild = false)
    {
        static $options;
        if (!isset($options) || $forceRebuild) {
            $options = array(
                'page' => _digi('Pages'),
                'post' => _digi('Posts'),
            );

            $post_types_to_skip = $this->IGNORED_POST_TYPES;
            $post_types_to_skip[] = 'page';
            $post_types_to_skip[] = 'post';

            foreach ($this->postTypes as $type => $label)
            {
                $is_skipped = in_array( $type, $post_types_to_skip );
                if (!$is_skipped) {
                    $options[ $type ] = ncore_camelCase( $label, ncore_wordGlue() );
                }
            }
        }

        return $options;
    }


    public function isPostTypeHandled( $post_type )
    {
        static $cache;

        $handled =& $cache[ $post_type ];

        if (isset($handled)) {
            return $handled;
        }
        $handled = in_array( $post_type, $this->postTypes() );

        return $handled;
    }

    public function setupChecklistDone()
    {
        $this->api->load->helper( 'array' );

        $model = $this->api->load->model( 'data/product' );
        $where = array( 'published !=' => null );
        $product_objs = $model->getAll( $where );

        $published_product_ids = array_keys( ncore_listToArray( $product_objs, 'id', 'name' ) );

        $where = array( 'is_active' => 'Y' );
        $all = $this->getAll( $where );
        foreach ($all as $one)
        {
            $is_active = in_array( $one->product_id, $published_product_ids );
            if ($is_active)
            {
                return true;
            }
        }

        return false;
    }


    //
    // protected section
    //
    protected function sqlBaseTableName()
    {
        return 'page_product';
    }

    protected function sqlTableMeta()
    {
       $columns = array(
        'post_id'         => 'id',
        'post_type'       => 'string[80]',
        'product_id'      => 'id',
        'is_active'       => 'yes_no_bit',
        'unlock_day'      => 'int',
        'position'        => 'int',
        'level'           => 'int',
        'lecture_number'  => 'string[15]',
       );

       $indexes = array( 'post_id', 'product_id' );

       $meta = array(
        'columns' => $columns,
        'indexes' => $indexes,
       );

       return $meta;
    }

    protected function defaultOrder()
    {
        return 'position ASC, product_id ASC, id ASC';
    }

    protected function buildObject( $object )
    {
        parent::buildObject( $object );

        if (!$object->unlock_day)
        {
            $object->unlock_day = '';
        }
    }

    protected function defaultValues()
    {
        $values = parent::defaultValues();

        $values['is_active'] = 'Y';

        return $values;
    }

    //
    // private section
    //
    private $pageCache = array();

    private function _sortProductPostList( &$options )
    {
        $sort_unlock_day = array();
        $sort_position   = array();
        $sort_page_name  = array();

        foreach ($options as $index => $one)
        {
            if (empty($one[ 'title']))
            {
                $sort_page_name[]  = 'aaaaa';
                $sort_unlock_day[] = 0;
                $sort_position[]   = 0;
            }
            else
            {
                $sort_page_name[]  = strtolower( $one[ 'title'] );
                $sort_unlock_day[] = $one[ 'unlock_day' ];
                $sort_position[]   = $one[ 'position' ];
            }
        }

        array_multisort( $sort_position, $sort_unlock_day, $sort_page_name, $options );
    }

    private function _sanitizeProductPostList( &$sanitized_options, $options )
    {
        if (empty($options)) {
            return;
        }

        $this->_sortProductPostList( $options );

        foreach ($options as $one)
        {
            $sublist = ncore_retrieveAndUnset( $one, 'subpages', array() );

            $sanitized_options[] = $one;

            $this->_sanitizeProductPostList( $sanitized_options, $sublist );
        }
    }

    private function renderLectureNumber( $numbers_array_or_text )
    {
        $numbers = is_string($numbers_array_or_text)
                 ? explode( ',', str_replace( '.', ',', $numbers_array_or_text ) )
                 : $numbers_array_or_text;

        return implode( '.', $numbers );
    }

    /**
     * Intern function to generate a menu structure of pages/post that is associated to a product, calls private function buildTree(array &$elements, $product_id, $selected_post_id, $parentId = 0)
     * @param $page_products
     * @param int $product_id
     * @param int $selected_post_id
     * @return array
     */
    private function _getLectureMenu($page_products, $product_id, $selected_post_id)
    {
        foreach ($page_products as $i => $product) {
            $count = $i;
            do {
                $prev = empty( $page_products[ $count - 1 ] )
                    ? false
                    : $page_products[ $count - 1 ];

                if ($prev && $prev->level < $product->level) {
                    $product->parent_id = $prev->id;
                    break;
                }
                else {
                    $product->parent_id = false;
                }
                $count--;
            } while($prev);
        }
        $productsById = [];
        foreach ($page_products as $value) {
            $productsById[$value->id] = $value;
        }

        return $this->_buildLectureMenuTree($productsById, $product_id, $selected_post_id,0);
    }

    /**
     * Function that recursively builds the correct menu structure of Pages/Post that are associated to a product. Original idea behind that structure is a non-balanced but sorted"tree"
     * @param array $elements
     * @param int $product_id
     * @param int $selected_post_id
     * @param int $parentId
     * @return array
     */
    private function _buildLectureMenuTree(array &$elements, $product_id, $selected_post_id, $parentId = 0) {

        $branch = array();

        foreach ($elements as $element) {

            if ($element->parent_id == $parentId) {
                $children = $this->_buildLectureMenuTree($elements, $product_id, $selected_post_id, $element->id);

                if ($children) {
                    $element->children = $children;
                }

                $post_list = ncore_getPages($element->post_type);

                $page_titles = [];
                foreach ($post_list as $single_page) {
                    $page_titles[$single_page->ID] = $single_page->post_title;
                }
                $title = ncore_retrieve($page_titles, $element->post_id);
                $url = ncore_addArgs(get_permalink($element->post_id), ['digimember_product_id' => $product_id]);
                $is_selected = $selected_post_id == $element->post_id;

                $menu_entry = [
                    'title' => $title,
                    'url' => $url,
                    'level' => $element->level,
                    'product_id' => $product_id,
                    'is_selected' => $is_selected,
                    'sub_menu' => $children,
                ];

                $zaehler=count($branch);
                $branch[$zaehler] = $menu_entry;

                if ($is_selected) {
                    $current_index = count($branch)-1;
                    $branch[0]['selected_index_by_level'] = [$current_index];
                } else if (count($children) && count(ncore_retrieve($children[0], 'selected_index_by_level', []))) {
                    $current_index = count($branch)-1;
                    $branch[0]['selected_index_by_level'] = array_merge([$current_index], $children[0]['selected_index_by_level']);
                } else if (!isset($branch[0]['selected_index_by_level'])) {
                    $branch[0]['selected_index_by_level'] = [];
                }
                unset($elements[$element->id]);
            }
        }
        return $branch;
    }
}