e107inc / e107

e107 Bootstrap CMS (Content Management System) v2 with PHP, MySQL, HTML5, jQuery and Twitter Bootstrap. Issue Discussion Room: https://gitter.im/e107inc/e107
https://e107.org
GNU General Public License v3.0
321 stars 213 forks source link

[documentation] - Library Manager #1725

Open lonalore opened 8 years ago

lonalore commented 8 years ago

Installing an external library that is required by a contributed plugin

Libraries need to be obtained separately from e107 plugins and themes. For now this has to be done manually.

Libraries should not reside in plugin folders

Reasoning

The best practice is to place libraries into a e107_web/lib directory.

Library Manager needs to be able to detect a library's version

Reasoning

Release cycles of e107 plugins and themes can be different than the release cycles of external libraries.

Effect

Library Manager supports version detection of libraries and provides a library's version information to plugins. Plugins implementing libraries can provide version-specific integration code or at least bail out in case of incompatible versions.

The current code flow is:

<?php
$library = e107::library('detect', 'example_library');
$version = $library['version'];
?>

Only one version of a library can be installed per site

Reasoning

If two different versions of the same library are installed, there is no way to guarantee that they will not both be loaded on the same page. If that were the case, visual errors could appear in case of CSS libraries, functional errors in case of JavaScript libraries and fatal errors in case of PHP libraries.

Library Manager needs meta information about libraries

See the API documentation for config() method in e107_plugins/_blank/e_library.php file for a detailed explanation of the information currently needed.

There are currently two ways to declare this information:

Library Manager includes a library registry, so if you want to use an external library in your plugin, you need to make it known first. You can do this by implementing config() method in e_library.php file of your plugin for your library, which users then have to download.

Using e_library.php file and implementing config() method
<?php
/**
 * @file
 * Provides information about external libraries.
 */

/**
 * Class PLUGIN_library.
 */
class PLUGIN_library
{

    /**
     * Return information about external libraries.
     */
    function config()
    {
        // A very simple library. No changing APIs (hence, no versions), no variants. 
        // Expected to be extracted into 'e107_web/lib/simple'.
        $libraries['simple'] = array(
            'name'              => 'Simple library',
            'vendor_url'        => 'http://example.com/simple',
            'download_url'      => 'http://example.com/simple',
            'version_arguments' => array(
                'file'    => 'readme.txt',
                // Best practice: Document the actual version strings for later reference.
                // 1.x: Version 1.0
                'pattern' => '/Version (\d+)/',
                'lines'   => 5,
            ),
            'files'             => array(
                'js'  => array(
                    'simple.js',
                ),
                'css' => array(
                    'simple.css',
                ),
            ),
        );

        return $libraries;
    }

}
Version detection

Version detection is using regular expressions. If you'd like to bypass the version detection regex you can replace the version_arguments array with a callback as demonstrated below:

<?php
/**
 * @file
 * Provides information about external libraries.
 */

/**
 * Class PLUGIN_library.
 */
class PLUGIN_library
{

    /**
     * Return information about external libraries.
     */
    function config()
    {
        // A very simple library. No changing APIs (hence, no versions), no variants. 
        // Expected to be extracted into 'e107_web/lib/simple'.
        $libraries['simple'] = array(
            'name'              => 'Simple library',
            'vendor_url'        => 'http://example.com/simple',
            'download_url'      => 'http://example.com/simple',
            'version callback' => 'simple_version_callback',
            'files'             => array(
                'js'  => array(
                    'simple.js',
                ),
                'css' => array(
                    'simple.css',
                ),
            ),
        );

        return $libraries;
    }

    function simple_version_callback() {
        // Use some fancy magic to get the version number... or don't.
        return TRUE;
    }

}
Loading

To load the library from inside your plugin (i.e in your e_header.php file), simply do:

<?php
e107::library('load', $name);
?>

Usually, you'll want to do something after the library has been loaded. Because you cannot always depend on the library being installed you have to check first if the loading was actually successful:

<?php
// Try to load the library and check if that worked.
if (($library = e107::library('load', $name)) && !empty($library['loaded'])) {
    // Do something with the library here.
}
?>
Detection

If you just want to check whether the library is installed, but don't want to load it right away, you can use:

<?php
$library = e107::library('detect', $name);
?>

Similar to checking whether the library was loaded above, we can then check if the library is installed:

<?php
if (($library = e107::library('detect', $name)) && !empty($library['installed'])) {
    // The library is installed. Awesome!
}
else
{
    // Something went wrong. :(
    // This contains a short status code of what went wrong, such as 'not found'.
    $error = $library['error'];
    // This contains a detailed error message.
    $error_message = $library['error_message'];
}
?>

Using Newer Versions of jQuery in e107

You will often need a newer version of jQuery to use a certain jQuery plugin. There are two ways to achieve this.

Method 1: Using theme_library.php addon file in your theme folder

<?php

/**
 * @file
 * Provides information about external libraries.
 */

/**
 * Class theme_library.
 */
class theme_library
{

    /**
     * Provides information about external libraries.
     */
    function config()
    {
        return array();
    }

    /**
     * Alters library information before detection and caching takes place.
     */
    function config_alter(&$libraries)
    {
        // Override CDN library path. Make sure, CDN path is correct.
        $libraries['cdn.jquery']['path'] = '3.1.1';

        // Override local library path. Make sure, you have downloaded the files
        // to 'e107_web/lib/jquery/3.1.1' folder with the same folder structure
        // than 'e107_web/lib/jquery/2.2.4'.
        $libraries['jquery']['path'] = '3.1.1';
    }

}

Method 2: Using e_library.php addon file in your plugin folder

<?php

/**
 * @file
 * Provides information about external libraries.
 */

/**
 * Class PLUGIN_NAME_library.
 */
class PLUGIN_NAME_library
{

    /**
     * Provides information about external libraries.
     */
    function config()
    {
        return array();
    }

    /**
     * Alters library information before detection and caching takes place.
     */
    function config_alter(&$libraries)
    {
        // Override CDN library path. Make sure, CDN path is correct.
        $libraries['cdn.jquery']['path'] = '3.1.1';

        // Override local library path. Make sure, you have downloaded the files
        // to 'e107_web/lib/jquery/3.1.1' folder with the same folder structure
        // than 'e107_web/lib/jquery/2.2.4'.
        $libraries['jquery']['path'] = '3.1.1';
    }

}

Finally, visit Admin UI / Preferences / Libraries page, and check your jQuery libraries.

lonalore commented 8 years ago

The situation is the same: My english is not the best, so please review this documentation before I share it on e107.org. Thank you! :)

Jimmi08 commented 6 years ago

@lonalore could you try to create theme_library.php for theme using bootstrap 4.0.0 beta?

I can't change bootstrap only for Frontend (css in admin area is correct, but js is not loaded) - as I can see library for Admin should be different than for Frontend.

I can't detect local bootstrap 4 library because this is not readable . I tried to change it to e_THEME_ABS, but still nothing. Echoed path looks correct. Tested on localhost.

if(is_readable(e_THEME . $library['theme'] . '/theme_library.php'))

Thank you.

lonalore commented 6 years ago

@Jimmi08 sorry for the late answer.

1, Download Bootstrap 4 files into the following directory structure:

kepernyokep_2017-09-25_19-30-20

2, Alter library information with your theme_library.php file:

/**
 * Class theme_library.
 */
class theme_library
{

    /**
     * Provides information about external libraries.
     */
    function config()
    {
        return array();
    }

    /**
     * Alters library information before detection and caching takes place.
     */
    function config_alter(&$libraries)
    {
        // Bootstrap (CDN).
        $libraries['cdn.bootstrap']['path'] = '4.0.0-alpha.6';
        $libraries['cdn.bootstrap']['version_arguments']['pattern'] = '/(\d\.\d\.\d\-[a-z]*\.\d+)/';

        // Bootstrap (local).
        $libraries['bootstrap']['path'] = '4.0.0-alpha.6';
        $libraries['bootstrap']['version_arguments']['pattern'] = '/(\d\.\d\.\d\-[a-z]*\.\d+)/';
    }

}

3, Clear system cache

CaMer0n commented 6 years ago

@lonalore I imagine that if someone downloads a theme using this theme_library.php file the theme will appear broken/messed-up until the user manually downloads bootstrap 4 and places it in the library folder. I'm wondering if we can have this download/unzip of missing libraries occur automatically during theme (and plugin) installation. Thoughts?

In v2.x I have tried to make plugin/theme/language-pack installation as automated as possible, without requiring someone to use FTP at all. So this would be in line with keeping e107 'simple', if you know what I mean.

Jimmi08 commented 6 years ago

@lonalore @CaMer0n I think that before official support e107 of bootstrap 4 (part of core files) it should be always load from theme folder. And there is - I think - problem with loaded paths. I wasn't able to set it loaded from theme folder.

For now I can live with CDN version.

I found next problems (its Alfa problem) : image

After changing version to 4.0.0-beta (dependency on thether should be fixed) in admin prefs. (Iworks only with cdnjs, but not with jsDelivr ) image

$libraries['cdn.bootstrap']['path'] = '4.0.0-beta'; Path is correct: https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-beta/css/bootstrap.min.css

I wasn't aware about this before, so it's just too soon. Old way without library works just fine.

lonalore commented 6 years ago

@CaMer0n It's a good idea, if I have time I will look into that plugin/theme manager class to see how it works.

@Jimmi08 e107 uses BS3 plugins, especially on the forms, e.g. BS3 Datepicker, Selectize.js with BS3 theme (autocomplete fields), and e107 renders HTML output based on BS3 standards. So I don't think you can use BS4 for your theme (without having to override core functions). @CaMer0n I was just wondering what do you think about a "v3.0.0" branch in this repo, for preparing e107 core for BS4 standards? We could also drop old BC codes from the core.

lonalore commented 6 years ago

Btw @Jimmi08 you can load BS4 files from your theme folder with altering library_path:

/**
 * Class theme_library.
 */
class theme_library
{

    /**
     * Provides information about external libraries.
     */
    function config()
    {
        return array();
    }

    /**
     * Alters library information before detection and caching takes place.
     */
    function config_alter(&$libraries)
    {
        // Bootstrap (CDN).
        $libraries['cdn.bootstrap']['path'] = '4.0.0-beta';
        $libraries['cdn.bootstrap']['version_arguments']['pattern'] = '/(\d\.\d\.\d\-[a-z]*)/';

        // Bootstrap (local).
        $libraries['bootstrap']['library_path'] = '{e_THEME}yourtheme/vendor/bootstrap';
        $libraries['bootstrap']['path'] = '4.0.0-beta';
        $libraries['bootstrap']['version_arguments']['pattern'] = '/(\d\.\d\.\d\-[a-z]*)/';
    }

}

For that CDN issue you need to put more logic to config_alter(), need to replace library_path.

Jimmi08 commented 6 years ago

@lonalore most changed parts are already fixed (img-responsive etc...) It's more about testing what else needs to be changed to get b4 theme working. We stopped this effort before because there were really big differencies between alpha versions and it was changed with each version too much.

With beta I noticed that most of authors are publishing new release with bootstrap 4. So now is the time to be prepared. The point is to have fixed core things if somebody set Bootstrap with value "4". For now only boostrap 4 classes was added. I am testing limits nothing more. And each limit I will discuss with @CaMer0n . So for now theme with b4 using e107:js() and e107:css() will be enough.

Agency HTML version has now stable bootstrap 4 version, only problem is my time.

Jimmi08 commented 6 years ago

@lonalore thanks for code, I didn't notice it before. I will try it. If didnt fix something, I dont think it will work. Maybe it surprises me.

That CDN problem should core thing. Maybe they will add it later.

Jimmi08 commented 6 years ago

this code worked:

        // Bootstrap (local).
        $libraries['bootstrap']['library_path'] = '{e_THEME}AgencyBootstrap4/vendor/bootstrap';
        $libraries['bootstrap']['path'] = '4.0.0-beta';
        $libraries['bootstrap']['theme']    = 'AgencyBootstrap4';
        $libraries['bootstrap']['version']  = '4.0.0-beta';     
        $libraries['bootstrap']['version_arguments']['pattern'] = '/(\d\.\d\.\d\-[a-z]*)/';
CaMer0n commented 6 years ago

@lonalore Actually, I started on Bootstrap4 compatibility in the master branch some months back. We can check the BOOTSTRAP === 4 and load accordingly. The admin area should continue to use bootstrap3 though. So we can continue on this branch, no problem.

fsLeg commented 5 years ago

I wanted to use latest stable versions of jQuery and Bootstrap (from CDN; I'll try local versions later), and this code worked for me in theme_library.php:

        $libraries['cdn.jquery']['library_path'] = 'https://cdnjs.cloudflare.com/ajax/libs/jquery';
        $libraries['cdn.jquery']['path'] = '3.3.1';
        $libraries['cdn.bootstrap4']['library_path'] = 'https://cdn.jsdelivr.net/npm/bootstrap@4.1.3';

I also had to specify

e107::library('load', 'cdn.bootstrap4');

in my theme.php, since jQuery seems to be the only library that is always being loaded.

But I must add that those libraries aren't shown anywhere in admin panel, they only load in frontend, so it was trial and error to make everything work as I wanted.

CaMer0n commented 5 years ago

Thanks @fsLeg ! That's certainly a good work-around.
Normally, one would just need to include this in their theme.xml file to load the latest bootstrap 4.

<libraries>
    <library name="bootstrap" version="4" scope="all"/>
    <library name="fontawesome" scope="all"/>
</libraries>

.. they could then switch between CDN or local in the admin preferences area.

The bootstrap4 version likely needs updating in the core at this time.

rica-carv commented 3 years ago

I don't know if it's the right place or not, but i have a few minor issues with libraries.

For instance, if in a plugin, i state via e_library for a library to be loaded, it only loads the js, even if i have a css specified in e_library. This issue happens when i load it via e107::library on e_header file of my plugin, like this:

e_header: e107::library('load', 'jquery.DataTables');

e_library:

$libraries['cdn.jquery.DataTables'] = array(
            // Only used in administrative UI of Libraries API.
            'name'              => 'DataTable (CDN)',
            'vendor_url'        => 'https://datatables.net',
            'download_url'      => 'https://datatables.net/download/',
            'version_arguments' => array(
                'file'    => 'js/jquery.dataTables.min.js',
                // Version: 3.1.6
                'pattern' => '/DataTables\s+(\d+\.+\d+\.+\d+)/',
                'lines'   => 15,
            ),
            'files'             => array(
                'js'  => array(
                    'js/jquery.dataTables.min.js' => array(
                        'type' => 'footer',
                    ),
                    'js/dataTables.bootstrap4.min.js' => array(
                        'type' => 'footer',
                    ),
                ),
                'css' => array(
                    'css/dataTables.bootstrap4.min.css',
                ),
            ),
            'variants'          => array(
                // 'unminified' version for debugging.
                'dev' => array(
                    'files' => array(
                        'js'  => array(
                            'js/jquery.dataTables.js' => array(
                                'type' => 'footer',
                            ),
                            'js/dataTables.bootstrap4.js' => array(
                                'type' => 'footer',
                            ),
                        ),
                        'css' => array(
                            'css/dataTables.bootstrap4.css',
                        ),
                    ),
                ),
            ),
            // Override library path to CDN.
            'library_path'      => 'https://cdn.datatables.net',
            'path'              => '1.10.23',
            'integration_files' => array(
                'philcat' => array(
                    'js' => array('jquery.dataTables.min.js'),
                ),
            ),
        );

        $libraries['jquery.DataTables'] = array(
            // Only used in administrative UI of Libraries API.
            'name'              => 'DataTable (local)',
            'vendor_url'        => 'https://datatables.net',
            'download_url'      => 'https://datatables.net/download/',
            'version_arguments' => array(
                'file'    => 'DataTables-1.10.23/js/jquery.dataTables.min.js',
                // Version: 3.1.6
                'pattern' => '/DataTables\s+(\d+\.+\d+\.+\d+)/',
                'lines'   => 15,
            ),
            'files'             => array(
                'js'  => array(
                    'DataTables-1.10.23/js/jquery.dataTables.min.js' => array(
                        'type' => 'footer',
                    ),
                    'DataTables-1.10.23/js/dataTables.bootstrap4.min.js' => array(
                        'type' => 'footer',
                    ),
                ),
                'css' => array(
                    'DataTables-1.10.23/css/dataTables.bootstrap4.min.css',
                ),
            ),
            'variants'          => array(
                // 'unminified' version for debugging.
                'dev' => array(
                    'files' => array(
                        'js'  => array(
                            'DataTables-1.10.23/js/jquery.dataTables.js' => array(
                                'type' => 'footer',
                            ),
                            'DataTables-1.10.23/js/dataTables.bootstrap4.js' => array(
                                'type' => 'footer',
                            ),
                        ),
                        'css' => array(
                            'DataTables-1.10.23/css/dataTables.bootstrap4.css',
                        ),
                    ),
                ),
            ),
            // Override library path to CDN.
            'library_path'      => '{e_WEB}lib/jquery.dataTables',
            'path'              => '1.10.23',
            'integration_files' => array(
                'philcat' => array(
                    'js' => array('jquery.dataTables.min.js'),
                ),
            ),
        );

So i ended up to load the css file manually on e_header.....

Shouldn't the css be loaded when the library correctly loads when called?

Furthermore, as a remark, i have some proposals for make more easier to code e_library file (i just took two days to understand it and set it up almost correctly...):

Again, if this is not the place, just let me know and i'll ask this somewhere else. And please excuse me for posting on a long clossed issue.... and posting such a long text....

CaMer0n commented 3 years ago

@rica-carv I agree, it is complex and the suggestions are good. For now, I suggest to stick with using e_header.php and e107::js / e107::css