'Tips for code organization PHP/JavaScript

I've been looking at code organization techniques especially for JavaScript but haven't found the right solution yet. So I thought I ask here for any inputs on this matter.

Introduction

I am currently working on an intranet project which is based on a custom developed php framework.

The framework works like this:

  • Files are seperated into modules. Every module has its own folder
  • A GET Parameter decides which module should be loaded
  • Inside a module folder you can basically do whatever you want
  • The folder structure inside a module looks like this:

    [MODULEROOT]
    --[include]
    ----[auto] # every php script inhere gets autocincluded when the module loads
    ----[css]  # module specific css files go in here. They also get autoincluded and injected into the header tag of the generated html 
    ----[js] # module specific js files go in here. They also get autoincluded and injected into the header tag of the generated html
    --[interface] 
    ---- class.modInterface.php # Provides an easy interface for other modules to use their functionality.
    ---- class.modAjaxInterface.php # All AjaxCalls inside this framework go through php which does context changes (switch working directories when calling other modules etc...), generates the necessary JavaScript calls etc... (based on jQuery's $.get())
    ---- class.modSearch.php # Basically an interface for providing module specific search results and hooks them into the global search
    
  • The global AjaxInterface Class looks like this (simplified):

    class ModuleAjaxInterface extends LibBase{
    
        private static $handler_file = "";    
        private static $file_upload_handler_file = "";
        private static $registered_objects = array();
        public static function init(){
            // Initialization of the class. Getting all the modules interfaces and registering them etc...
            // Setting up the handler_file base on the config
        }
    
        public static function create($request_params=array(), $funcname, $options=array()){
            // Basically builds a JavaScript CodeBlock which handles all the function calling to the right file, parameter handling and callback functionality and returns it as String
        }
    
    
        public static function createPeriodical($request_params=array(), $funcname, $options=array()){
            // Same as above but creates periodical calls to the given function
        }
    
    
        public static function createUploadElement($upload_target, $input="file", $options=array()){
            // Creates an AjaxBased uploader and returns it as String
        }
    
        public function getHandlerUrl($params=array()){
            // Returns the URL for manual AjaxCalls to a Module defined by params 
        }
    }
    

Problem

Now that you have a basic idea about the setup here's my problem

I have a few modules that are pretty heavy on the javascript. So there are a lot of AjaxCalls to its own AjaxInterface or other module's AjaxInterfaces going on.

These AjaxCalls are generated through a PHP function end echoed to the page.

Then I have the specific logic when to call the Ajax JavaScript Functions as well as all the handling of the response data and injecting it into the dom right in the JavaScript of the current module.

A lot of the time the JavaScript code that calls the AjaxFunctions is generated through PHP because it depends on information which comes from the PHP environment. Like session infos or user specific infos or database related stuff.

So I currently write a PHP function which outputs a JavaScript Function with an AjaxCall to a PHP function. And this JavaScript function is called by another JavaScript function or inside a JavaScript Event which might be dependend on the current PHP environment, which is why it has been written in PHP.

I hope anyone gets what my problem is. As a result I often times end up with a lot of inline JavaScript because all the modules are rendered inside a content div in the html. Also how should I handle $(document).ready() calls?

To give you a short example how it is working with this setup see the following lines of code:

Inside our booking system

facility_container.php:

<?php
...

include_once('facility_dropdown.php');
include_once('facility_calendar.php');
include_once('facility_javascript.php');

?>

facility_javascript.php:

<script type="text/javascript">
<?php
    if(!$rights->getSpecialRight('IS_FACACC', $facility_id) && $resmode==2){
?>
        _flash("<h3>Information</h3><p>You don't have access to this facility.</p>", 'INFO', 0);
<?php
    }
?>

    $(document).ready(function(){

        function setFacilityListAndShow(html){
            $('#facility-list').html(html).parent().show();
            $('#facility-list').combobox();
        }

        function setFacilityListAndHide(html){
            $('#facility-list').html(html).parent().show();
            $('#facility-list').combobox();
        }

        function setFacilityList(html){
            $('#facility-list').html(html);
        }

        [...]

        $('#facility-list').change(function(){
            $('form[name="facility_form"]').submit();
        });

        <?php echo ModuleAjaxInterface::create(array('intname'=>'facilities', 'funcname'=>'getFacilitiesByTid'), 'getFacilitiesByTid', array('use_callback'=>true)); ?>
        <?php echo ModuleAjaxInterface::create(array('intname'=>'facilities', 'funcname'=>'addReservationAsArray'), 'addReservationAsArray', array('use_callback'=>true)); ?>
        <?php echo ModuleAjaxInterface::create(array('intname'=>'facilities', 'funcname'=>'addReservationAsSeriesAsArray'), 'addReservationAsSeriesAsArray', array('use_callback'=>true)); ?>
        <?php echo ModuleAjaxInterface::create(array('intname'=>'facilities', 'funcname'=>'addSeriesElementAsArray'), 'addSeriesElementAsArray', array('use_callback'=>true)); ?>
        <?php echo ModuleAjaxInterface::create(array('intname'=>'facilities', 'funcname'=>'fetchEvents'), 'fetchEvents', array('use_callback'=>true)); ?>
        <?php echo ModuleAjaxInterface::create(array('intname'=>'facilities', 'funcname'=>'removeEvent'), 'removeEvent', array('use_callback'=>true)); ?>
        <?php echo ModuleAjaxInterface::create(array('intname'=>'facilities', 'funcname'=>'updateEvent'), 'updateEvent', array('use_callback'=>true)); ?>

        [...]

        function removeEventComplete(data, input_params){
            if(data.status == 'success'){
                $('#calendar').fullCalendar('removeEvents', current_event.id);
                current_event = null;
                resetBookingForm();
            }
            _flash('<h3>'+data.title+'</h3><p>'+data.msg+'</p>', data.status, data.timeout);
        }

        function updateEventComplete(data, input_params){
            if(data.status == false){
                $('#submit').show();
                $('#calendar').fullCalendar('rerenderEvents'); // Nothing was updated. So we rerender all the events so that the reservation appears on the same place
            }else{
                resetBookingForm();
            }
        }

        <?php
            if(!empty($facility_id)){
        ?>

                [...] // 1000 lines of logic

                $('#submit').click(function(){  
                    $(this).hide();
                    $('#delete').hide();
                    var startdate = new Date(_parseInt($('#start-year').val()), _parseInt($('#start-month').val()-1), _parseInt($('#start-day').val()), _parseInt($('#start-hour').val()), _parseInt($('#start-minute').val()),0);
                    var enddate = new Date(_parseInt($('#start-year').val()), _parseInt($('#start-month').val()-1), _parseInt($('#start-day').val()), _parseInt($('#end-hour').val()), _parseInt($('#end-minute').val()), 0);           
                    var send_notification = 0;
                    if($('#notify').is(':checked')){
                    send_notification = 1;
                }

                var is_private = 0;
                if($('#is_private').is(':checked')){
                    is_private = 1;
                }

                // New Event was created so we call addReservationAsArray();
                if(current_event.db_id == 0){
                    var event_type = $('input[name=type]:checked').val();

                    if(event_type == 'single'){
                        var new_event = {
                            'reservation': {
                                'facilityid': <?php echo $facility_id; ?>,
                                'userid': '<?php echo $session->getUser(); ?>',
                                'serid': 0,
                                'reason': $('#title').val(),
                                'begin': startdate.getTime()/1000,
                                'end': enddate.getTime()/1000,
                                'send_notification': send_notification,
                                'is_private': is_private,
                                'style': current_event.category,
                                'count': 1
                            }
                        };

                        addReservationAsArray(new_event);
                        current_event.is_temp = false;
                }else{
                    [...]
                }
        <?php
            }else{
        ?>
                $('.combobox').combobox();
                $('#facility-list').siblings().find('input.ui-combobox-input').val("");
        <?php       
            }
        ?>
    }); // document.ready() END
</script>

I don't really have a good concept what the best way to organize this code would be.

Thanks for reading all of this. Any inputs would be appreciated



Solution 1:[1]

You only have about 100 lines of code and it already starts to be messy.

I would advise you to use a framework.

For PHP one of the frameworks that I've used and which never disappointed me is CakePHP. It has a huge communy, a great documentation and even a Blog tutorial to get you started.

Their folder structure is explained here.

For JS the smartest framework that I've met is AngularJS.

Angular doesn't force you to use a folder structure but it would be easier if you would create different folders for controllers, views, services, directives.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Catalin MUNTEANU