JOOMLA中国
  • Joomla中国首页
  • 社区
  • 教程
  • 应用市场
  • B计划
Joomla! Framework TM
  • Namespace
  • Class
  • Tree
  • Deprecated

Namespaces

  • Composer
    • Autoload
  • Joomla
    • Application
      • Cli
        • Output
          • Processor
      • Web
    • Data
    • DI
      • Exception
    • Event
    • Filter
    • Input
    • Ldap
    • Registry
      • Format
    • Session
      • Storage
    • String
    • Uri
    • Utilities
  • None
  • PasswordCompat
    • binary
  • PHP
  • Psr
    • Log
  • Symfony
    • Component
      • Yaml
        • Exception
    • Polyfill
      • Util

Classes

  • CallbackFilterIterator
  • ComposerAutoloaderInit205c915b9c7d3e718e7c95793ee67ffe
  • easyparse
  • EasyPeasyICS
  • FOFAutoloaderComponent
  • FOFAutoloaderFof
  • FOFConfigDomainDispatcher
  • FOFConfigDomainTables
  • FOFConfigDomainViews
  • FOFConfigProvider
  • FOFController
  • FOFDatabase
  • FOFDatabaseDriver
  • FOFDatabaseDriverJoomla
  • FOFDatabaseDriverMysql
  • FOFDatabaseDriverMysqli
  • FOFDatabaseDriverOracle
  • FOFDatabaseDriverPdo
  • FOFDatabaseDriverPdomysql
  • FOFDatabaseDriverPostgresql
  • FOFDatabaseDriverSqlazure
  • FOFDatabaseDriverSqlite
  • FOFDatabaseDriverSqlsrv
  • FOFDatabaseFactory
  • FOFDatabaseInstaller
  • FOFDatabaseIterator
  • FOFDatabaseIteratorAzure
  • FOFDatabaseIteratorMysql
  • FOFDatabaseIteratorMysqli
  • FOFDatabaseIteratorOracle
  • FOFDatabaseIteratorPdo
  • FOFDatabaseIteratorPdomysql
  • FOFDatabaseIteratorPostgresql
  • FOFDatabaseIteratorSqlite
  • FOFDatabaseIteratorSqlsrv
  • FOFDatabaseQuery
  • FOFDatabaseQueryElement
  • FOFDatabaseQueryMysql
  • FOFDatabaseQueryMysqli
  • FOFDatabaseQueryOracle
  • FOFDatabaseQueryPdo
  • FOFDatabaseQueryPdomysql
  • FOFDatabaseQueryPostgresql
  • FOFDatabaseQuerySqlazure
  • FOFDatabaseQuerySqlite
  • FOFDatabaseQuerySqlsrv
  • FOFDispatcher
  • FOFDownload
  • FOFDownloadAdapterAbstract
  • FOFDownloadAdapterCurl
  • FOFDownloadAdapterFopen
  • FOFEncryptAes
  • FOFEncryptAesAbstract
  • FOFEncryptAesMcrypt
  • FOFEncryptAesOpenssl
  • FOFEncryptBase32
  • FOFEncryptRandval
  • FOFEncryptTotp
  • FOFForm
  • FOFFormFieldAccesslevel
  • FOFFormFieldActions
  • FOFFormFieldButton
  • FOFFormFieldCachehandler
  • FOFFormFieldCalendar
  • FOFFormFieldCaptcha
  • FOFFormFieldCheckbox
  • FOFFormFieldCheckboxes
  • FOFFormFieldComponents
  • FOFFormFieldEditor
  • FOFFormFieldEmail
  • FOFFormFieldGroupedbutton
  • FOFFormFieldGroupedlist
  • FOFFormFieldHidden
  • FOFFormFieldImage
  • FOFFormFieldImagelist
  • FOFFormFieldInteger
  • FOFFormFieldLanguage
  • FOFFormFieldList
  • FOFFormFieldMedia
  • FOFFormFieldModel
  • FOFFormFieldOrdering
  • FOFFormFieldPassword
  • FOFFormFieldPlugins
  • FOFFormFieldPublished
  • FOFFormFieldRadio
  • FOFFormFieldRelation
  • FOFFormFieldRules
  • FOFFormFieldSelectrow
  • FOFFormFieldSessionhandler
  • FOFFormFieldSpacer
  • FOFFormFieldSql
  • FOFFormFieldTag
  • FOFFormFieldTel
  • FOFFormFieldText
  • FOFFormFieldTextarea
  • FOFFormFieldTimezone
  • FOFFormFieldTitle
  • FOFFormFieldUrl
  • FOFFormFieldUser
  • FOFFormFieldUsergroup
  • FOFFormHeader
  • FOFFormHeaderAccesslevel
  • FOFFormHeaderField
  • FOFFormHeaderFielddate
  • FOFFormHeaderFieldfilterable
  • FOFFormHeaderFieldsearchable
  • FOFFormHeaderFieldselectable
  • FOFFormHeaderFieldsql
  • FOFFormHeaderFilterdate
  • FOFFormHeaderFilterfilterable
  • FOFFormHeaderFiltersearchable
  • FOFFormHeaderFilterselectable
  • FOFFormHeaderFiltersql
  • FOFFormHeaderLanguage
  • FOFFormHeaderModel
  • FOFFormHeaderOrdering
  • FOFFormHeaderPublished
  • FOFFormHeaderRowselect
  • FOFFormHelper
  • FOFHalDocument
  • FOFHalLink
  • FOFHalLinks
  • FOFHalRenderJson
  • FOFInflector
  • FOFInput
  • FOFIntegrationJoomlaFilesystem
  • FOFIntegrationJoomlaPlatform
  • FOFLayoutFile
  • FOFLayoutHelper
  • FOFLess
  • FOFLessFormatterClassic
  • FOFLessFormatterCompressed
  • FOFLessFormatterJoomla
  • FOFLessFormatterLessjs
  • FOFLessParser
  • FOFModel
  • FOFModelBehavior
  • FOFModelBehaviorAccess
  • FOFModelBehaviorEmptynonzero
  • FOFModelBehaviorEnabled
  • FOFModelBehaviorFilters
  • FOFModelBehaviorLanguage
  • FOFModelBehaviorPrivate
  • FOFModelDispatcherBehavior
  • FOFModelField
  • FOFModelFieldBoolean
  • FOFModelFieldDate
  • FOFModelFieldNumber
  • FOFModelFieldText
  • FOFPlatform
  • FOFPlatformFilesystem
  • FOFQueryAbstract
  • FOFRenderAbstract
  • FOFRenderJoomla
  • FOFRenderJoomla3
  • FOFRenderStrapper
  • FOFStringUtils
  • FOFTable
  • FOFTableBehavior
  • FOFTableBehaviorAssets
  • FOFTableBehaviorContenthistory
  • FOFTableBehaviorTags
  • FOFTableDispatcherBehavior
  • FOFTableNested
  • FOFTableRelations
  • FOFTemplateUtils
  • FOFToolbar
  • FOFUtilsArray
  • FOFUtilsCacheCleaner
  • FOFUtilsConfigHelper
  • FOFUtilsFilescheck
  • FOFUtilsIniParser
  • FOFUtilsInstallscript
  • FOFUtilsIp
  • FOFUtilsObject
  • FOFUtilsObservableDispatcher
  • FOFUtilsObservableEvent
  • FOFUtilsPhpfunc
  • FOFUtilsTimer
  • FOFUtilsUpdate
  • FOFUtilsUpdateCollection
  • FOFUtilsUpdateExtension
  • FOFUtilsUpdateJoomla
  • FOFView
  • FOFViewCsv
  • FOFViewForm
  • FOFViewHtml
  • FOFViewJson
  • FOFViewRaw
  • idna_convert
  • JAccess
  • JAccessRule
  • JAccessRules
  • JAccessWrapperAccess
  • JAdapter
  • JAdapterInstance
  • JApplication
  • JApplicationAdministrator
  • JApplicationBase
  • JApplicationCli
  • JApplicationCms
  • JApplicationDaemon
  • JApplicationHelper
  • JApplicationSite
  • JApplicationWeb
  • JApplicationWebRouter
  • JApplicationWebRouterBase
  • JApplicationWebRouterRest
  • JArchive
  • JArchiveBzip2
  • JArchiveGzip
  • JArchiveTar
  • JArchiveWrapperArchive
  • JArchiveZip
  • JArrayHelper
  • JAssociationExtensionHelper
  • JAuthentication
  • JAuthenticationHelper
  • JAuthenticationResponse
  • JBrowser
  • JBuffer
  • JButton
  • JCache
  • JCacheController
  • JCacheControllerCallback
  • JCacheControllerOutput
  • JCacheControllerPage
  • JCacheControllerView
  • JCacheStorage
  • JCacheStorageApc
  • JCacheStorageApcu
  • JCacheStorageCachelite
  • JCacheStorageFile
  • JCacheStorageHelper
  • JCacheStorageMemcache
  • JCacheStorageMemcached
  • JCacheStorageRedis
  • JCacheStorageWincache
  • JCacheStorageXcache
  • JCaptcha
  • JCategories
  • JCategoryNode
  • JClassLoader
  • JCli
  • JClientFtp
  • JClientHelper
  • JClientLdap
  • JClientWrapperHelper
  • JComponentHelper
  • JComponentRecord
  • JComponentRouterBase
  • JComponentRouterLegacy
  • JComponentRouterRulesMenu
  • JComponentRouterRulesNomenu
  • JComponentRouterRulesStandard
  • JComponentRouterView
  • JComponentRouterViewconfiguration
  • JControllerAdmin
  • JControllerBase
  • JControllerForm
  • JControllerLegacy
  • JCrypt
  • JCryptCipher3Des
  • JCryptCipherBlowfish
  • JCryptCipherCrypto
  • JCryptCipherMcrypt
  • JCryptCipherRijndael256
  • JCryptCipherSimple
  • JCryptKey
  • JCryptPasswordSimple
  • JDaemon
  • JDatabase
  • JDatabaseDriver
  • JDatabaseDriverMysql
  • JDatabaseDriverMysqli
  • JDatabaseDriverOracle
  • JDatabaseDriverPdo
  • JDatabaseDriverPdomysql
  • JDatabaseDriverPostgresql
  • JDatabaseDriverSqlazure
  • JDatabaseDriverSqlite
  • JDatabaseDriverSqlsrv
  • JDatabaseExporter
  • JDatabaseExporterMysql
  • JDatabaseExporterMysqli
  • JDatabaseExporterPdomysql
  • JDatabaseExporterPostgresql
  • JDatabaseFactory
  • JDatabaseImporter
  • JDatabaseImporterMysql
  • JDatabaseImporterMysqli
  • JDatabaseImporterPdomysql
  • JDatabaseImporterPostgresql
  • JDatabaseInterface
  • JDatabaseIterator
  • JDatabaseIteratorMysql
  • JDatabaseIteratorMysqli
  • JDatabaseIteratorOracle
  • JDatabaseIteratorPdo
  • JDatabaseIteratorPdomysql
  • JDatabaseIteratorPostgresql
  • JDatabaseIteratorSqlazure
  • JDatabaseIteratorSqlite
  • JDatabaseIteratorSqlsrv
  • JDatabaseMysql
  • JDatabaseMysqli
  • JDatabaseQuery
  • JDatabaseQueryElement
  • JDatabaseQueryLimitable
  • JDatabaseQueryMysql
  • JDatabaseQueryMysqli
  • JDatabaseQueryOracle
  • JDatabaseQueryPdo
  • JDatabaseQueryPdomysql
  • JDatabaseQueryPostgresql
  • JDatabaseQueryPreparable
  • JDatabaseQuerySqlazure
  • JDatabaseQuerySqlite
  • JDatabaseQuerySqlsrv
  • JDatabaseSqlazure
  • JDatabaseSqlsrv
  • JDate
  • JDispatcher
  • JDocument
  • JDocumentError
  • JDocumentFeed
  • JDocumentHtml
  • JDocumentImage
  • JDocumentJson
  • JDocumentOpensearch
  • JDocumentRaw
  • JDocumentRenderer
  • JDocumentRendererAtom
  • JDocumentRendererComponent
  • JDocumentRendererFeedAtom
  • JDocumentRendererFeedRss
  • JDocumentRendererHead
  • JDocumentRendererHtmlComponent
  • JDocumentRendererHtmlHead
  • JDocumentRendererHtmlMessage
  • JDocumentRendererHtmlModule
  • JDocumentRendererHtmlModules
  • JDocumentRendererMessage
  • JDocumentRendererModule
  • JDocumentRendererModules
  • JDocumentRendererRSS
  • JDocumentXml
  • JEditor
  • JError
  • JErrorPage
  • JEvent
  • JEventDispatcher
  • JExtension
  • JFacebook
  • JFacebookAlbum
  • JFacebookCheckin
  • JFacebookComment
  • JFacebookEvent
  • JFacebookGroup
  • JFacebookLink
  • JFacebookNote
  • JFacebookOAuth
  • JFacebookObject
  • JFacebookPhoto
  • JFacebookPost
  • JFacebookStatus
  • JFacebookUser
  • JFacebookVideo
  • JFactory
  • JFeed
  • JFeedEnclosure
  • JFeedEntry
  • JFeedFactory
  • JFeedImage
  • JFeedItem
  • JFeedLink
  • JFeedParser
  • JFeedParserAtom
  • JFeedParserRss
  • JFeedParserRssItunes
  • JFeedParserRssMedia
  • JFeedPerson
  • JFile
  • JFilesystemHelper
  • JFilesystemPatcher
  • JFilesystemWrapperFile
  • JFilesystemWrapperFolder
  • JFilesystemWrapperPath
  • JFilterInput
  • JFilterOutput
  • JFilterWrapperOutput
  • JFolder
  • JForm
  • JFormField
  • JFormFieldAccessLevel
  • JFormFieldAliastag
  • JFormFieldAuthor
  • JFormFieldCacheHandler
  • JFormFieldCalendar
  • JFormFieldCaptcha
  • JFormFieldCategory
  • JFormFieldCheckbox
  • JFormFieldCheckboxes
  • JFormFieldChromeStyle
  • JFormFieldColor
  • JFormFieldCombo
  • JFormFieldComponentlayout
  • JFormFieldComponents
  • JFormFieldContenthistory
  • JFormFieldContentlanguage
  • JFormFieldContenttype
  • JFormFieldDatabaseConnection
  • JFormFieldEditor
  • JFormFieldEMail
  • JFormFieldFile
  • JFormFieldFileList
  • JFormFieldFolderList
  • JFormFieldFrontend_Language
  • JFormFieldGroupedList
  • JFormFieldHeadertag
  • JFormFieldHelpsite
  • JFormFieldHidden
  • JFormFieldImageList
  • JFormFieldInteger
  • JFormFieldLanguage
  • JFormFieldLastvisitDateRange
  • JFormFieldLimitbox
  • JFormFieldList
  • JFormFieldMedia
  • JFormFieldMenu
  • JFormFieldMenuitem
  • JFormFieldMeter
  • JFormFieldModulelayout
  • JFormFieldModuleOrder
  • JFormFieldModulePosition
  • JFormFieldModuletag
  • JFormFieldNote
  • JFormFieldNumber
  • JFormFieldOrdering
  • JFormFieldPassword
  • JFormFieldPlugin_Status
  • JFormFieldPlugins
  • JFormFieldPredefinedList
  • JFormFieldRadio
  • JFormFieldRange
  • JFormFieldRegistrationDateRange
  • JFormFieldRepeatable
  • JFormFieldRules
  • JFormFieldSessionHandler
  • JFormFieldSpacer
  • JFormFieldSQL
  • JFormFieldStatus
  • JFormFieldSubform
  • JFormFieldTag
  • JFormFieldTel
  • JFormFieldTemplatestyle
  • JFormFieldText
  • JFormFieldTextarea
  • JFormFieldTimezone
  • JFormFieldUrl
  • JFormFieldUser
  • JFormFieldUserActive
  • JFormFieldUsergroup
  • JFormFieldUserGroupList
  • JFormFieldUserState
  • JFormHelper
  • JFormRule
  • JFormRuleBoolean
  • JFormRuleCalendar
  • JFormRuleCaptcha
  • JFormRuleColor
  • JFormRuleEmail
  • JFormRuleEquals
  • JFormRuleNotequals
  • JFormRuleNumber
  • JFormRuleOptions
  • JFormRulePassword
  • JFormRuleRules
  • JFormRuleTel
  • JFormRuleUrl
  • JFormRuleUsername
  • JFormWrapperHelper
  • JFTP
  • JGithub
  • JGithubAccount
  • JGithubCommits
  • JGithubForks
  • JGithubHooks
  • JGithubHttp
  • JGithubMeta
  • JGithubMilestones
  • JGithubObject
  • JGithubPackage
  • JGithubPackageActivity
  • JGithubPackageActivityEvents
  • JGithubPackageActivityNotifications
  • JGithubPackageActivityStarring
  • JGithubPackageActivityWatching
  • JGithubPackageAuthorization
  • JGithubPackageData
  • JGithubPackageDataBlobs
  • JGithubPackageDataCommits
  • JGithubPackageDataRefs
  • JGithubPackageDataTags
  • JGithubPackageDataTrees
  • JGithubPackageGists
  • JGithubPackageGistsComments
  • JGithubPackageGitignore
  • JGithubPackageIssues
  • JGithubPackageIssuesAssignees
  • JGithubPackageIssuesComments
  • JGithubPackageIssuesEvents
  • JGithubPackageIssuesLabels
  • JGithubPackageIssuesMilestones
  • JGithubPackageMarkdown
  • JGithubPackageOrgs
  • JGithubPackageOrgsMembers
  • JGithubPackageOrgsTeams
  • JGithubPackagePulls
  • JGithubPackagePullsComments
  • JGithubPackageRepositories
  • JGithubPackageRepositoriesCollaborators
  • JGithubPackageRepositoriesComments
  • JGithubPackageRepositoriesCommits
  • JGithubPackageRepositoriesContents
  • JGithubPackageRepositoriesDownloads
  • JGithubPackageRepositoriesForks
  • JGithubPackageRepositoriesHooks
  • JGithubPackageRepositoriesKeys
  • JGithubPackageRepositoriesMerging
  • JGithubPackageRepositoriesStatistics
  • JGithubPackageRepositoriesStatuses
  • JGithubPackageSearch
  • JGithubPackageUsers
  • JGithubPackageUsersEmails
  • JGithubPackageUsersFollowers
  • JGithubPackageUsersKeys
  • JGithubRefs
  • JGithubStatuses
  • JGoogle
  • JGoogleAuth
  • JGoogleAuthOauth2
  • JGoogleData
  • JGoogleDataAdsense
  • JGoogleDataCalendar
  • JGoogleDataPicasa
  • JGoogleDataPicasaAlbum
  • JGoogleDataPicasaPhoto
  • JGoogleDataPlus
  • JGoogleDataPlusActivities
  • JGoogleDataPlusComments
  • JGoogleDataPlusPeople
  • JGoogleEmbed
  • JGoogleEmbedAnalytics
  • JGoogleEmbedMaps
  • JGrid
  • JHelp
  • JHelper
  • JHelperContent
  • JHelperContenthistory
  • JHelperMedia
  • JHelperRoute
  • JHelperTags
  • JHelperUsergroups
  • JHtml
  • JHtmlAccess
  • JHtmlActionsDropdown
  • JHtmlBatch
  • JHtmlBehavior
  • JHtmlBootstrap
  • JHtmlCategory
  • JHtmlContent
  • JHtmlContentLanguage
  • JHtmlDate
  • JHtmlDebug
  • JHtmlDropdown
  • JHtmlEmail
  • JHtmlForm
  • JHtmlFormbehavior
  • JHtmlGrid
  • JHtmlIcons
  • JHtmlJGrid
  • JHtmlJquery
  • JHtmlLinks
  • JHtmlList
  • JHtmlMenu
  • JHtmlNumber
  • JHtmlRules
  • JHtmlSearchtools
  • JHtmlSelect
  • JHtmlSidebar
  • JHtmlSliders
  • JHtmlSortablelist
  • JHtmlString
  • JHtmlTabs
  • JHtmlTag
  • JHtmlTel
  • JHtmlUser
  • JHttp
  • JHttpFactory
  • JHttpResponse
  • JHttpTransportCurl
  • JHttpTransportSocket
  • JHttpTransportStream
  • JHttpWrapperFactory
  • JImage
  • JImageFilter
  • JImageFilterBackgroundfill
  • JImageFilterBrightness
  • JImageFilterContrast
  • JImageFilterEdgedetect
  • JImageFilterEmboss
  • JImageFilterGrayscale
  • JImageFilterNegate
  • JImageFilterSketchy
  • JImageFilterSmooth
  • JInput
  • JInputCli
  • JInputCookie
  • JInputFiles
  • JInputJSON
  • JInstaller
  • JInstallerAdapter
  • JInstallerAdapterComponent
  • JInstallerAdapterFile
  • JInstallerAdapterLanguage
  • JInstallerAdapterLibrary
  • JInstallerAdapterModule
  • JInstallerAdapterPackage
  • JInstallerAdapterPlugin
  • JInstallerAdapterTemplate
  • JInstallerComponent
  • JInstallerExtension
  • JInstallerFile
  • JInstallerHelper
  • JInstallerLanguage
  • JInstallerLibrary
  • JInstallerManifest
  • JInstallerManifestLibrary
  • JInstallerManifestPackage
  • JInstallerModule
  • JInstallerPackage
  • JInstallerPlugin
  • JInstallerScript
  • JInstallerTemplate
  • JKeychain
  • JLanguage
  • JLanguageAssociations
  • JLanguageHelper
  • JLanguageMultilang
  • JLanguageStemmer
  • JLanguageStemmerPorteren
  • JLanguageTransliterate
  • JLanguageWrapperHelper
  • JLanguageWrapperText
  • JLanguageWrapperTransliterate
  • JLayoutBase
  • JLayoutFile
  • JLayoutHelper
  • JLDAP
  • JLess
  • JLessFormatterJoomla
  • JLibraryHelper
  • JLinkedin
  • JLinkedinCommunications
  • JLinkedinCompanies
  • JLinkedinGroups
  • JLinkedinJobs
  • JLinkedinOauth
  • JLinkedinObject
  • JLinkedinPeople
  • JLinkedinStream
  • JLoader
  • JLog
  • JLogEntry
  • JLogger
  • JLogLogger
  • JLogLoggerCallback
  • JLogLoggerDatabase
  • JLogLoggerEcho
  • JLogLoggerFormattedtext
  • JLogLoggerMessagequeue
  • JLogLoggerSyslog
  • JLogLoggerW3c
  • JMail
  • JMailHelper
  • JMailWrapperHelper
  • JMediawiki
  • JMediawikiCategories
  • JMediawikiHttp
  • JMediawikiImages
  • JMediawikiLinks
  • JMediawikiObject
  • JMediawikiPages
  • JMediawikiSearch
  • JMediawikiSites
  • JMediawikiUsers
  • JMenu
  • JMenuAdministrator
  • JMenuItem
  • JMenuSite
  • JMicrodata
  • JModelAdmin
  • JModelBase
  • JModelDatabase
  • JModelForm
  • JModelItem
  • JModelLegacy
  • JModelList
  • JModuleHelper
  • JNode
  • JOAuth1Client
  • JOAuth2Client
  • JObject
  • JObservable
  • JObserver
  • JObserverMapper
  • JObserverUpdater
  • JObserverWrapperMapper
  • JOpenSearchImage
  • JOpenSearchUrl
  • JOpenstreetmap
  • JOpenstreetmapChangesets
  • JOpenstreetmapElements
  • JOpenstreetmapGps
  • JOpenstreetmapInfo
  • JOpenstreetmapOauth
  • JOpenstreetmapObject
  • JOpenstreetmapUser
  • JPagination
  • JPaginationObject
  • JPath
  • JPathway
  • JPathwaySite
  • JPlatform
  • JPlugin
  • JPluginHelper
  • JProfiler
  • JRequest
  • JResponse
  • JResponseJson
  • JRoute
  • JRouter
  • JRouterAdministrator
  • JRouterSite
  • JRouteWrapperRoute
  • JRule
  • JRules
  • JSchemaChangeitem
  • JSchemaChangeitemMysql
  • JSchemaChangeitemPostgresql
  • JSchemaChangeitemSqlsrv
  • JSchemaChangeset
  • JSearchHelper
  • JSession
  • JSessionHandlerJoomla
  • JSessionHandlerNative
  • JSessionStorage
  • JSessionStorageApc
  • JSessionStorageDatabase
  • JSessionStorageMemcache
  • JSessionStorageMemcached
  • JSessionStorageNone
  • JSessionStorageWincache
  • JSessionStorageXcache
  • JSimplecrypt
  • JSimplepieFactory
  • JStream
  • JStreamString
  • JString
  • JStringController
  • JStringPunycode
  • JStringWrapperNormalise
  • JStringWrapperPunycode
  • JTable
  • JTableAsset
  • JTableCategory
  • JTableContent
  • JTableContenthistory
  • JTableContenttype
  • JTableCorecontent
  • JTableExtension
  • JTableInterface
  • JTableLanguage
  • JTableMenu
  • JTableMenuType
  • JTableModule
  • JTableNested
  • JTableObserver
  • JTableObserverContenthistory
  • JTableObserverTags
  • JTableSession
  • JTableUcm
  • JTableUpdate
  • JTableUpdatesite
  • JTableUser
  • JTableUsergroup
  • JTableViewlevel
  • JText
  • JToolbar
  • JToolbarButton
  • JToolbarButtonConfirm
  • JToolbarButtonCustom
  • JToolbarButtonHelp
  • JToolbarButtonLink
  • JToolbarButtonPopup
  • JToolbarButtonSeparator
  • JToolbarButtonSlider
  • JToolbarButtonStandard
  • JTree
  • JTwitter
  • JTwitterBlock
  • JTwitterDirectmessages
  • JTwitterFavorites
  • JTwitterFriends
  • JTwitterHelp
  • JTwitterLists
  • JTwitterOAuth
  • JTwitterObject
  • JTwitterPlaces
  • JTwitterProfile
  • JTwittersearch
  • JTwitterStatuses
  • JTwitterTrends
  • JTwitterUsers
  • JUcmBase
  • JUcmContent
  • JUcmType
  • JUpdate
  • JUpdateAdapter
  • JUpdater
  • JUpdaterCollection
  • JUpdaterExtension
  • JUri
  • JUser
  • JUserHelper
  • JUserWrapperHelper
  • JUtility
  • JVersion
  • JViewBase
  • JViewCategories
  • JViewCategory
  • JViewCategoryfeed
  • JViewHtml
  • JViewLegacy
  • JWeb
  • JWebClient
  • JXMLElement
  • lessc
  • lessc_formatter_classic
  • lessc_formatter_compressed
  • lessc_formatter_lessjs
  • lessc_parser
  • lessify
  • Net_IDNA_php4
  • nodecounter
  • ntlm_sasl_client_class
  • PHPMailer
  • PHPMailerOAuth
  • PHPMailerOAuthGoogle
  • POP3
  • SimplePie
  • SimplePie_Author
  • SimplePie_Autoloader
  • SimplePie_Cache
  • SimplePie_Cache_DB
  • SimplePie_Cache_File
  • SimplePie_Cache_Memcache
  • SimplePie_Cache_MySQL
  • SimplePie_Caption
  • SimplePie_Category
  • SimplePie_Content_Type_Sniffer
  • SimplePie_Copyright
  • SimplePie_Core
  • SimplePie_Credit
  • SimplePie_Decode_HTML_Entities
  • SimplePie_Enclosure
  • SimplePie_File
  • SimplePie_gzdecode
  • SimplePie_HTTP_Parser
  • SimplePie_IRI
  • SimplePie_Item
  • SimplePie_Locator
  • SimplePie_Misc
  • SimplePie_Net_IPv6
  • SimplePie_Parse_Date
  • SimplePie_Parser
  • SimplePie_Rating
  • SimplePie_Registry
  • SimplePie_Restriction
  • SimplePie_Sanitize
  • SimplePie_Source
  • SimplePie_XML_Declaration_Parser
  • SMTP
  • tagparse
  • TypeError

Interfaces

  • FOFConfigDomainInterface
  • FOFDatabaseInterface
  • FOFDatabaseQueryLimitable
  • FOFDatabaseQueryPreparable
  • FOFDownloadInterface
  • FOFEncryptAesInterface
  • FOFEncryptRandvalinterface
  • FOFFormField
  • FOFHalRenderInterface
  • FOFPlatformFilesystemInterface
  • FOFPlatformInterface
  • JArchiveExtractable
  • JAssociationExtensionInterface
  • JCacheException
  • JComponentRouterInterface
  • JComponentRouterRulesInterface
  • JController
  • JCryptCipher
  • JCryptPassword
  • JFeedParserNamespace
  • JHttpTransport
  • JLayout
  • JModel
  • JObservableInterface
  • JObserverInterface
  • JObserverUpdaterInterface
  • JSessionHandlerInterface
  • JsonSerializable
  • JUcm
  • JView
  • SimplePie_Cache_Base

Exceptions

  • Error
  • JAccessExceptionNotallowed
  • JCacheExceptionConnecting
  • JCacheExceptionUnsupported
  • JComponentExceptionMissing
  • JDatabaseException
  • JDatabaseExceptionConnecting
  • JDatabaseExceptionExecuting
  • JDatabaseExceptionUnsupported
  • JException
  • JSessionExceptionUnsupported
  • LogException
  • phpmailerException
  • SimplePie_Exception

Constants

  • JERROR_CALLBACK_NOT_CALLABLE
  • JERROR_ILLEGAL_MODE
  • JERROR_ILLEGAL_OPTIONS
  • JREQUEST_ALLOWHTML
  • JREQUEST_ALLOWRAW
  • JREQUEST_NOTRIM
  • JROUTER_MODE_RAW
  • JROUTER_MODE_SEF

Functions

  • __autoload
  • array_column
  • boolval
  • composerRequire205c915b9c7d3e718e7c95793ee67ffe
  • gzopen
  • gzseek
  • gztell
  • hash_equals
  • hash_pbkdf2
  • HTMLFilter
  • jexit
  • jimport
  • json_last_error_msg
  • ldap_escape
  • password_get_info
  • password_hash
  • password_needs_rehash
  • password_verify
  • PHPMailerAutoload
  • random_bytes
  • random_int
  • RandomCompat_intval
  • RandomCompat_strlen
  • RandomCompat_substr
  • tln_body2div
  • tln_casenormalize
  • tln_deent
  • tln_defang
  • tln_findnxreg
  • tln_findnxstr
  • tln_fixatts
  • tln_fixstyle
  • tln_fixurl
  • tln_getnxtag
  • tln_sanitize
  • tln_skipspace
  • tln_tagprint
  • tln_unspace
  • utf8_accents_to_ascii
  • utf8_bad_explain
  • utf8_bad_find
  • utf8_bad_findall
  • utf8_bad_identify
  • utf8_bad_replace
  • utf8_bad_strip
  • utf8_byte_position
  • utf8_compliant
  • utf8_from_unicode
  • utf8_ireplace
  • utf8_is_ascii
  • utf8_is_ascii_ctrl
  • utf8_is_valid
  • utf8_is_word_chars
  • utf8_locate_current_chr
  • utf8_locate_next_chr
  • utf8_ltrim
  • utf8_ord
  • utf8_rtrim
  • utf8_specials_pattern
  • utf8_str_pad
  • utf8_str_split
  • utf8_strcasecmp
  • utf8_strcspn
  • utf8_strip_ascii_ctrl
  • utf8_strip_non_ascii
  • utf8_strip_non_ascii_ctrl
  • utf8_strip_specials
  • utf8_stristr
  • utf8_strlen
  • utf8_strpos
  • utf8_strrev
  • utf8_strrpos
  • utf8_strspn
  • utf8_strtolower
  • utf8_strtoupper
  • utf8_substr
  • utf8_substr_replace
  • utf8_to_unicode
  • utf8_trim
  • utf8_ucfirst
  • utf8_ucwords
  • utf8_ucwords_callback
   1 <?php
   2 /**
   3  * @package     FrameworkOnFramework
   4  * @subpackage  utils
   5  * @copyright   Copyright (C) 2010-2016 Nicholas K. Dionysopoulos / Akeeba Ltd. All rights reserved.
   6  * @license     GNU General Public License version 2 or later; see LICENSE.txt
   7  */
   8 
   9 defined('FOF_INCLUDED') or die;
  10 
  11 JLoader::import('joomla.filesystem.folder');
  12 JLoader::import('joomla.filesystem.file');
  13 JLoader::import('joomla.installer.installer');
  14 JLoader::import('joomla.utilities.date');
  15 
  16 /**
  17  * A helper class which you can use to create component installation scripts
  18  */
  19 abstract class FOFUtilsInstallscript
  20 {
  21     /**
  22      * The component's name
  23      *
  24      * @var   string
  25      */
  26     protected $componentName = 'com_foobar';
  27 
  28     /**
  29      * The title of the component (printed on installation and uninstallation messages)
  30      *
  31      * @var string
  32      */
  33     protected $componentTitle = 'Foobar Component';
  34 
  35     /**
  36      * The list of extra modules and plugins to install on component installation / update and remove on component
  37      * uninstallation.
  38      *
  39      * @var   array
  40      */
  41     protected $installation_queue = array(
  42         // modules => { (folder) => { (module) => { (position), (published) } }* }*
  43         'modules' => array(
  44             'admin' => array(),
  45             'site'  => array()
  46         ),
  47         // plugins => { (folder) => { (element) => (published) }* }*
  48         'plugins' => array(
  49             'system' => array(),
  50         )
  51     );
  52 
  53     /**
  54      * The list of obsolete extra modules and plugins to uninstall on component upgrade / installation.
  55      *
  56      * @var array
  57      */
  58     protected $uninstallation_queue = array(
  59         // modules => { (folder) => { (module) }* }*
  60         'modules' => array(
  61             'admin' => array(),
  62             'site'  => array()
  63         ),
  64         // plugins => { (folder) => { (element) }* }*
  65         'plugins' => array(
  66             'system' => array(),
  67         )
  68     );
  69 
  70     /**
  71      * Obsolete files and folders to remove from the free version only. This is used when you move a feature from the
  72      * free version of your extension to its paid version. If you don't have such a distinction you can ignore this.
  73      *
  74      * @var   array
  75      */
  76     protected $removeFilesFree = array(
  77         'files'   => array(
  78             // Use pathnames relative to your site's root, e.g.
  79             // 'administrator/components/com_foobar/helpers/whatever.php'
  80         ),
  81         'folders' => array(
  82             // Use pathnames relative to your site's root, e.g.
  83             // 'administrator/components/com_foobar/baz'
  84         )
  85     );
  86 
  87     /**
  88      * Obsolete files and folders to remove from both paid and free releases. This is used when you refactor code and
  89      * some files inevitably become obsolete and need to be removed.
  90      *
  91      * @var   array
  92      */
  93     protected $removeFilesAllVersions = array(
  94         'files'   => array(
  95             // Use pathnames relative to your site's root, e.g.
  96             // 'administrator/components/com_foobar/helpers/whatever.php'
  97         ),
  98         'folders' => array(
  99             // Use pathnames relative to your site's root, e.g.
 100             // 'administrator/components/com_foobar/baz'
 101         )
 102     );
 103 
 104     /**
 105      * A list of scripts to be copied to the "cli" directory of the site
 106      *
 107      * @var   array
 108      */
 109     protected $cliScriptFiles = array(
 110         // Use just the filename, e.g.
 111         // 'my-cron-script.php'
 112     );
 113 
 114     /**
 115      * The path inside your package where cli scripts are stored
 116      *
 117      * @var   string
 118      */
 119     protected $cliSourcePath = 'cli';
 120 
 121     /**
 122      * The path inside your package where FOF is stored
 123      *
 124      * @var   string
 125      */
 126     protected $fofSourcePath = 'fof';
 127 
 128     /**
 129      * The path inside your package where Akeeba Strapper is stored
 130      *
 131      * @var   string
 132      */
 133     protected $strapperSourcePath = 'strapper';
 134 
 135     /**
 136      * The path inside your package where extra modules are stored
 137      *
 138      * @var   string
 139      */
 140     protected $modulesSourcePath = 'modules';
 141 
 142     /**
 143      * The path inside your package where extra plugins are stored
 144      *
 145      * @var   string
 146      */
 147     protected $pluginsSourcePath = 'plugins';
 148 
 149     /**
 150      * Is the schemaXmlPath class variable a relative path? If set to true the schemaXmlPath variable contains a path
 151      * relative to the component's back-end directory. If set to false the schemaXmlPath variable contains an absolute
 152      * filesystem path.
 153      *
 154      * @var   boolean
 155      */
 156     protected $schemaXmlPathRelative = true;
 157 
 158     /**
 159      * The path where the schema XML files are stored. Its contents depend on the schemaXmlPathRelative variable above
 160      * true        => schemaXmlPath contains a path relative to the component's back-end directory
 161      * false    => schemaXmlPath contains an absolute filesystem path
 162      *
 163      * @var string
 164      */
 165     protected $schemaXmlPath = 'sql/xml';
 166 
 167     /**
 168      * The minimum PHP version required to install this extension
 169      *
 170      * @var   string
 171      */
 172     protected $minimumPHPVersion = '5.3.3';
 173 
 174     /**
 175      * The minimum Joomla! version required to install this extension
 176      *
 177      * @var   string
 178      */
 179     protected $minimumJoomlaVersion = '2.5.6';
 180 
 181     /**
 182      * The maximum Joomla! version this extension can be installed on
 183      *
 184      * @var   string
 185      */
 186     protected $maximumJoomlaVersion = '3.9.99';
 187 
 188     /**
 189      * Is this the paid version of the extension? This only determines which files / extensions will be removed.
 190      *
 191      * @var   boolean
 192      */
 193     protected $isPaid = false;
 194 
 195     /**
 196      * Post-installation message definitions for Joomla! 3.2 or later.
 197      *
 198      * This array contains the message definitions for the Post-installation Messages component added in Joomla! 3.2 and
 199      * later versions. Each element is also a hashed array. For the keys used in these message definitions please
 200      * @see FOFUtilsInstallscript::addPostInstallationMessage
 201      *
 202      * @var array
 203      */
 204     protected $postInstallationMessages = array();
 205 
 206     /**
 207      * Joomla! pre-flight event. This runs before Joomla! installs or updates the component. This is our last chance to
 208      * tell Joomla! if it should abort the installation.
 209      *
 210      * @param   string     $type   Installation type (install, update, discover_install)
 211      * @param   JInstaller $parent Parent object
 212      *
 213      * @return  boolean  True to let the installation proceed, false to halt the installation
 214      */
 215     public function preflight($type, $parent)
 216     {
 217         // Check the minimum PHP version
 218         if (!empty($this->minimumPHPVersion))
 219         {
 220             if (defined('PHP_VERSION'))
 221             {
 222                 $version = PHP_VERSION;
 223             }
 224             elseif (function_exists('phpversion'))
 225             {
 226                 $version = phpversion();
 227             }
 228             else
 229             {
 230                 $version = '5.0.0'; // all bets are off!
 231             }
 232 
 233             if (!version_compare($version, $this->minimumPHPVersion, 'ge'))
 234             {
 235                 $msg = "<p>You need PHP $this->minimumPHPVersion or later to install this component</p>";
 236 
 237                 if (version_compare(JVERSION, '3.0', 'gt'))
 238                 {
 239                     JLog::add($msg, JLog::WARNING, 'jerror');
 240                 }
 241                 else
 242                 {
 243                     JError::raiseWarning(100, $msg);
 244                 }
 245 
 246                 return false;
 247             }
 248         }
 249 
 250         // Check the minimum Joomla! version
 251         if (!empty($this->minimumJoomlaVersion) && !version_compare(JVERSION, $this->minimumJoomlaVersion, 'ge'))
 252         {
 253             $msg = "<p>You need Joomla! $this->minimumJoomlaVersion or later to install this component</p>";
 254 
 255             if (version_compare(JVERSION, '3.0', 'gt'))
 256             {
 257                 JLog::add($msg, JLog::WARNING, 'jerror');
 258             }
 259             else
 260             {
 261                 JError::raiseWarning(100, $msg);
 262             }
 263 
 264             return false;
 265         }
 266 
 267         // Check the maximum Joomla! version
 268         if (!empty($this->maximumJoomlaVersion) && !version_compare(JVERSION, $this->maximumJoomlaVersion, 'le'))
 269         {
 270             $msg = "<p>You need Joomla! $this->maximumJoomlaVersion or earlier to install this component</p>";
 271 
 272             if (version_compare(JVERSION, '3.0', 'gt'))
 273             {
 274                 JLog::add($msg, JLog::WARNING, 'jerror');
 275             }
 276             else
 277             {
 278                 JError::raiseWarning(100, $msg);
 279             }
 280 
 281             return false;
 282         }
 283 
 284         // Always reset the OPcache if it's enabled. Otherwise there's a good chance the server will not know we are
 285         // replacing .php scripts. This is a major concern since PHP 5.5 included and enabled OPcache by default.
 286         if (function_exists('opcache_reset'))
 287         {
 288             opcache_reset();
 289         }
 290 
 291         // Workarounds for JInstaller issues
 292         if (in_array($type, array('install', 'discover_install')))
 293         {
 294             // Bugfix for "Database function returned no error"
 295             $this->bugfixDBFunctionReturnedNoError();
 296         }
 297         else
 298         {
 299             // Bugfix for "Can not build admin menus"
 300             $this->bugfixCantBuildAdminMenus();
 301         }
 302 
 303         return true;
 304     }
 305 
 306     /**
 307      * Runs after install, update or discover_update. In other words, it executes after Joomla! has finished installing
 308      * or updating your component. This is the last chance you've got to perform any additional installations, clean-up,
 309      * database updates and similar housekeeping functions.
 310      *
 311      * @param   string     $type   install, update or discover_update
 312      * @param   JInstaller $parent Parent object
 313      */
 314     public function postflight($type, $parent)
 315     {
 316         // Install or update database
 317         $dbInstaller = new FOFDatabaseInstaller(array(
 318             'dbinstaller_directory' =>
 319                 ($this->schemaXmlPathRelative ? JPATH_ADMINISTRATOR . '/components/' . $this->componentName : '') . '/' .
 320                 $this->schemaXmlPath
 321         ));
 322         $dbInstaller->updateSchema();
 323 
 324         // Install subextensions
 325         $status = $this->installSubextensions($parent);
 326 
 327         // Install FOF
 328         $fofInstallationStatus = $this->installFOF($parent);
 329 
 330         // Install Akeeba Straper
 331         $strapperInstallationStatus = $this->installStrapper($parent);
 332 
 333         // Make sure menu items are installed
 334         $this->_createAdminMenus($parent);
 335 
 336         // Make sure menu items are published (surprise goal in the 92' by JInstaller wins the cup for "most screwed up
 337         // bug in the history of Joomla!")
 338         $this->_reallyPublishAdminMenuItems($parent);
 339 
 340         // Which files should I remove?
 341         if ($this->isPaid)
 342         {
 343             // This is the paid version, only remove the removeFilesAllVersions files
 344             $removeFiles = $this->removeFilesAllVersions;
 345         }
 346         else
 347         {
 348             // This is the free version, remove the removeFilesAllVersions and removeFilesFree files
 349             $removeFiles = array('files' => array(), 'folders' => array());
 350 
 351             if (isset($this->removeFilesAllVersions['files']))
 352             {
 353                 if (isset($this->removeFilesFree['files']))
 354                 {
 355                     $removeFiles['files'] = array_merge($this->removeFilesAllVersions['files'], $this->removeFilesFree['files']);
 356                 }
 357                 else
 358                 {
 359                     $removeFiles['files'] = $this->removeFilesAllVersions['files'];
 360                 }
 361             }
 362             elseif (isset($this->removeFilesFree['files']))
 363             {
 364                 $removeFiles['files'] = $this->removeFilesFree['files'];
 365             }
 366 
 367             if (isset($this->removeFilesAllVersions['folders']))
 368             {
 369                 if (isset($this->removeFilesFree['folders']))
 370                 {
 371                     $removeFiles['folders'] = array_merge($this->removeFilesAllVersions['folders'], $this->removeFilesFree['folders']);
 372                 }
 373                 else
 374                 {
 375                     $removeFiles['folders'] = $this->removeFilesAllVersions['folders'];
 376                 }
 377             }
 378             elseif (isset($this->removeFilesFree['folders']))
 379             {
 380                 $removeFiles['folders'] = $this->removeFilesFree['folders'];
 381             }
 382         }
 383 
 384         // Remove obsolete files and folders
 385         $this->removeFilesAndFolders($removeFiles);
 386 
 387         // Copy the CLI files (if any)
 388         $this->copyCliFiles($parent);
 389 
 390         // Show the post-installation page
 391         $this->renderPostInstallation($status, $fofInstallationStatus, $strapperInstallationStatus, $parent);
 392 
 393         // Uninstall obsolete subextensions
 394         $uninstall_status = $this->uninstallObsoleteSubextensions($parent);
 395 
 396         // Clear the FOF cache
 397         $platform = FOFPlatform::getInstance();
 398 
 399         if (method_exists($platform, 'clearCache'))
 400         {
 401             FOFPlatform::getInstance()->clearCache();
 402         }
 403 
 404         // Make sure the Joomla! menu structure is correct
 405         $this->_rebuildMenu();
 406 
 407         // Add post-installation messages on Joomla! 3.2 and later
 408         $this->_applyPostInstallationMessages();
 409     }
 410 
 411     /**
 412      * Runs on uninstallation
 413      *
 414      * @param   JInstaller $parent The parent object
 415      */
 416     public function uninstall($parent)
 417     {
 418         // Uninstall database
 419         $dbInstaller = new FOFDatabaseInstaller(array(
 420             'dbinstaller_directory' =>
 421                 ($this->schemaXmlPathRelative ? JPATH_ADMINISTRATOR . '/components/' . $this->componentName : '') . '/' .
 422                 $this->schemaXmlPath
 423         ));
 424         $dbInstaller->removeSchema();
 425 
 426         // Uninstall modules and plugins
 427         $status = $this->uninstallSubextensions($parent);
 428 
 429         // Uninstall post-installation messages on Joomla! 3.2 and later
 430         $this->uninstallPostInstallationMessages();
 431 
 432         // Show the post-uninstallation page
 433         $this->renderPostUninstallation($status, $parent);
 434     }
 435 
 436     /**
 437      * Copies the CLI scripts into Joomla!'s cli directory
 438      *
 439      * @param JInstaller $parent
 440      */
 441     protected function copyCliFiles($parent)
 442     {
 443         $src = $parent->getParent()->getPath('source');
 444 
 445         $cliPath = JPATH_ROOT . '/cli';
 446 
 447         if (!JFolder::exists($cliPath))
 448         {
 449             JFolder::create($cliPath);
 450         }
 451 
 452         foreach ($this->cliScriptFiles as $script)
 453         {
 454             if (JFile::exists($cliPath . '/' . $script))
 455             {
 456                 JFile::delete($cliPath . '/' . $script);
 457             }
 458 
 459             if (JFile::exists($src . '/' . $this->cliSourcePath . '/' . $script))
 460             {
 461                 JFile::copy($src . '/' . $this->cliSourcePath . '/' . $script, $cliPath . '/' . $script);
 462             }
 463         }
 464     }
 465 
 466     /**
 467      * Renders the message after installing or upgrading the component
 468      */
 469     protected function renderPostInstallation($status, $fofInstallationStatus, $strapperInstallationStatus, $parent)
 470     {
 471         $rows = 0;
 472         ?>
 473         <table class="adminlist table table-striped" width="100%">
 474             <thead>
 475             <tr>
 476                 <th class="title" colspan="2">Extension</th>
 477                 <th width="30%">Status</th>
 478             </tr>
 479             </thead>
 480             <tfoot>
 481             <tr>
 482                 <td colspan="3"></td>
 483             </tr>
 484             </tfoot>
 485             <tbody>
 486             <tr class="row<?php echo($rows++ % 2); ?>">
 487                 <td class="key" colspan="2"><?php echo $this->componentTitle ?></td>
 488                 <td><strong style="color: green">Installed</strong></td>
 489             </tr>
 490             <?php if ($fofInstallationStatus['required']): ?>
 491                 <tr class="row<?php echo($rows++ % 2); ?>">
 492                     <td class="key" colspan="2">
 493                         <strong>Framework on Framework (FOF) <?php echo $fofInstallationStatus['version'] ?></strong>
 494                         [<?php echo $fofInstallationStatus['date'] ?>]
 495                     </td>
 496                     <td><strong>
 497                             <span
 498                                 style="color: <?php echo $fofInstallationStatus['required'] ? ($fofInstallationStatus['installed'] ? 'green' : 'red') : '#660' ?>; font-weight: bold;">
 499         <?php echo $fofInstallationStatus['required'] ? ($fofInstallationStatus['installed'] ? 'Installed' : 'Not Installed') : 'Already up-to-date'; ?>
 500                             </span>
 501                         </strong></td>
 502                 </tr>
 503             <?php endif; ?>
 504             <?php if ($strapperInstallationStatus['required']): ?>
 505                 <tr class="row<?php echo($rows++ % 2); ?>">
 506                     <td class="key" colspan="2">
 507                         <strong>Akeeba Strapper <?php echo $strapperInstallationStatus['version'] ?></strong>
 508                         [<?php echo $strapperInstallationStatus['date'] ?>]
 509                     </td>
 510                     <td><strong>
 511                             <span
 512                                 style="color: <?php echo $strapperInstallationStatus['required'] ? ($strapperInstallationStatus['installed'] ? 'green' : 'red') : '#660' ?>; font-weight: bold;">
 513                 <?php echo $strapperInstallationStatus['required'] ? ($strapperInstallationStatus['installed'] ? 'Installed' : 'Not Installed') : 'Already up-to-date'; ?>
 514                             </span>
 515                         </strong></td>
 516                 </tr>
 517             <?php endif; ?>
 518             <?php if (count($status->modules)) : ?>
 519                 <tr>
 520                     <th>Module</th>
 521                     <th>Client</th>
 522                     <th></th>
 523                 </tr>
 524                 <?php foreach ($status->modules as $module) : ?>
 525                     <tr class="row<?php echo($rows++ % 2); ?>">
 526                         <td class="key"><?php echo $module['name']; ?></td>
 527                         <td class="key"><?php echo ucfirst($module['client']); ?></td>
 528                         <td><strong
 529                                 style="color: <?php echo ($module['result']) ? "green" : "red" ?>"><?php echo ($module['result']) ? 'Installed' : 'Not installed'; ?></strong>
 530                         </td>
 531                     </tr>
 532                 <?php endforeach; ?>
 533             <?php endif; ?>
 534             <?php if (count($status->plugins)) : ?>
 535                 <tr>
 536                     <th>Plugin</th>
 537                     <th>Group</th>
 538                     <th></th>
 539                 </tr>
 540                 <?php foreach ($status->plugins as $plugin) : ?>
 541                     <tr class="row<?php echo($rows++ % 2); ?>">
 542                         <td class="key"><?php echo ucfirst($plugin['name']); ?></td>
 543                         <td class="key"><?php echo ucfirst($plugin['group']); ?></td>
 544                         <td><strong
 545                                 style="color: <?php echo ($plugin['result']) ? "green" : "red" ?>"><?php echo ($plugin['result']) ? 'Installed' : 'Not installed'; ?></strong>
 546                         </td>
 547                     </tr>
 548                 <?php endforeach; ?>
 549             <?php endif; ?>
 550             </tbody>
 551         </table>
 552     <?php
 553     }
 554 
 555     /**
 556      * Renders the message after uninstalling the component
 557      */
 558     protected function renderPostUninstallation($status, $parent)
 559     {
 560         $rows = 1;
 561         ?>
 562         <table class="adminlist table table-striped" width="100%">
 563             <thead>
 564             <tr>
 565                 <th class="title" colspan="2"><?php echo JText::_('Extension'); ?></th>
 566                 <th width="30%"><?php echo JText::_('Status'); ?></th>
 567             </tr>
 568             </thead>
 569             <tfoot>
 570             <tr>
 571                 <td colspan="3"></td>
 572             </tr>
 573             </tfoot>
 574             <tbody>
 575             <tr class="row<?php echo($rows++ % 2); ?>">
 576                 <td class="key" colspan="2"><?php echo $this->componentTitle; ?></td>
 577                 <td><strong style="color: green">Removed</strong></td>
 578             </tr>
 579             <?php if (count($status->modules)) : ?>
 580                 <tr>
 581                     <th>Module</th>
 582                     <th>Client</th>
 583                     <th></th>
 584                 </tr>
 585                 <?php foreach ($status->modules as $module) : ?>
 586                     <tr class="row<?php echo($rows++ % 2); ?>">
 587                         <td class="key"><?php echo $module['name']; ?></td>
 588                         <td class="key"><?php echo ucfirst($module['client']); ?></td>
 589                         <td><strong
 590                                 style="color: <?php echo ($module['result']) ? "green" : "red" ?>"><?php echo ($module['result']) ? 'Removed' : 'Not removed'; ?></strong>
 591                         </td>
 592                     </tr>
 593                 <?php endforeach; ?>
 594             <?php endif; ?>
 595             <?php if (count($status->plugins)) : ?>
 596                 <tr>
 597                     <th>Plugin</th>
 598                     <th>Group</th>
 599                     <th></th>
 600                 </tr>
 601                 <?php foreach ($status->plugins as $plugin) : ?>
 602                     <tr class="row<?php echo($rows++ % 2); ?>">
 603                         <td class="key"><?php echo ucfirst($plugin['name']); ?></td>
 604                         <td class="key"><?php echo ucfirst($plugin['group']); ?></td>
 605                         <td><strong
 606                                 style="color: <?php echo ($plugin['result']) ? "green" : "red" ?>"><?php echo ($plugin['result']) ? 'Removed' : 'Not removed'; ?></strong>
 607                         </td>
 608                     </tr>
 609                 <?php endforeach; ?>
 610             <?php endif; ?>
 611             </tbody>
 612         </table>
 613     <?php
 614     }
 615 
 616     /**
 617      * Bugfix for "DB function returned no error"
 618      */
 619     protected function bugfixDBFunctionReturnedNoError()
 620     {
 621         $db = FOFPlatform::getInstance()->getDbo();
 622 
 623         // Fix broken #__assets records
 624         $query = $db->getQuery(true);
 625         $query->select('id')
 626             ->from('#__assets')
 627             ->where($db->qn('name') . ' = ' . $db->q($this->componentName));
 628         $db->setQuery($query);
 629 
 630         try
 631         {
 632             $ids = $db->loadColumn();
 633         }
 634         catch (Exception $exc)
 635         {
 636             return;
 637         }
 638 
 639         if (!empty($ids))
 640         {
 641             foreach ($ids as $id)
 642             {
 643                 $query = $db->getQuery(true);
 644                 $query->delete('#__assets')
 645                     ->where($db->qn('id') . ' = ' . $db->q($id));
 646                 $db->setQuery($query);
 647 
 648                 try
 649                 {
 650                     $db->execute();
 651                 }
 652                 catch (Exception $exc)
 653                 {
 654                     // Nothing
 655                 }
 656             }
 657         }
 658 
 659         // Fix broken #__extensions records
 660         $query = $db->getQuery(true);
 661         $query->select('extension_id')
 662             ->from('#__extensions')
 663             ->where($db->qn('type') . ' = ' . $db->q('component'))
 664             ->where($db->qn('element') . ' = ' . $db->q($this->componentName));
 665         $db->setQuery($query);
 666         $ids = $db->loadColumn();
 667 
 668         if (!empty($ids))
 669         {
 670             foreach ($ids as $id)
 671             {
 672                 $query = $db->getQuery(true);
 673                 $query->delete('#__extensions')
 674                     ->where($db->qn('extension_id') . ' = ' . $db->q($id));
 675                 $db->setQuery($query);
 676 
 677                 try
 678                 {
 679                     $db->execute();
 680                 }
 681                 catch (Exception $exc)
 682                 {
 683                     // Nothing
 684                 }
 685             }
 686         }
 687 
 688         // Fix broken #__menu records
 689         $query = $db->getQuery(true);
 690         $query->select('id')
 691             ->from('#__menu')
 692             ->where($db->qn('type') . ' = ' . $db->q('component'))
 693             ->where($db->qn('menutype') . ' = ' . $db->q('main'))
 694             ->where($db->qn('link') . ' LIKE ' . $db->q('index.php?option=' . $this->componentName));
 695         $db->setQuery($query);
 696         $ids = $db->loadColumn();
 697 
 698         if (!empty($ids))
 699         {
 700             foreach ($ids as $id)
 701             {
 702                 $query = $db->getQuery(true);
 703                 $query->delete('#__menu')
 704                     ->where($db->qn('id') . ' = ' . $db->q($id));
 705                 $db->setQuery($query);
 706 
 707                 try
 708                 {
 709                     $db->execute();
 710                 }
 711                 catch (Exception $exc)
 712                 {
 713                     // Nothing
 714                 }
 715             }
 716         }
 717     }
 718 
 719     /**
 720      * Joomla! 1.6+ bugfix for "Can not build admin menus"
 721      */
 722     protected function bugfixCantBuildAdminMenus()
 723     {
 724         $db = FOFPlatform::getInstance()->getDbo();
 725 
 726         // If there are multiple #__extensions record, keep one of them
 727         $query = $db->getQuery(true);
 728         $query->select('extension_id')
 729             ->from('#__extensions')
 730             ->where($db->qn('type') . ' = ' . $db->q('component'))
 731             ->where($db->qn('element') . ' = ' . $db->q($this->componentName));
 732         $db->setQuery($query);
 733 
 734         try
 735         {
 736             $ids = $db->loadColumn();
 737         }
 738         catch (Exception $exc)
 739         {
 740             return;
 741         }
 742 
 743 
 744         if (count($ids) > 1)
 745         {
 746             asort($ids);
 747             $extension_id = array_shift($ids); // Keep the oldest id
 748 
 749             foreach ($ids as $id)
 750             {
 751                 $query = $db->getQuery(true);
 752                 $query->delete('#__extensions')
 753                     ->where($db->qn('extension_id') . ' = ' . $db->q($id));
 754                 $db->setQuery($query);
 755 
 756                 try
 757                 {
 758                     $db->execute();
 759                 }
 760                 catch (Exception $exc)
 761                 {
 762                     // Nothing
 763                 }
 764             }
 765         }
 766 
 767         // If there are multiple assets records, delete all except the oldest one
 768         $query = $db->getQuery(true);
 769         $query->select('id')
 770             ->from('#__assets')
 771             ->where($db->qn('name') . ' = ' . $db->q($this->componentName));
 772         $db->setQuery($query);
 773         $ids = $db->loadObjectList();
 774 
 775         if (count($ids) > 1)
 776         {
 777             asort($ids);
 778             $asset_id = array_shift($ids); // Keep the oldest id
 779 
 780             foreach ($ids as $id)
 781             {
 782                 $query = $db->getQuery(true);
 783                 $query->delete('#__assets')
 784                     ->where($db->qn('id') . ' = ' . $db->q($id));
 785                 $db->setQuery($query);
 786 
 787                 try
 788                 {
 789                     $db->execute();
 790                 }
 791                 catch (Exception $exc)
 792                 {
 793                     // Nothing
 794                 }
 795             }
 796         }
 797 
 798         // Remove #__menu records for good measure! –– I think this is not necessary and causes the menu item to
 799         // disappear on extension update.
 800         /**
 801         $query = $db->getQuery(true);
 802         $query->select('id')
 803             ->from('#__menu')
 804             ->where($db->qn('type') . ' = ' . $db->q('component'))
 805             ->where($db->qn('menutype') . ' = ' . $db->q('main'))
 806             ->where($db->qn('link') . ' LIKE ' . $db->q('index.php?option=' . $this->componentName));
 807         $db->setQuery($query);
 808 
 809         try
 810         {
 811             $ids1 = $db->loadColumn();
 812         }
 813         catch (Exception $exc)
 814         {
 815             $ids1 = array();
 816         }
 817 
 818         if (empty($ids1))
 819         {
 820             $ids1 = array();
 821         }
 822 
 823         $query = $db->getQuery(true);
 824         $query->select('id')
 825             ->from('#__menu')
 826             ->where($db->qn('type') . ' = ' . $db->q('component'))
 827             ->where($db->qn('menutype') . ' = ' . $db->q('main'))
 828             ->where($db->qn('link') . ' LIKE ' . $db->q('index.php?option=' . $this->componentName . '&%'));
 829         $db->setQuery($query);
 830 
 831         try
 832         {
 833             $ids2 = $db->loadColumn();
 834         }
 835         catch (Exception $exc)
 836         {
 837             $ids2 = array();
 838         }
 839 
 840         if (empty($ids2))
 841         {
 842             $ids2 = array();
 843         }
 844 
 845         $ids = array_merge($ids1, $ids2);
 846 
 847         if (!empty($ids))
 848         {
 849             foreach ($ids as $id)
 850             {
 851                 $query = $db->getQuery(true);
 852                 $query->delete('#__menu')
 853                     ->where($db->qn('id') . ' = ' . $db->q($id));
 854                 $db->setQuery($query);
 855 
 856                 try
 857                 {
 858                     $db->execute();
 859                 }
 860                 catch (Exception $exc)
 861                 {
 862                     // Nothing
 863                 }
 864             }
 865         }
 866         /**/
 867     }
 868 
 869     /**
 870      * Installs subextensions (modules, plugins) bundled with the main extension
 871      *
 872      * @param JInstaller $parent
 873      *
 874      * @return JObject The subextension installation status
 875      */
 876     protected function installSubextensions($parent)
 877     {
 878         $src = $parent->getParent()->getPath('source');
 879 
 880         $db = FOFPlatform::getInstance()->getDbo();;
 881 
 882         $status = new JObject();
 883         $status->modules = array();
 884         $status->plugins = array();
 885 
 886         // Modules installation
 887         if (isset($this->installation_queue['modules']) && count($this->installation_queue['modules']))
 888         {
 889             foreach ($this->installation_queue['modules'] as $folder => $modules)
 890             {
 891                 if (count($modules))
 892                 {
 893                     foreach ($modules as $module => $modulePreferences)
 894                     {
 895                         // Install the module
 896                         if (empty($folder))
 897                         {
 898                             $folder = 'site';
 899                         }
 900 
 901                         $path = "$src/" . $this->modulesSourcePath . "/$folder/$module";
 902 
 903                         if (!is_dir($path))
 904                         {
 905                             $path = "$src/" . $this->modulesSourcePath . "/$folder/mod_$module";
 906                         }
 907 
 908                         if (!is_dir($path))
 909                         {
 910                             $path = "$src/" . $this->modulesSourcePath . "/$module";
 911                         }
 912 
 913                         if (!is_dir($path))
 914                         {
 915                             $path = "$src/" . $this->modulesSourcePath . "/mod_$module";
 916                         }
 917 
 918                         if (!is_dir($path))
 919                         {
 920                             continue;
 921                         }
 922 
 923                         // Was the module already installed?
 924                         $sql = $db->getQuery(true)
 925                             ->select('COUNT(*)')
 926                             ->from('#__modules')
 927                             ->where($db->qn('module') . ' = ' . $db->q('mod_' . $module));
 928                         $db->setQuery($sql);
 929 
 930                         try
 931                         {
 932                             $count = $db->loadResult();
 933                         }
 934                         catch (Exception $exc)
 935                         {
 936                             $count = 0;
 937                         }
 938 
 939                         $installer = new JInstaller;
 940                         $result = $installer->install($path);
 941                         $status->modules[] = array(
 942                             'name'   => 'mod_' . $module,
 943                             'client' => $folder,
 944                             'result' => $result
 945                         );
 946 
 947                         // Modify where it's published and its published state
 948                         if (!$count)
 949                         {
 950                             // A. Position and state
 951                             list($modulePosition, $modulePublished) = $modulePreferences;
 952 
 953                             $sql = $db->getQuery(true)
 954                                 ->update($db->qn('#__modules'))
 955                                 ->set($db->qn('position') . ' = ' . $db->q($modulePosition))
 956                                 ->where($db->qn('module') . ' = ' . $db->q('mod_' . $module));
 957 
 958                             if ($modulePublished)
 959                             {
 960                                 $sql->set($db->qn('published') . ' = ' . $db->q('1'));
 961                             }
 962 
 963                             $db->setQuery($sql);
 964 
 965                             try
 966                             {
 967                                 $db->execute();
 968                             }
 969                             catch (Exception $exc)
 970                             {
 971                                 // Nothing
 972                             }
 973 
 974                             // B. Change the ordering of back-end modules to 1 + max ordering
 975                             if ($folder == 'admin')
 976                             {
 977                                 try
 978                                 {
 979                                     $query = $db->getQuery(true);
 980                                     $query->select('MAX(' . $db->qn('ordering') . ')')
 981                                         ->from($db->qn('#__modules'))
 982                                         ->where($db->qn('position') . '=' . $db->q($modulePosition));
 983                                     $db->setQuery($query);
 984                                     $position = $db->loadResult();
 985                                     $position++;
 986 
 987                                     $query = $db->getQuery(true);
 988                                     $query->update($db->qn('#__modules'))
 989                                         ->set($db->qn('ordering') . ' = ' . $db->q($position))
 990                                         ->where($db->qn('module') . ' = ' . $db->q('mod_' . $module));
 991                                     $db->setQuery($query);
 992                                     $db->execute();
 993                                 }
 994                                 catch (Exception $exc)
 995                                 {
 996                                     // Nothing
 997                                 }
 998                             }
 999 
1000                             // C. Link to all pages
1001                             try
1002                             {
1003                                 $query = $db->getQuery(true);
1004                                 $query->select('id')->from($db->qn('#__modules'))
1005                                     ->where($db->qn('module') . ' = ' . $db->q('mod_' . $module));
1006                                 $db->setQuery($query);
1007                                 $moduleid = $db->loadResult();
1008 
1009                                 $query = $db->getQuery(true);
1010                                 $query->select('*')->from($db->qn('#__modules_menu'))
1011                                     ->where($db->qn('moduleid') . ' = ' . $db->q($moduleid));
1012                                 $db->setQuery($query);
1013                                 $assignments = $db->loadObjectList();
1014                                 $isAssigned = !empty($assignments);
1015 
1016                                 if (!$isAssigned)
1017                                 {
1018                                     $o = (object)array(
1019                                         'moduleid' => $moduleid,
1020                                         'menuid'   => 0
1021                                     );
1022                                     $db->insertObject('#__modules_menu', $o);
1023                                 }
1024                             }
1025                             catch (Exception $exc)
1026                             {
1027                                 // Nothing
1028                             }
1029                         }
1030                     }
1031                 }
1032             }
1033         }
1034 
1035         // Plugins installation
1036         if (isset($this->installation_queue['plugins']) && count($this->installation_queue['plugins']))
1037         {
1038             foreach ($this->installation_queue['plugins'] as $folder => $plugins)
1039             {
1040                 if (count($plugins))
1041                 {
1042                     foreach ($plugins as $plugin => $published)
1043                     {
1044                         $path = "$src/" . $this->pluginsSourcePath . "/$folder/$plugin";
1045 
1046                         if (!is_dir($path))
1047                         {
1048                             $path = "$src/" . $this->pluginsSourcePath . "/$folder/plg_$plugin";
1049                         }
1050 
1051                         if (!is_dir($path))
1052                         {
1053                             $path = "$src/" . $this->pluginsSourcePath . "/$plugin";
1054                         }
1055 
1056                         if (!is_dir($path))
1057                         {
1058                             $path = "$src/" . $this->pluginsSourcePath . "/plg_$plugin";
1059                         }
1060 
1061                         if (!is_dir($path))
1062                         {
1063                             continue;
1064                         }
1065 
1066                         // Was the plugin already installed?
1067                         $query = $db->getQuery(true)
1068                             ->select('COUNT(*)')
1069                             ->from($db->qn('#__extensions'))
1070                             ->where($db->qn('element') . ' = ' . $db->q($plugin))
1071                             ->where($db->qn('folder') . ' = ' . $db->q($folder));
1072                         $db->setQuery($query);
1073 
1074                         try
1075                         {
1076                             $count = $db->loadResult();
1077                         }
1078                         catch (Exception $exc)
1079                         {
1080                             $count = 0;
1081                         }
1082 
1083                         $installer = new JInstaller;
1084                         $result = $installer->install($path);
1085 
1086                         $status->plugins[] = array('name' => 'plg_' . $plugin, 'group' => $folder, 'result' => $result);
1087 
1088                         if ($published && !$count)
1089                         {
1090                             $query = $db->getQuery(true)
1091                                 ->update($db->qn('#__extensions'))
1092                                 ->set($db->qn('enabled') . ' = ' . $db->q('1'))
1093                                 ->where($db->qn('element') . ' = ' . $db->q($plugin))
1094                                 ->where($db->qn('folder') . ' = ' . $db->q($folder));
1095                             $db->setQuery($query);
1096 
1097                             try
1098                             {
1099                                 $db->execute();
1100                             }
1101                             catch (Exception $exc)
1102                             {
1103                                 // Nothing
1104                             }
1105                         }
1106                     }
1107                 }
1108             }
1109         }
1110 
1111         // Clear com_modules and com_plugins cache (needed when we alter module/plugin state)
1112         FOFUtilsCacheCleaner::clearPluginsAndModulesCache();
1113 
1114         return $status;
1115     }
1116 
1117     /**
1118      * Uninstalls subextensions (modules, plugins) bundled with the main extension
1119      *
1120      * @param   JInstaller $parent The parent object
1121      *
1122      * @return  stdClass  The subextension uninstallation status
1123      */
1124     protected function uninstallSubextensions($parent)
1125     {
1126         $db = FOFPlatform::getInstance()->getDbo();
1127 
1128         $status = new stdClass();
1129         $status->modules = array();
1130         $status->plugins = array();
1131 
1132         $src = $parent->getParent()->getPath('source');
1133 
1134         // Modules uninstallation
1135         if (isset($this->installation_queue['modules']) && count($this->installation_queue['modules']))
1136         {
1137             foreach ($this->installation_queue['modules'] as $folder => $modules)
1138             {
1139                 if (count($modules))
1140                 {
1141                     foreach ($modules as $module => $modulePreferences)
1142                     {
1143                         // Find the module ID
1144                         $sql = $db->getQuery(true)
1145                             ->select($db->qn('extension_id'))
1146                             ->from($db->qn('#__extensions'))
1147                             ->where($db->qn('element') . ' = ' . $db->q('mod_' . $module))
1148                             ->where($db->qn('type') . ' = ' . $db->q('module'));
1149                         $db->setQuery($sql);
1150 
1151                         try
1152                         {
1153                             $id = $db->loadResult();
1154                         }
1155                         catch (Exception $exc)
1156                         {
1157                             $id = 0;
1158                         }
1159 
1160                         // Uninstall the module
1161                         if ($id)
1162                         {
1163                             $installer = new JInstaller;
1164                             $result = $installer->uninstall('module', $id, 1);
1165                             $status->modules[] = array(
1166                                 'name'   => 'mod_' . $module,
1167                                 'client' => $folder,
1168                                 'result' => $result
1169                             );
1170                         }
1171                     }
1172                 }
1173             }
1174         }
1175 
1176         // Plugins uninstallation
1177         if (isset($this->installation_queue['plugins']) && count($this->installation_queue['plugins']))
1178         {
1179             foreach ($this->installation_queue['plugins'] as $folder => $plugins)
1180             {
1181                 if (count($plugins))
1182                 {
1183                     foreach ($plugins as $plugin => $published)
1184                     {
1185                         $sql = $db->getQuery(true)
1186                             ->select($db->qn('extension_id'))
1187                             ->from($db->qn('#__extensions'))
1188                             ->where($db->qn('type') . ' = ' . $db->q('plugin'))
1189                             ->where($db->qn('element') . ' = ' . $db->q($plugin))
1190                             ->where($db->qn('folder') . ' = ' . $db->q($folder));
1191                         $db->setQuery($sql);
1192 
1193                         try
1194                         {
1195                             $id = $db->loadResult();
1196                         }
1197                         catch (Exception $exc)
1198                         {
1199                             $id = 0;
1200                         }
1201 
1202                         if ($id)
1203                         {
1204                             $installer = new JInstaller;
1205                             $result = $installer->uninstall('plugin', $id, 1);
1206                             $status->plugins[] = array(
1207                                 'name'   => 'plg_' . $plugin,
1208                                 'group'  => $folder,
1209                                 'result' => $result
1210                             );
1211                         }
1212                     }
1213                 }
1214             }
1215         }
1216 
1217         // Clear com_modules and com_plugins cache (needed when we alter module/plugin state)
1218         FOFUtilsCacheCleaner::clearPluginsAndModulesCache();
1219 
1220         return $status;
1221     }
1222 
1223     /**
1224      * Removes obsolete files and folders
1225      *
1226      * @param   array $removeList The files and directories to remove
1227      */
1228     protected function removeFilesAndFolders($removeList)
1229     {
1230         // Remove files
1231         if (isset($removeList['files']) && !empty($removeList['files']))
1232         {
1233             foreach ($removeList['files'] as $file)
1234             {
1235                 $f = JPATH_ROOT . '/' . $file;
1236 
1237                 if (!JFile::exists($f))
1238                 {
1239                     continue;
1240                 }
1241 
1242                 JFile::delete($f);
1243             }
1244         }
1245 
1246         // Remove folders
1247         if (isset($removeList['folders']) && !empty($removeList['folders']))
1248         {
1249             foreach ($removeList['folders'] as $folder)
1250             {
1251                 $f = JPATH_ROOT . '/' . $folder;
1252 
1253                 if (!JFolder::exists($f))
1254                 {
1255                     continue;
1256                 }
1257 
1258                 JFolder::delete($f);
1259             }
1260         }
1261     }
1262 
1263     /**
1264      * Installs FOF if necessary
1265      *
1266      * @param   JInstaller $parent The parent object
1267      *
1268      * @return  array  The installation status
1269      */
1270     protected function installFOF($parent)
1271     {
1272         // Get the source path
1273         $src = $parent->getParent()->getPath('source');
1274         $source = $src . '/' . $this->fofSourcePath;
1275 
1276         if (!JFolder::exists($source))
1277         {
1278             return array(
1279                 'required'  => false,
1280                 'installed' => false,
1281                 'version'   => '0.0.0',
1282                 'date'      => '2011-01-01',
1283             );
1284         }
1285 
1286         // Get the target path
1287         if (!defined('JPATH_LIBRARIES'))
1288         {
1289             $target = JPATH_ROOT . '/libraries/f0f';
1290         }
1291         else
1292         {
1293             $target = JPATH_LIBRARIES . '/f0f';
1294         }
1295 
1296         // Do I have to install FOF?
1297         $haveToInstallFOF = false;
1298 
1299         if (!JFolder::exists($target))
1300         {
1301             // FOF is not installed; install now
1302             $haveToInstallFOF = true;
1303         }
1304         else
1305         {
1306             // FOF is already installed; check the version
1307             $fofVersion = array();
1308 
1309             if (JFile::exists($target . '/version.txt'))
1310             {
1311                 $rawData = JFile::read($target . '/version.txt');
1312                 $rawData = ($rawData === false) ? "0.0.0\n2011-01-01\n" : $rawData;
1313                 $info = explode("\n", $rawData);
1314                 $fofVersion['installed'] = array(
1315                     'version' => trim($info[0]),
1316                     'date'    => new JDate(trim($info[1]))
1317                 );
1318             }
1319             else
1320             {
1321                 $fofVersion['installed'] = array(
1322                     'version' => '0.0',
1323                     'date'    => new JDate('2011-01-01')
1324                 );
1325             }
1326 
1327             $rawData = @file_get_contents($source . '/version.txt');
1328             $rawData = ($rawData === false) ? "0.0.0\n2011-01-01\n" : $rawData;
1329             $info = explode("\n", $rawData);
1330 
1331             $fofVersion['package'] = array(
1332                 'version' => trim($info[0]),
1333                 'date'    => new JDate(trim($info[1]))
1334             );
1335 
1336             $haveToInstallFOF = $fofVersion['package']['date']->toUNIX() > $fofVersion['installed']['date']->toUNIX();
1337         }
1338 
1339         $installedFOF = false;
1340 
1341         if ($haveToInstallFOF)
1342         {
1343             $versionSource = 'package';
1344             $installer = new JInstaller;
1345             $installedFOF = $installer->install($source);
1346         }
1347         else
1348         {
1349             $versionSource = 'installed';
1350         }
1351 
1352         if (!isset($fofVersion))
1353         {
1354             $fofVersion = array();
1355 
1356             if (JFile::exists($target . '/version.txt'))
1357             {
1358                 $rawData = @file_get_contents($source . '/version.txt');
1359                 $rawData = ($rawData === false) ? "0.0.0\n2011-01-01\n" : $rawData;
1360                 $info = explode("\n", $rawData);
1361                 $fofVersion['installed'] = array(
1362                     'version' => trim($info[0]),
1363                     'date'    => new JDate(trim($info[1]))
1364                 );
1365             }
1366             else
1367             {
1368                 $fofVersion['installed'] = array(
1369                     'version' => '0.0',
1370                     'date'    => new JDate('2011-01-01')
1371                 );
1372             }
1373 
1374             $rawData = @file_get_contents($source . '/version.txt');
1375             $rawData = ($rawData === false) ? "0.0.0\n2011-01-01\n" : $rawData;
1376             $info = explode("\n", $rawData);
1377 
1378             $fofVersion['package'] = array(
1379                 'version' => trim($info[0]),
1380                 'date'    => new JDate(trim($info[1]))
1381             );
1382 
1383             $versionSource = 'installed';
1384         }
1385 
1386         if (!($fofVersion[$versionSource]['date'] instanceof JDate))
1387         {
1388             $fofVersion[$versionSource]['date'] = new JDate();
1389         }
1390 
1391         return array(
1392             'required'  => $haveToInstallFOF,
1393             'installed' => $installedFOF,
1394             'version'   => $fofVersion[$versionSource]['version'],
1395             'date'      => $fofVersion[$versionSource]['date']->format('Y-m-d'),
1396         );
1397     }
1398 
1399     /**
1400      * Installs Akeeba Strapper if necessary
1401      *
1402      * @param   JInstaller $parent The parent object
1403      *
1404      * @return  array  The installation status
1405      */
1406     protected function installStrapper($parent)
1407     {
1408         $src = $parent->getParent()->getPath('source');
1409         $source = $src . '/' . $this->strapperSourcePath;
1410 
1411         $target = JPATH_ROOT . '/media/akeeba_strapper';
1412 
1413         if (!JFolder::exists($source))
1414         {
1415             return array(
1416                 'required'  => false,
1417                 'installed' => false,
1418                 'version'   => '0.0.0',
1419                 'date'      => '2011-01-01',
1420             );
1421         }
1422 
1423         $haveToInstallStrapper = false;
1424 
1425         if (!JFolder::exists($target))
1426         {
1427             $haveToInstallStrapper = true;
1428         }
1429         else
1430         {
1431             $strapperVersion = array();
1432 
1433             if (JFile::exists($target . '/version.txt'))
1434             {
1435                 $rawData = JFile::read($target . '/version.txt');
1436                 $rawData = ($rawData === false) ? "0.0.0\n2011-01-01\n" : $rawData;
1437                 $info = explode("\n", $rawData);
1438                 $strapperVersion['installed'] = array(
1439                     'version' => trim($info[0]),
1440                     'date'    => new JDate(trim($info[1]))
1441                 );
1442             }
1443             else
1444             {
1445                 $strapperVersion['installed'] = array(
1446                     'version' => '0.0',
1447                     'date'    => new JDate('2011-01-01')
1448                 );
1449             }
1450 
1451             $rawData = JFile::read($source . '/version.txt');
1452             $rawData = ($rawData === false) ? "0.0.0\n2011-01-01\n" : $rawData;
1453             $info = explode("\n", $rawData);
1454             $strapperVersion['package'] = array(
1455                 'version' => trim($info[0]),
1456                 'date'    => new JDate(trim($info[1]))
1457             );
1458 
1459             $haveToInstallStrapper = $strapperVersion['package']['date']->toUNIX() > $strapperVersion['installed']['date']->toUNIX();
1460         }
1461 
1462         $installedStraper = false;
1463 
1464         if ($haveToInstallStrapper)
1465         {
1466             $versionSource = 'package';
1467             $installer = new JInstaller;
1468             $installedStraper = $installer->install($source);
1469         }
1470         else
1471         {
1472             $versionSource = 'installed';
1473         }
1474 
1475         if (!isset($strapperVersion))
1476         {
1477             $strapperVersion = array();
1478 
1479             if (JFile::exists($target . '/version.txt'))
1480             {
1481                 $rawData = JFile::read($target . '/version.txt');
1482                 $rawData = ($rawData === false) ? "0.0.0\n2011-01-01\n" : $rawData;
1483                 $info = explode("\n", $rawData);
1484                 $strapperVersion['installed'] = array(
1485                     'version' => trim($info[0]),
1486                     'date'    => new JDate(trim($info[1]))
1487                 );
1488             }
1489             else
1490             {
1491                 $strapperVersion['installed'] = array(
1492                     'version' => '0.0',
1493                     'date'    => new JDate('2011-01-01')
1494                 );
1495             }
1496 
1497             $rawData = JFile::read($source . '/version.txt');
1498             $rawData = ($rawData === false) ? "0.0.0\n2011-01-01\n" : $rawData;
1499             $info = explode("\n", $rawData);
1500 
1501             $strapperVersion['package'] = array(
1502                 'version' => trim($info[0]),
1503                 'date'    => new JDate(trim($info[1]))
1504             );
1505 
1506             $versionSource = 'installed';
1507         }
1508 
1509         if (!($strapperVersion[$versionSource]['date'] instanceof JDate))
1510         {
1511             $strapperVersion[$versionSource]['date'] = new JDate();
1512         }
1513 
1514         return array(
1515             'required'  => $haveToInstallStrapper,
1516             'installed' => $installedStraper,
1517             'version'   => $strapperVersion[$versionSource]['version'],
1518             'date'      => $strapperVersion[$versionSource]['date']->format('Y-m-d'),
1519         );
1520     }
1521 
1522     /**
1523      * Uninstalls obsolete subextensions (modules, plugins) bundled with the main extension
1524      *
1525      * @param   JInstaller $parent The parent object
1526      *
1527      * @return  stdClass The subextension uninstallation status
1528      */
1529     protected function uninstallObsoleteSubextensions($parent)
1530     {
1531         JLoader::import('joomla.installer.installer');
1532 
1533         $db = FOFPlatform::getInstance()->getDbo();
1534 
1535         $status = new stdClass();
1536         $status->modules = array();
1537         $status->plugins = array();
1538 
1539         $src = $parent->getParent()->getPath('source');
1540 
1541         // Modules uninstallation
1542         if (isset($this->uninstallation_queue['modules']) && count($this->uninstallation_queue['modules']))
1543         {
1544             foreach ($this->uninstallation_queue['modules'] as $folder => $modules)
1545             {
1546                 if (count($modules))
1547                 {
1548                     foreach ($modules as $module)
1549                     {
1550                         // Find the module ID
1551                         $sql = $db->getQuery(true)
1552                             ->select($db->qn('extension_id'))
1553                             ->from($db->qn('#__extensions'))
1554                             ->where($db->qn('element') . ' = ' . $db->q('mod_' . $module))
1555                             ->where($db->qn('type') . ' = ' . $db->q('module'));
1556                         $db->setQuery($sql);
1557                         $id = $db->loadResult();
1558                         // Uninstall the module
1559                         if ($id)
1560                         {
1561                             $installer = new JInstaller;
1562                             $result = $installer->uninstall('module', $id, 1);
1563                             $status->modules[] = array(
1564                                 'name'   => 'mod_' . $module,
1565                                 'client' => $folder,
1566                                 'result' => $result
1567                             );
1568                         }
1569                     }
1570                 }
1571             }
1572         }
1573 
1574         // Plugins uninstallation
1575         if (isset($this->uninstallation_queue['plugins']) && count($this->uninstallation_queue['plugins']))
1576         {
1577             foreach ($this->uninstallation_queue['plugins'] as $folder => $plugins)
1578             {
1579                 if (count($plugins))
1580                 {
1581                     foreach ($plugins as $plugin)
1582                     {
1583                         $sql = $db->getQuery(true)
1584                             ->select($db->qn('extension_id'))
1585                             ->from($db->qn('#__extensions'))
1586                             ->where($db->qn('type') . ' = ' . $db->q('plugin'))
1587                             ->where($db->qn('element') . ' = ' . $db->q($plugin))
1588                             ->where($db->qn('folder') . ' = ' . $db->q($folder));
1589                         $db->setQuery($sql);
1590 
1591                         $id = $db->loadResult();
1592                         if ($id)
1593                         {
1594                             $installer = new JInstaller;
1595                             $result = $installer->uninstall('plugin', $id, 1);
1596                             $status->plugins[] = array(
1597                                 'name'   => 'plg_' . $plugin,
1598                                 'group'  => $folder,
1599                                 'result' => $result
1600                             );
1601                         }
1602                     }
1603                 }
1604             }
1605         }
1606 
1607         return $status;
1608     }
1609 
1610     /**
1611      * @param JInstallerAdapterComponent $parent
1612      *
1613      * @return bool
1614      *
1615      * @throws Exception When the Joomla! menu is FUBAR
1616      */
1617     private function _createAdminMenus($parent)
1618     {
1619         $db = $db = FOFPlatform::getInstance()->getDbo();
1620 
1621         /** @var JTableMenu $table */
1622         $table = JTable::getInstance('menu');
1623         $option = $parent->get('element');
1624 
1625         // If a component exists with this option in the table then we don't need to add menus - check only 'main' menutype
1626         $query = $db->getQuery(true)
1627             ->select('m.id, e.extension_id')
1628             ->from('#__menu AS m')
1629             ->join('LEFT', '#__extensions AS e ON m.component_id = e.extension_id')
1630             ->where('m.parent_id = 1')
1631             ->where('m.client_id = 1')
1632             ->where('m.menutype = ' . $db->q('main'))
1633             ->where($db->qn('e') . '.' . $db->qn('type') . ' = ' . $db->q('component'))
1634             ->where('e.element = ' . $db->quote($option));
1635 
1636         $db->setQuery($query);
1637 
1638         $componentrow = $db->loadObject();
1639 
1640         // Check if menu items exist
1641         if ($componentrow)
1642         {
1643             // @todo Return if the menu item already exists to save some time
1644             //return true;
1645         }
1646 
1647         // Let's find the extension id
1648         $query->clear()
1649             ->select('e.extension_id')
1650             ->from('#__extensions AS e')
1651             ->where('e.type = ' . $db->quote('component'))
1652             ->where('e.element = ' . $db->quote($option));
1653         $db->setQuery($query);
1654         $component_id = $db->loadResult();
1655 
1656         // Ok, now its time to handle the menus.  Start with the component root menu, then handle submenus.
1657         $menuElement = $parent->get('manifest')->administration->menu;
1658 
1659         // We need to insert the menu item as the last child of Joomla!'s menu root node. By default this is the
1660         // menu item with ID=1. However, some crappy upgrade scripts enjoy screwing it up. Hey, ho, the workaround
1661         // way I go.
1662         $query = $db->getQuery(true)
1663             ->select($db->qn('id'))
1664             ->from($db->qn('#__menu'))
1665             ->where($db->qn('id') . ' = ' . $db->q(1));
1666         $rootItemId = $db->setQuery($query)->loadResult();
1667 
1668         if (is_null($rootItemId))
1669         {
1670             // Guess what? The Problem has happened. Let's find the root node by title.
1671             $rootItemId = null;
1672             $query = $db->getQuery(true)
1673                 ->select($db->qn('id'))
1674                 ->from($db->qn('#__menu'))
1675                 ->where($db->qn('title') . ' = ' . $db->q('Menu_Item_Root'));
1676             $rootItemId = $db->setQuery($query, 0, 1)->loadResult();
1677         }
1678 
1679         if (is_null($rootItemId))
1680         {
1681             // For crying out loud, did that idiot changed the title too?! Let's find it by alias.
1682             $rootItemId = null;
1683             $query = $db->getQuery(true)
1684                 ->select($db->qn('id'))
1685                 ->from($db->qn('#__menu'))
1686                 ->where($db->qn('alias') . ' = ' . $db->q('root'));
1687             $rootItemId = $db->setQuery($query, 0, 1)->loadResult();
1688         }
1689 
1690         if (is_null($rootItemId))
1691         {
1692             // Dude. Dude! Duuuuuuude! The alias is screwed up, too?! Find it by component ID.
1693             $rootItemId = null;
1694             $query = $db->getQuery(true)
1695                 ->select($db->qn('id'))
1696                 ->from($db->qn('#__menu'))
1697                 ->where($db->qn('component_id') . ' = ' . $db->q('0'));
1698             $rootItemId = $db->setQuery($query, 0, 1)->loadResult();
1699         }
1700 
1701         if (is_null($rootItemId))
1702         {
1703             // Your site is more of a "shite" than a "site". Let's try with minimum lft value.
1704             $rootItemId = null;
1705             $query = $db->getQuery(true)
1706                 ->select($db->qn('id'))
1707                 ->from($db->qn('#__menu'))
1708                 ->order($db->qn('lft') . ' ASC');
1709             $rootItemId = $db->setQuery($query, 0, 1)->loadResult();
1710         }
1711 
1712         if (is_null($rootItemId))
1713         {
1714             // I quit. Your site is broken. What the hell are you doing with it? I'll just throw an error.
1715             throw new Exception("Your site is broken. There is no root menu item. As a result it is impossible to create menu items. The installation of this component has failed. Please fix your database and retry!", 500);
1716         }
1717 
1718         if ($menuElement)
1719         {
1720             $data = array();
1721             $data['menutype'] = 'main';
1722             $data['client_id'] = 1;
1723             $data['title'] = (string)trim($menuElement);
1724             $data['alias'] = (string)$menuElement;
1725             $data['link'] = 'index.php?option=' . $option;
1726             $data['type'] = 'component';
1727             $data['published'] = 0;
1728             $data['parent_id'] = 1;
1729             $data['component_id'] = $component_id;
1730             $data['img'] = ((string)$menuElement->attributes()->img) ? (string)$menuElement->attributes()->img : 'class:component';
1731             $data['home'] = 0;
1732             $data['path'] = '';
1733             $data['params'] = '';
1734         }
1735         // No menu element was specified, Let's make a generic menu item
1736         else
1737         {
1738             $data = array();
1739             $data['menutype'] = 'main';
1740             $data['client_id'] = 1;
1741             $data['title'] = $option;
1742             $data['alias'] = $option;
1743             $data['link'] = 'index.php?option=' . $option;
1744             $data['type'] = 'component';
1745             $data['published'] = 0;
1746             $data['parent_id'] = 1;
1747             $data['component_id'] = $component_id;
1748             $data['img'] = 'class:component';
1749             $data['home'] = 0;
1750             $data['path'] = '';
1751             $data['params'] = '';
1752         }
1753 
1754         try
1755         {
1756             $table->setLocation($rootItemId, 'last-child');
1757         }
1758         catch (InvalidArgumentException $e)
1759         {
1760             if (class_exists('JLog'))
1761             {
1762                 JLog::add($e->getMessage(), JLog::WARNING, 'jerror');
1763             }
1764 
1765             return false;
1766         }
1767 
1768         if (!$table->bind($data) || !$table->check() || !$table->store())
1769         {
1770             // The menu item already exists. Delete it and retry instead of throwing an error.
1771             $query->clear()
1772                 ->select('id')
1773                 ->from('#__menu')
1774                 ->where('menutype = ' . $db->quote('main'))
1775                 ->where('client_id = 1')
1776                 ->where('link = ' . $db->quote('index.php?option=' . $option))
1777                 ->where('type = ' . $db->quote('component'))
1778                 ->where('parent_id = 1')
1779                 ->where('home = 0');
1780 
1781             $db->setQuery($query);
1782             $menu_ids_level1 = $db->loadColumn();
1783 
1784             if (empty($menu_ids_level1))
1785             {
1786                 // Oops! Could not get the menu ID. Go back and rollback changes.
1787                 JError::raiseWarning(1, $table->getError());
1788 
1789                 return false;
1790             }
1791             else
1792             {
1793                 $ids = implode(',', $menu_ids_level1);
1794 
1795                 $query->clear()
1796                     ->select('id')
1797                     ->from('#__menu')
1798                     ->where('menutype = ' . $db->quote('main'))
1799                     ->where('client_id = 1')
1800                     ->where('type = ' . $db->quote('component'))
1801                     ->where('parent_id in (' . $ids . ')')
1802                     ->where('level = 2')
1803                     ->where('home = 0');
1804 
1805                 $db->setQuery($query);
1806                 $menu_ids_level2 = $db->loadColumn();
1807 
1808                 $ids = implode(',', array_merge($menu_ids_level1, $menu_ids_level2));
1809 
1810                 // Remove the old menu item
1811                 $query->clear()
1812                     ->delete('#__menu')
1813                     ->where('id in (' . $ids . ')');
1814 
1815                 $db->setQuery($query);
1816                 $db->query();
1817 
1818                 // Retry creating the menu item
1819                 $table->setLocation($rootItemId, 'last-child');
1820 
1821                 if (!$table->bind($data) || !$table->check() || !$table->store())
1822                 {
1823                     // Install failed, warn user and rollback changes
1824                     JError::raiseWarning(1, $table->getError());
1825 
1826                     return false;
1827                 }
1828             }
1829         }
1830 
1831         /*
1832          * Since we have created a menu item, we add it to the installation step stack
1833          * so that if we have to rollback the changes we can undo it.
1834          */
1835         $parent->getParent()->pushStep(array('type' => 'menu', 'id' => $component_id));
1836 
1837         /*
1838          * Process SubMenus
1839          */
1840 
1841         if (!$parent->get('manifest')->administration->submenu)
1842         {
1843             return true;
1844         }
1845 
1846         $parent_id = $table->id;
1847 
1848         foreach ($parent->get('manifest')->administration->submenu->menu as $child)
1849         {
1850             $data = array();
1851             $data['menutype'] = 'main';
1852             $data['client_id'] = 1;
1853             $data['title'] = (string)trim($child);
1854             $data['alias'] = (string)$child;
1855             $data['type'] = 'component';
1856             $data['published'] = 0;
1857             $data['parent_id'] = $parent_id;
1858             $data['component_id'] = $component_id;
1859             $data['img'] = ((string)$child->attributes()->img) ? (string)$child->attributes()->img : 'class:component';
1860             $data['home'] = 0;
1861 
1862             // Set the sub menu link
1863             if ((string)$child->attributes()->link)
1864             {
1865                 $data['link'] = 'index.php?' . $child->attributes()->link;
1866             }
1867             else
1868             {
1869                 $request = array();
1870 
1871                 if ((string)$child->attributes()->act)
1872                 {
1873                     $request[] = 'act=' . $child->attributes()->act;
1874                 }
1875 
1876                 if ((string)$child->attributes()->task)
1877                 {
1878                     $request[] = 'task=' . $child->attributes()->task;
1879                 }
1880 
1881                 if ((string)$child->attributes()->controller)
1882                 {
1883                     $request[] = 'controller=' . $child->attributes()->controller;
1884                 }
1885 
1886                 if ((string)$child->attributes()->view)
1887                 {
1888                     $request[] = 'view=' . $child->attributes()->view;
1889                 }
1890 
1891                 if ((string)$child->attributes()->layout)
1892                 {
1893                     $request[] = 'layout=' . $child->attributes()->layout;
1894                 }
1895 
1896                 if ((string)$child->attributes()->sub)
1897                 {
1898                     $request[] = 'sub=' . $child->attributes()->sub;
1899                 }
1900 
1901                 $qstring = (count($request)) ? '&' . implode('&', $request) : '';
1902                 $data['link'] = 'index.php?option=' . $option . $qstring;
1903             }
1904 
1905             $table = JTable::getInstance('menu');
1906 
1907             try
1908             {
1909                 $table->setLocation($parent_id, 'last-child');
1910             }
1911             catch (InvalidArgumentException $e)
1912             {
1913                 return false;
1914             }
1915 
1916             if (!$table->bind($data) || !$table->check() || !$table->store())
1917             {
1918                 // Install failed, rollback changes
1919                 return false;
1920             }
1921 
1922             /*
1923              * Since we have created a menu item, we add it to the installation step stack
1924              * so that if we have to rollback the changes we can undo it.
1925              */
1926             $parent->getParent()->pushStep(array('type' => 'menu', 'id' => $component_id));
1927         }
1928 
1929         return true;
1930     }
1931 
1932     /**
1933      * Make sure the Component menu items are really published!
1934      *
1935      * @param JInstallerAdapterComponent $parent
1936      *
1937      * @return bool
1938      */
1939     private function _reallyPublishAdminMenuItems($parent)
1940     {
1941         $db = FOFPlatform::getInstance()->getDbo();
1942 
1943         $option = $parent->get('element');
1944 
1945         $query = $db->getQuery(true)
1946             ->update('#__menu AS m')
1947             ->join('LEFT', '#__extensions AS e ON m.component_id = e.extension_id')
1948             ->set($db->qn('published') . ' = ' . $db->q(1))
1949             ->where('m.parent_id = 1')
1950             ->where('m.client_id = 1')
1951             ->where('m.menutype = ' . $db->quote('main'))
1952             ->where('e.type = ' . $db->quote('component'))
1953             ->where('e.element = ' . $db->quote($option));
1954 
1955         $db->setQuery($query);
1956 
1957         try
1958         {
1959             $db->execute();
1960         }
1961         catch (Exception $e)
1962         {
1963             // If it fails, it fails. Who cares.
1964         }
1965     }
1966 
1967     /**
1968      * Tells Joomla! to rebuild its menu structure to make triple-sure that the Components menu items really do exist
1969      * in the correct place and can really be rendered.
1970      */
1971     private function _rebuildMenu()
1972     {
1973         /** @var JTableMenu $table */
1974         $table = JTable::getInstance('menu');
1975         $db = FOFPlatform::getInstance()->getDbo();
1976 
1977         // We need to rebuild the menu based on its root item. By default this is the menu item with ID=1. However, some
1978         // crappy upgrade scripts enjoy screwing it up. Hey, ho, the workaround way I go.
1979         $query = $db->getQuery(true)
1980             ->select($db->qn('id'))
1981             ->from($db->qn('#__menu'))
1982             ->where($db->qn('id') . ' = ' . $db->q(1));
1983         $rootItemId = $db->setQuery($query)->loadResult();
1984 
1985         if (is_null($rootItemId))
1986         {
1987             // Guess what? The Problem has happened. Let's find the root node by title.
1988             $rootItemId = null;
1989             $query = $db->getQuery(true)
1990                 ->select($db->qn('id'))
1991                 ->from($db->qn('#__menu'))
1992                 ->where($db->qn('title') . ' = ' . $db->q('Menu_Item_Root'));
1993             $rootItemId = $db->setQuery($query, 0, 1)->loadResult();
1994         }
1995 
1996         if (is_null($rootItemId))
1997         {
1998             // For crying out loud, did that idiot changed the title too?! Let's find it by alias.
1999             $rootItemId = null;
2000             $query = $db->getQuery(true)
2001                 ->select($db->qn('id'))
2002                 ->from($db->qn('#__menu'))
2003                 ->where($db->qn('alias') . ' = ' . $db->q('root'));
2004             $rootItemId = $db->setQuery($query, 0, 1)->loadResult();
2005         }
2006 
2007         if (is_null($rootItemId))
2008         {
2009             // Dude. Dude! Duuuuuuude! The alias is screwed up, too?! Find it by component ID.
2010             $rootItemId = null;
2011             $query = $db->getQuery(true)
2012                 ->select($db->qn('id'))
2013                 ->from($db->qn('#__menu'))
2014                 ->where($db->qn('component_id') . ' = ' . $db->q('0'));
2015             $rootItemId = $db->setQuery($query, 0, 1)->loadResult();
2016         }
2017 
2018         if (is_null($rootItemId))
2019         {
2020             // Your site is more of a "shite" than a "site". Let's try with minimum lft value.
2021             $rootItemId = null;
2022             $query = $db->getQuery(true)
2023                 ->select($db->qn('id'))
2024                 ->from($db->qn('#__menu'))
2025                 ->order($db->qn('lft') . ' ASC');
2026             $rootItemId = $db->setQuery($query, 0, 1)->loadResult();
2027         }
2028 
2029         if (is_null($rootItemId))
2030         {
2031             // I quit. Your site is broken.
2032             return false;
2033         }
2034 
2035         $table->rebuild($rootItemId);
2036     }
2037 
2038     /**
2039      * Adds or updates a post-installation message (PIM) definition for Joomla! 3.2 or later. You can use this in your
2040      * post-installation script using this code:
2041      *
2042      * The $options array contains the following mandatory keys:
2043      *
2044      * extension_id        The numeric ID of the extension this message is for (see the #__extensions table)
2045      *
2046      * type                One of message, link or action. Their meaning is:
2047      *                    message        Informative message. The user can dismiss it.
2048      *                    link        The action button links to a URL. The URL is defined in the action parameter.
2049      *                  action      A PHP action takes place when the action button is clicked. You need to specify the
2050      *                              action_file (RAD path to the PHP file) and action (PHP function name) keys. See
2051      *                              below for more information.
2052      *
2053      * title_key        The JText language key for the title of this PIM
2054      *                    Example: COM_FOOBAR_POSTINSTALL_MESSAGEONE_TITLE
2055      *
2056      * description_key    The JText language key for the main body (description) of this PIM
2057      *                    Example: COM_FOOBAR_POSTINSTALL_MESSAGEONE_DESCRIPTION
2058      *
2059      * action_key        The JText language key for the action button. Ignored and not required when type=message
2060      *                    Example: COM_FOOBAR_POSTINSTALL_MESSAGEONE_ACTION
2061      *
2062      * language_extension    The extension name which holds the language keys used above. For example, com_foobar,
2063      *                    mod_something, plg_system_whatever, tpl_mytemplate
2064      *
2065      * language_client_id   Should we load the front-end (0) or back-end (1) language keys?
2066      *
2067      * version_introduced   Which was the version of your extension where this message appeared for the first time?
2068      *                        Example: 3.2.1
2069      *
2070      * enabled              Must be 1 for this message to be enabled. If you omit it, it defaults to 1.
2071      *
2072      * condition_file        The RAD path to a PHP file containing a PHP function which determines whether this message
2073      *                        should be shown to the user. @see FOFTemplateUtils::parsePath() for RAD path format. Joomla!
2074      *                        will include this file before calling the condition_method.
2075      *                      Example:   admin://components/com_foobar/helpers/postinstall.php
2076      *
2077      * condition_method     The name of a PHP function which will be used to determine whether to show this message to
2078      *                      the user. This must be a simple PHP user function (not a class method, static method etc)
2079      *                        which returns true to show the message and false to hide it. This function is defined in the
2080      *                        condition_file.
2081      *                        Example: com_foobar_postinstall_messageone_condition
2082      *
2083      * When type=message no additional keys are required.
2084      *
2085      * When type=link the following additional keys are required:
2086      *
2087      * action                The URL which will open when the user clicks on the PIM's action button
2088      *                        Example:    index.php?option=com_foobar&view=tools&task=installSampleData
2089      *
2090      * Then type=action the following additional keys are required:
2091      *
2092      * action_file            The RAD path to a PHP file containing a PHP function which performs the action of this PIM.
2093      *
2094      * @see                   FOFTemplateUtils::parsePath() for RAD path format. Joomla! will include this file
2095      *                        before calling the function defined in the action key below.
2096      *                        Example:   admin://components/com_foobar/helpers/postinstall.php
2097      *
2098      * action                The name of a PHP function which will be used to run the action of this PIM. This must be a
2099      *                      simple PHP user function (not a class method, static method etc) which returns no result.
2100      *                        Example: com_foobar_postinstall_messageone_action
2101      *
2102      * @param array $options See description
2103      *
2104      * @return  void
2105      *
2106      * @throws Exception
2107      */
2108     protected function addPostInstallationMessage(array $options)
2109     {
2110         // Make sure there are options set
2111         if (!is_array($options))
2112         {
2113             throw new Exception('Post-installation message definitions must be of type array', 500);
2114         }
2115 
2116         // Initialise array keys
2117         $defaultOptions = array(
2118             'extension_id'       => '',
2119             'type'               => '',
2120             'title_key'          => '',
2121             'description_key'    => '',
2122             'action_key'         => '',
2123             'language_extension' => '',
2124             'language_client_id' => '',
2125             'action_file'        => '',
2126             'action'             => '',
2127             'condition_file'     => '',
2128             'condition_method'   => '',
2129             'version_introduced' => '',
2130             'enabled'            => '1',
2131         );
2132 
2133         $options = array_merge($defaultOptions, $options);
2134 
2135         // Array normalisation. Removes array keys not belonging to a definition.
2136         $defaultKeys = array_keys($defaultOptions);
2137         $allKeys = array_keys($options);
2138         $extraKeys = array_diff($allKeys, $defaultKeys);
2139 
2140         if (!empty($extraKeys))
2141         {
2142             foreach ($extraKeys as $key)
2143             {
2144                 unset($options[$key]);
2145             }
2146         }
2147 
2148         // Normalisation of integer values
2149         $options['extension_id'] = (int)$options['extension_id'];
2150         $options['language_client_id'] = (int)$options['language_client_id'];
2151         $options['enabled'] = (int)$options['enabled'];
2152 
2153         // Normalisation of 0/1 values
2154         foreach (array('language_client_id', 'enabled') as $key)
2155         {
2156             $options[$key] = $options[$key] ? 1 : 0;
2157         }
2158 
2159         // Make sure there's an extension_id
2160         if (!(int)$options['extension_id'])
2161         {
2162             throw new Exception('Post-installation message definitions need an extension_id', 500);
2163         }
2164 
2165         // Make sure there's a valid type
2166         if (!in_array($options['type'], array('message', 'link', 'action')))
2167         {
2168             throw new Exception('Post-installation message definitions need to declare a type of message, link or action', 500);
2169         }
2170 
2171         // Make sure there's a title key
2172         if (empty($options['title_key']))
2173         {
2174             throw new Exception('Post-installation message definitions need a title key', 500);
2175         }
2176 
2177         // Make sure there's a description key
2178         if (empty($options['description_key']))
2179         {
2180             throw new Exception('Post-installation message definitions need a description key', 500);
2181         }
2182 
2183         // If the type is anything other than message you need an action key
2184         if (($options['type'] != 'message') && empty($options['action_key']))
2185         {
2186             throw new Exception('Post-installation message definitions need an action key when they are of type "' . $options['type'] . '"', 500);
2187         }
2188 
2189         // You must specify the language extension
2190         if (empty($options['language_extension']))
2191         {
2192             throw new Exception('Post-installation message definitions need to specify which extension contains their language keys', 500);
2193         }
2194 
2195         // The action file and method are only required for the "action" type
2196         if ($options['type'] == 'action')
2197         {
2198             if (empty($options['action_file']))
2199             {
2200                 throw new Exception('Post-installation message definitions need an action file when they are of type "action"', 500);
2201             }
2202 
2203             $file_path = FOFTemplateUtils::parsePath($options['action_file'], true);
2204 
2205             if (!@is_file($file_path))
2206             {
2207                 throw new Exception('The action file ' . $options['action_file'] . ' of your post-installation message definition does not exist', 500);
2208             }
2209 
2210             if (empty($options['action']))
2211             {
2212                 throw new Exception('Post-installation message definitions need an action (function name) when they are of type "action"', 500);
2213             }
2214         }
2215 
2216         if ($options['type'] == 'link')
2217         {
2218             if (empty($options['link']))
2219             {
2220                 throw new Exception('Post-installation message definitions need an action (URL) when they are of type "link"', 500);
2221             }
2222         }
2223 
2224         // The condition file and method are only required when the type is not "message"
2225         if ($options['type'] != 'message')
2226         {
2227             if (empty($options['condition_file']))
2228             {
2229                 throw new Exception('Post-installation message definitions need a condition file when they are of type "' . $options['type'] . '"', 500);
2230             }
2231 
2232             $file_path = FOFTemplateUtils::parsePath($options['condition_file'], true);
2233 
2234             if (!@is_file($file_path))
2235             {
2236                 throw new Exception('The condition file ' . $options['condition_file'] . ' of your post-installation message definition does not exist', 500);
2237             }
2238 
2239             if (empty($options['condition_method']))
2240             {
2241                 throw new Exception('Post-installation message definitions need a condition method (function name) when they are of type "' . $options['type'] . '"', 500);
2242             }
2243         }
2244 
2245         // Check if the definition exists
2246         $tableName = '#__postinstall_messages';
2247 
2248         $db = FOFPlatform::getInstance()->getDbo();
2249         $query = $db->getQuery(true)
2250             ->select('*')
2251             ->from($db->qn($tableName))
2252             ->where($db->qn('extension_id') . ' = ' . $db->q($options['extension_id']))
2253             ->where($db->qn('type') . ' = ' . $db->q($options['type']))
2254             ->where($db->qn('title_key') . ' = ' . $db->q($options['title_key']));
2255         $existingRow = $db->setQuery($query)->loadAssoc();
2256 
2257         // Is the existing definition the same as the one we're trying to save (ignore the enabled flag)?
2258         if (!empty($existingRow))
2259         {
2260             $same = true;
2261 
2262             foreach ($options as $k => $v)
2263             {
2264                 if ($k == 'enabled')
2265                 {
2266                     continue;
2267                 }
2268 
2269                 if ($existingRow[$k] != $v)
2270                 {
2271                     $same = false;
2272                     break;
2273                 }
2274             }
2275 
2276             // Trying to add the same row as the existing one; quit
2277             if ($same)
2278             {
2279                 return;
2280             }
2281 
2282             // Otherwise it's not the same row. Remove the old row before insert a new one.
2283             $query = $db->getQuery(true)
2284                 ->delete($db->qn($tableName))
2285                 ->where($db->q('extension_id') . ' = ' . $db->q($options['extension_id']))
2286                 ->where($db->q('type') . ' = ' . $db->q($options['type']))
2287                 ->where($db->q('title_key') . ' = ' . $db->q($options['title_key']));
2288             $db->setQuery($query)->execute();
2289         }
2290 
2291         // Insert the new row
2292         $options = (object)$options;
2293         $db->insertObject($tableName, $options);
2294     }
2295 
2296     /**
2297      * Applies the post-installation messages for Joomla! 3.2 or later
2298      *
2299      * @return void
2300      */
2301     protected function _applyPostInstallationMessages()
2302     {
2303         // Make sure it's Joomla! 3.2.0 or later
2304         if (!version_compare(JVERSION, '3.2.0', 'ge'))
2305         {
2306             return;
2307         }
2308 
2309         // Make sure there are post-installation messages
2310         if (empty($this->postInstallationMessages))
2311         {
2312             return;
2313         }
2314 
2315         // Get the extension ID for our component
2316         $db = FOFPlatform::getInstance()->getDbo();
2317         $query = $db->getQuery(true);
2318         $query->select('extension_id')
2319             ->from('#__extensions')
2320             ->where($db->qn('type') . ' = ' . $db->q('component'))
2321             ->where($db->qn('element') . ' = ' . $db->q($this->componentName));
2322         $db->setQuery($query);
2323 
2324         try
2325         {
2326             $ids = $db->loadColumn();
2327         }
2328         catch (Exception $exc)
2329         {
2330             return;
2331         }
2332 
2333         if (empty($ids))
2334         {
2335             return;
2336         }
2337 
2338         $extension_id = array_shift($ids);
2339 
2340         foreach ($this->postInstallationMessages as $message)
2341         {
2342             $message['extension_id'] = $extension_id;
2343             $this->addPostInstallationMessage($message);
2344         }
2345     }
2346 
2347     protected function uninstallPostInstallationMessages()
2348     {
2349         // Make sure it's Joomla! 3.2.0 or later
2350         if (!version_compare(JVERSION, '3.2.0', 'ge'))
2351         {
2352             return;
2353         }
2354 
2355         // Make sure there are post-installation messages
2356         if (empty($this->postInstallationMessages))
2357         {
2358             return;
2359         }
2360 
2361         // Get the extension ID for our component
2362         $db = FOFPlatform::getInstance()->getDbo();
2363         $query = $db->getQuery(true);
2364         $query->select('extension_id')
2365             ->from('#__extensions')
2366             ->where($db->qn('type') . ' = ' . $db->q('component'))
2367             ->where($db->qn('element') . ' = ' . $db->q($this->componentName));
2368         $db->setQuery($query);
2369 
2370         try
2371         {
2372             $ids = $db->loadColumn();
2373         }
2374         catch (Exception $exc)
2375         {
2376             return;
2377         }
2378 
2379         if (empty($ids))
2380         {
2381             return;
2382         }
2383 
2384         $extension_id = array_shift($ids);
2385 
2386         $query = $db->getQuery(true)
2387             ->delete($db->qn('#__postinstall_messages'))
2388             ->where($db->qn('extension_id') . ' = ' . $db->q($extension_id));
2389 
2390         try
2391         {
2392             $db->setQuery($query)->execute();
2393         }
2394         catch (Exception $e)
2395         {
2396             return;
2397         }
2398     }
2399 }
2400 
Joomla! Framework TM API documentation generated by ApiGen 2.8.0
Joomla!® and Joomla! Framework™ are trademarks of Open Source Matters, Inc. in the United States and other countries.