Prado - Component Framework for PHP 7

Related tags

Frameworks prado
Overview

Prado PHP Framework

PRADO is a component-based and event-driven programming framework for developing Web applications in PHP 7. PRADO stands for PHP Rapid Application Development Object-oriented.

Build Status Code Quality Code Coverage Total Downloads Latest Stable Version Gitter

PRADO is best suitable for creating Web applications that are highly user-interactive. It can be used to develop systems as simple as a blog system to those as complex as a content management system (CMS) or a complete e-commerce solution. Because PRADO promotes object-oriented programming (OOP) through its component-based methodology, it fits extremely well for team work and enterprise development. Its event-driven programming pattern helps developers gain better focus on business logic rather than distracted by various tedious and repetitive low-level coding handling.

PRADO comes with many features that can cut down development time significantly. In particular, it provides a rich set of pluggable Web controls, complete database support including both active record and complex object mapper, seamless AJAX support, theme and skin, internationalization and localization, various caching solutions, security measures, and many other features that are seldom found in other programming frameworks.

The PRADO framework and the included demos are free software. They are released under the terms of the LICENSE.

Install

The best way to install PRADO is through composer. If you don't use composer yet, first install it:

# download composer.phar
curl -s http://getcomposer.org/installer | php
# install it globally on the system
mv composer.phar /usr/local/bin/composer

Then, create the application structure using composer:

composer create-project pradosoft/prado-app app

The application will be installed in the "app" directory.

Add PRADO to an existing application

Just create a composer.json file for your project:

{
  "repositories": [
    {
      "type": "composer",
      "url": "https://asset-packagist.org"
    }
  ],
    "require": {
      "pradosoft/prado": "~4.1"
  }
}

The asset-packagist repository is used to install javascript dependencies. Assuming you already installed composer, run

composer install

Then you can include the autoloader, and you will have access to the library classes:

<?php
require 'vendor/autoload.php';

Documentation

A great introduction to PRADO is available in the Quickstart tutorial. The tutorial itself is a PRADO application included in the demos The complete API documentation can be found on the API Manual

Demo Apps

Several different example PRADO applications are provided in the https://github.com/pradosoft/prado-demos repository. You can see these applications running here: http://www.pradoframework.net/site/demos/ .

Integration with your favorite IDE/editor

Plugins providing syntax highlighting and code snippets can be found at https://github.com/pradosoft/editor-plugins

Contributing

In the spirit of free software, everyone is encouraged to help improve this project.

Here are some ways you can contribute:

  • by using prerelease versions
  • by reporting bugs
  • by writing specifications
  • by writing code (no patch is too small: fix typos, add comments, clean up inconsistent whitespace)
  • by refactoring code
  • by resolving issues
  • by reviewing patches

Starting point:

  • Fork the repo
  • Clone your repo
  • Make your changes
  • Write tests for your changes to ensure that later changes to PRADO won't break your code.
  • Submit your pull request

Testing

PRADO uses phpunit (https://phpunit.de/) for unit testing and Selenium (http://www.seleniumhq.org/) for functional testing.

In order to run tests, first clone the PRADO repository and have composer install the needed development libraries:

git clone https://github.com/pradosoft/prado.git`
cd prado
composer install

For functional tests only, you need to manually download and run an app called Selenium Server. It's a java application, so you'll need to install a JRE/JDK and then run it from a terminal:

java -jar selenium-server-standalone-3.xxx.xx.jar 

Depending on the browser you want to use to do functional testing, you may need an additional driver.

Now you are redy to run tests; a phpunit configuration file is providen, to run the tests just execute

composer unittest to run unit tests and composer functionaltest to run functional tests.

Test results will be saved in in the build/tests/ directory.

Generatting the API documentation

PRADO uses its own fork of ApiGen 4 (http://www.apigen.org) to generate its API documentation. An ApiGen configuration file is providen, to generate the documentation just execute

composer gendoc

The documentation will be generated in the build/docs/ directory.

Comments
  • T*CronModule issues

    T*CronModule issues

    Hi,

    At the beginning I would like to thank you for creating CronModules, nice job.

    Issues:

    1. New tasks are always executed during the first run of prado-cli cron/run, regardles of scheduled time of execution.
    2. Expired tasks (Task0) are being executed every minute after last valid (scheduled) execution.
    3. Task01 is scheduled for 15 21 * * * * and after first run next runtime is set one hour later at 22:15:00. My time zone is CET.

    Description of process:

    1. The way of runnig cron tasks described in comments of TCronModule.php is not clear for me and I am running it this way:
    /usr/bin/sudo -u www-data /usr/bin/php7.4 /home/roman/www/crontestapp/protected/vendor/bin/prado-cli cron/run /home/roman/www/crontestapp/
    /usr/bin/sudo -u www-data /usr/bin/php7.4 /home/roman/www/crontestapp/protected/vendor/bin/prado-cli cron/tasks /home/roman/www/crontestapp/
    
    1. The way of adding tasks:
    $cron = $this->Application->Modules['cron'];
    
    $t = new Prado\Util\Cron\TCronMethodTask('test', 'createTmpFile3("Task0")');
    $t->Name ='Task0';
    $t->Schedule ='30 10 14 11 * 2022';
    $t->UserName ='pracownik4';
    
    $cron->addTask($t);
    
    $t = new Prado\Util\Cron\TCronMethodTask('test', 'createTmpFile3("Task1")');
    $t->Name ='Task01';
    $t->Schedule ='15 21 * * * *';
    $t->UserName ='pracownik4';
    
    $cron->addTask($t);
    
    1. My configuration from application.xml:
    <modules>
        ...
        <module id="test" class="Application.Cron.TestCronModule" />
        <module id="cron_db" class="Prado\Data\TDataSourceConfig">
            <database ConnectionString="sqlite:/home/roman/www/crontestapp/protected/Files/cron.jobs" />
        </module>
        <module id="cron" class="Prado\Util\Cron\TDbCronModule" DefaultUserName="pracownik1" ConnectionID="cron_db">
            <--
            <job Schedule="55 11 * * *" Task="test->createTmpFile()" />
            <job Name="cronclean" Schedule="0 0 * * * *" Task="Prado\Util\Cron\TDbCronCleanLogTask" />
            <job Name="dbcacheclean" Schedule="0 0 * * *" Task="cache->flushCacheExpired(true)" />
            -->
        </module>
    </modules>
    
    1. Tests

    BEFORE FIRST RUN

       Command line tools for Prado 4.2.1.
    
     Last cron run was 2022-11-14 10:13:35
     The system time is 2022-11-14 10:19:28
    
       Application Cron Tasks:
     Name   Schedule           Task                          Last Run            Next Run  User        Run #
     Task0  30 10 14 11 * 2022 test->createTmpFile3("Task0") 1970-01-01 01:00:00 01:00:00* @pracownik4 0
     Task01 15 21 * * * *      test->createTmpFile3("Task1") 1970-01-01 01:00:00 01:00:00* @pracownik4 0
    
     Any 'next run' with a * means it is Pending
    

    AFTER FIRST RUN

      Command line tools for Prado 4.2.1.
    
    Last Task time was 2022-11-14 10:13:35
     Running 2 Cron Tasks @ 2022-11-14 10:20:51
    
    Running Task Task0 as pracownik1
    Ending Task Task0
    
    Running Task Task01 as pracownik1
    Ending Task Task01
    
      Command line tools for Prado 4.2.1.
    
    Last cron run was 2022-11-14 10:20:51
    The system time is 2022-11-14 10:20:52
    
      Application Cron Tasks:
    Name   Schedule           Task                          Last Run Next Run User        Run #
    Task0  30 10 14 11 * 2022 test->createTmpFile3("Task0") 10:20:51 11:30:00 @pracownik4 1
    Task01 15 21 * * * *      test->createTmpFile3("Task1") 10:20:51 22:15:00 @pracownik4 1
    
    Any 'next run' with a * means it is Pending
    

    AFTER EXPIRATION OF Task0

      Command line tools for Prado 4.2.1.
    
    Last Task time was 2022-11-14 11:32:01
     Running 1 Cron Tasks @ 2022-11-14 11:33:01 
    
    Running Task Task0 as pracownik1
    Ending Task Task0
    
      Command line tools for Prado 4.2.1.
    
    Last cron run was 2022-11-14 11:33:01
    The system time is 2022-11-14 11:33:01
    
      Application Cron Tasks:
    Name   Schedule           Task                          Last Run Next Run  User        Run #
    Task0  30 10 14 11 * 2022 test->createTmpFile3("Task0") 11:33:01 01:00:00* @pracownik4 5
    Task01 15 21 * * * *      test->createTmpFile3("Task1") 10:20:51 22:15:00  @pracownik4 1
    
    Any 'next run' with a * means it is Pending
    
    opened by szroman 58
  • RFC - Better Composer Integration for extending PRADO

    RFC - Better Composer Integration for extending PRADO

    PRADO should have some kind of self contained plugin module system that add blocks of functionality from self contained modules, portlets, pages, assets, etc.

    Each Module will have a manifest.json defining it's internal properties and other info, like author information.

    TPageService would need to be updated to handle alternative BasePaths. TControl method would add getting the Plugin Module that the control comes from TTemplate Would have a property to stop class/attribute validation for skin templates. This allows for objects in the skin that may not exist. If removing a plugin, correcting the skin shouldn't be needed. TSkinTemplate would be added for Skin Templates. TTheme would add dynamic events in case any behavior wants to modify the Theme loading behavior.

    TPluginManager would be the main module that loads plugins. This uses application dyPreInit to load plugin modules prior to module initialization. TPluginModule would be a plugin module for defining plugin specific methods like reading and getting manifest parameters.

    This adds a Plugins folder to the Application folder.

    Use cases:

    • Adding google maps functionality, self contained and easily installable and usable by others.
    • self contained GDPR module for EU cookie requiremens
    • Wordpress integration module for reading Wordpress paramaters, posts/pages, and media
    • Analytics package
    • media manager
    • email PHPmailer utility module
    opened by belisoful 28
  • TActivedropdownList will empty TActiveDataGrid

    TActivedropdownList will empty TActiveDataGrid

    Hello,

    if I use a TActiveDropdownList in the editmode of the TActiveDataGrid, the grid will be emptied after selection is changed in the dropdownlist:

    Before: grafik

    At edititng: grafik

    After selection change:

    grafik

    And I'll see some uncaught exceptions: grafik

    I use version 3.3.3

    opened by jo49bimpf 28
  • THtmlElement cannot have subclasses define the default

    THtmlElement cannot have subclasses define the default

    From [email protected] on April 17, 2010 01:25:51

    Any subclass of THtmlElement will have the default tagname of 'span'

    Subclasses should be able to change the default tagname to their own specification r2807

    Original issue: http://code.google.com/p/prado3/issues/detail?id=255

    enhancement imported 
    opened by ctrlaltca 28
  • Move frpm 3.24 to 3.3.2 don't work

    Move frpm 3.24 to 3.3.2 don't work

    Hello, I'm moving from 3.2.4 to 3.3.2. But the application dies. With debugging I see, that the AutManager returns code 401. So I think theres is an problem with dthe autehtication/authorization.

    Is there any change? WQhat can I do to find/fix it?

    Thanks. Juergen

    opened by jo49bimpf 26
  • Prado client-side flawed - aka Multiple client-side (JS) object instances created for the same single DOM control

    Prado client-side flawed - aka Multiple client-side (JS) object instances created for the same single DOM control

    From [email protected] on June 19, 2009 18:35:23

    The current implementation of several JS-supported non-active controls and/or of TClientScriptManager::registerPostBackControl() interferes with the active control / callback mechanism in Prado, as it doesn't care about the type of the actual page cycle and the state of the control. The problem is that nor registerPostBackControl() neither its callers care about whether the actual page-cycle is a full-page reload or just a callback, and they (actually registerPostBackControl()) just simply always emit the JavaScript code which is responsible for the creation of the client-side JS objects for several JS-supported controls ("new Prado.WebUI.XXX()" lines at the end of the page). This is OK at initial page loads, but if this happens in a callback request, it leads to the creation of a new, redundant JavaScript client-side objects for controls that already might have one (or more) JS client-side object instantiated for them, thus leading to multiple (possibly conflicting) client-side JS support objects living on the page for the affected controls. This in turn results in very odd and buggy behaviour on the client side, and might also seriously effect the server running the Prado application.

    In the worst case this leads to doubling the number of the actual client- side JS objects for every affected control, which not only makes the browser eat more and more memory after each callback, but can also make your server crawl and lead to unpredictable behaviour if any of the affected controls do callbacks themselves too, (either in response to user actions or due to timed callbacks and such), because now every one of those client-side JS objects will fire their own callbacks for that single Prado control. After 8 callbacks you will have 256 client-side JS objects for every single one of the affected DOM controls in the page!

    For ex. if you create an "active version" of TSlider and hook into its onChange event, where you initiate a callback back to your page, so you get notified when the user dragged the control, then - after executing your callback -Prado will send back a response to the client-side with a new "new Prado.WebUI.TSlider({'ID':...)" JavaScript block in it. This happens because TSlider calls TClientScriptManager::registerPostBackControl () from its onPreRender() method which gets executed at every page cycle (even at callbacks) and because registerPostBackControl() doesn't care either whether the slider is a newly created control (in which case it would be legitimate to create a client side TSlider JS object for it) or an already existing one (which already has a JS object created, up and running for it in the browser), but simply emits the code for the client- side TSlider Js-object creation ("new Prado.WebUI.TSlider...) again, thus creating a second JS object instance for the very same object that not only already has one, but also was the control that initiated the callback cycle in the first place. Now, if you drag the slider, there will be 2 JS- side client objects monitoring and handling the control, even though that won't be apparent to you, because they all do the same thing. But when you release the slider, both of them will fire their onChange() events, thus resulting in not only one, but two callbacks to the server code - both returning a response which will create another two JS instances for the slider, thus resulting in 4 (!) JS objects handling the slider in total. If you drag the slider again, you will have 8, 16, 32, 64... JS-objects which all hook up to the same single slider control both on the page and also on the server side.

    Other controls might exhibit different behaviour due to the redundant objects and might lead to very weird effects. For ex. a control alternating between two states might become unable to be change it's state after the first change, as it - well, actually the JS objects linked to it - will always "see" an even number of events (2,4,8,16...) fired on it, thus resulting in the reversal of any attempt of change back to the original state. Controls which have a single well defined response and take a well-defined state for each user action, won't be crippled by the effects of this bug, because all their linked object-instances would send them into a state anyway, into which the first one sends them, thus resulting in no apparent glitch. For ex. even though TTabControl is also affected by this bug, it doesn't show any glitches, as no matter how many JS objects listen to the control's events, all of them will select the same tab for a click at a specific set of coordinates, and if the tab is already selected, then that won't result in any error either, so you won't even notice that there are now for ex. 32 client-side TTabControl objects handling your clicks on that single tab control in the DOM.

    OK, so much about the problem. Now, the solution. The bad new is: there isn't a simple one. A complete solution would require to extend TClientScriptManager::registerPostBackControl() (or it's callers) to keeps track of each control's state and only emit the JS code for them if either the current page cycle is an initial full page-load, the control gets replaced in the DOM by a new instance (because for ex. it was on a TActivePanel which got refreshed, or because it was an active control itself which got it's properties modified), or the control is a newly created one which has been constructed in the callback. If none of these are true, it should withhold the code for creating the client-side JS object for the control as there's already one of those at work in the browser. Implementing that will be though to, because of having to keep track of all the updates.

    Original issue: http://code.google.com/p/prado3/issues/detail?id=181

    bug imported 
    opened by ctrlaltca 22
  • Disabled TextBox could't updated

    Disabled TextBox could't updated

    Hello,

    after updating from 3.2.4 to 3.3.2 the update of a disabled input textfield won't work any more. This is the code:

    <com:TTemplateColumn 
        SortExpression="Kategoriestufe2" 
        ID="Kategoriestufe2ht" 
        HeaderText="Kategoriestufe2" 
        HeaderStyle.CssClass="pflichtfeld_fa_header sort-arrow"  
        ItemTemplate="<%# $this->Parent->Data->Kategoriestufe2 %>" 
    >
    <prop:EditItemTemplate>
        <com:TTextBox 
            ID="Kategoriestufe2tx" 
            Columns="30" 
            style="Background-color:white;" 
            enabled = "false"
            MaxLength="200" 
            Text=<%# $this->Parent->Data->Kategoriestufe2 %> 
        />
    </prop:EditItemTemplate>
    

    If I set in the TTextBox "Kategorystufe2tx" enabled to true, it will work again. What's happen or what do I have to change to get the old functionality?

    Thanks and regards Juergen

    opened by jo49bimpf 20
  • #488 added onInitComplete for CLI application module initialization

    #488 added onInitComplete for CLI application module initialization

    This is an addition-enhancement that will help CLI applications initialize after the modules are loaded up. It replaces OnBeginRequest as the first application event. Shell applications do not have an application event stack like normal applications... but they still should have post module initialization.

    Use Case, A Module that uses the the database module may want to do its database work in onInitComplete if, in case, the database module is loaded after the A Module.

    opened by belisoful 18
  • Progressive rendering not possible

    Progressive rendering not possible

    From [email protected] on March 13, 2010 21:56:53

    Seems like progressive rendering (ie. rendering smaller parts of the page and sending them to client right after completed, one after the other, instead of sending the whole page at once, after rendering of the whole page has completed) is currently not possible with Prado. This is because even the outermost container of all Prado pages, the TForm component itself is buffering all of its contents and then emitting it at once.

    Looking at TForm::render() I see no obvious reason for that, except being a hack to work around poorly written/incosistent code in the framework and in the application, that isn't/aren't able to property determine their script/field usage prior to the actual rendering, and therefore do that (ie. register (begin)scripts and fields) in the render() method. In my opinion this is just the result of bad design/coding practices, as all that information should be either determined and be present already in the PreRender() state and/or the field declarations and script references should be emitted inline in the render() process (as