By modimanz on
I have written a python script to autogenerate a set of files for module develpment for Drupal 7. This will create the, .info, .module, .install files and setup css, js, and includes subdirectories. Also a couple other files are created as well and entity functions if you are including entities in your module. This helps start a new module quickly by just typing a command. I use linux so I am not sure about this working in windows.
#!/usr/bin/python
# @Author = Morgan Massens
# @date = 2/17/2012
# @version = 1.0
#
# Creates a new Drupal 7 Module template using the following command:
# make_module.py <module_name> --path <path> <options>
# Options:
# --description: Description of module
# --path: Path where the module template will be created
# --full-name: Full name of the module
# --dependencies: List of dependencies
# --controller: Should we implement a controller?
# --package: The package this module belongs to
# --entities: Comma separated list of entites, encapsulate in quotes, no spaces
import sys,os
import re
import urllib
from optparse import OptionParser
import datetime
import logging
module_name = ""
full_name = ""
##
#
# @param name - name of the function (string)
# @param desc - doxygen description of the function (string)
# @param params list of tuples of params as param (list of tuples)
# - param[0] = name of parameter
# - param[1] = Description of parameter
# - param[2] = default Value
# --EXAMPLE [("param1","Description","Default Value"),("param2","Desc","Default")]
# @param returns - the doxygen return parameter (string)
# @param details - the extra doxygen info (list)
# @code = the code list of lines of code to be the function body (list)
#
##
def writeFunction(name, desc, params=None, returns=None, details=None, code=None):
global module_name
global full_name
# Set function name with module prefix
name = module_name+"_"+name
if params:
if params == None:
params = []
else:
params = []
if details:
if details == None:
details == []
else:
details = []
if code:
if code == None:
code = []
else:
code = []
# Document Parameters
output ="/**\n"
output+=" * "+desc+"\n"
output+=" * \n"
param_count = 0
for param in params:
param_count+=1
output+=" * @param "+param[0]+" " + param[2] + "\n"
if param_count > 0:
output+=" *\n"
for detail in details:
output+=" * "+detail+"\n"
if returns:
output+=" *\n * @returns "+returns+"\n"
output+=" */\n"
output+="function "+name+"("
comma = False
param_output = ""
for param in params:
if param_output <> "":
param_output+=", "
param_output+=param[0]
if param[2] <> "":
param_output+="="+param[2]
output+=param_output+")\n"
output+="{\n"
for line in code:
output+=" "+line+"\n"
output+="\n}\n\n"
return output
##
# Create the header of a php file for drupal.
#
# @param details the Doxygen description of the file.
#
# @returns string
##
def fileHeader(details):
output = "<?php\n// $Id$\n"
output+= "/**\n"
output+= " * @file\n"
output+= " * "+details+"\n"
output+= " * \n"
output+= " */\n\n"
return output
##
# Opens the path as a file and writes the data as the file.
##
def createFile(path, data):
f = open(path, 'w')
f.write(data)
f.close()
def main():
global module_name
global full_name
# Main function here
#
# Validate that the required arguments are set
usage = "usage: %prog module-name [options]"
parser = OptionParser(usage=usage)
parser.add_option('--description', help='Description of module')
parser.add_option('--path', help='Path where the module template will be created')
parser.add_option('--full-name', help='Full name of the module')
parser.add_option('--dependencies', help='List of dependencies')
parser.add_option('--controller', help='Should we implement a controller?')
parser.add_option('--package', help='The package this module belongs to')
parser.add_option('--entities', help='Comma separated list of entites, encapsulate in quotes, no spaces')
# Set command line options and args from the parser
(options, args) = parser.parse_args()
# Set required command line options
required_options = ['path']
for option in required_options:
if not options.__dict__[option]:
print 'missing required option', option
print
parser.print_help()
exit(1)
if not args:
print 'missing module-name'
print
parser.print_help()
exit(1)
# Get module_name and other values from command line args
module_name = args[0]
full_name = options.full_name if options.full_name else module_name
description = options.description if options.description else ""
#TODO Add Logging
#if options.log:
#Create files
install_dir = options.path+"/"
include_dir = install_dir+"includes/"
install_file = install_dir+module_name+".install"
info_file = install_dir+module_name+".info"
module_file = install_dir+module_name+".module"
include_file = include_dir+module_name+".inc"
form_file = include_dir+module_name+".form.inc"
#TODO Create a separate controller file for each controller
controller_file = include_dir+module_name+".controller.inc"
js_file = install_dir+"js/"+module_name+".js"
js_form_file = install_dir+"js/"+module_name+".form.js"
css_file = install_dir+"css/"+module_name+".css"
css_form_file = install_dir+"css/"+module_name+".form.css"
# Create Directories if theyt do not exist
if not os.path.exists(install_file):
#TODO Add error handling here
os.makedirs(install_dir)
os.makedirs(include_dir)
os.makedirs(install_dir+'css/')
os.makedirs(install_dir+'js/')
# Create Info File
php_code = ";Id$\nname = \""+full_name+"\"\n"
php_code+= "description = \""+description+"\"\n"
php_code+= "core = 7.x\n"
php_code+= "php = 5.1\n"
if options.package:
php_code+= "package = "+options.package+"\n"
php_code+="\n"
php_code+="files[] = "+module_name+".module\n"
php_code+="files[] = "+module_name+".install\n"
php_code+="files[] = includes/"+module_name+".inc\n"
php_code+="files[] = includes/"+module_name+".form.inc\n"
if options.controller:
php_code+="files[] = includes/"+module_name+".controller.inc\n"
createFile(info_file, php_code)
# Create Module File
# # Menu Hook
php_code = fileHeader(module_name+" Module.")
code =["$items = array();","$items[] = array();","","return $items;"]
php_code+= writeFunction("menu", "Implements hook_menu().", code=code)
# # Create entity hook if entities exist
code = []
if options.entities:
code.append("$return = array();")
for entity in options.entities.split(','):
code.append("$return['"+entity+"'] = array(")
code.append(" 'label' => t(''),")
code.append(" 'entity class' => t(''),")
code.append(" 'controller class' => t(''),")
code.append(" 'base table' => t(''),")
code.append(" 'revision table' => t(''),")
code.append(" 'uri callback' => t(''),")
code.append(" 'label callback' => t(''),")
code.append(" 'fieldable' => t(''),")
code.append(" 'entity keys' => array(")
code.append(" 'id' => '',")
code.append(" 'revision' => '',")
code.append(" 'label' => '',")
code.append(" ),")
code.append(" 'static cache' => TRUE,")
code.append(" 'view modes' => array(")
code.append(" 'full' => array(")
code.append(" 'label' => t('Full'),")
code.append(" 'custom setting' => TRUE,")
code.append(" ),")
code.append(" 'teaser' => array(")
code.append(" 'label' => t(''),")
code.append(" 'custom setting' => FALSE,")
code.append(" ),")
code.append(" ),")
code.append(");")
code.append('')
code.append('return $return;')
php_code+= writeFunction("entity_info", "Implements hook_entity_info().",code=code)
createFile(module_file, php_code)
# Create Install File
php_code = fileHeader(module_name+" Install File.")
# # Install Hook
code =["db_query(\"Update {system} SET weight = 104 WHERE name = '"+module_name+"'\");"]
php_code+= writeFunction(
"install",
"Implements hook_install().",
code = code)
# # Schema Hook
code =["$schema = array();","","return $schema"]
php_code+= writeFunction(
"schema",
"Implements hook_schema().",
code = code
)
createFile(install_file, php_code)
# Create Include File
php_code = fileHeader(module_name+" Includes Function.")
createFile(include_file, php_code)
if options.entities:
options.controller = True
# Create the controller file if controller was set
if options.controller:
#@TODO Add an options.entities property of comma separated entites. Create controler for each.
#@TODO <module_name>.<entity_name>.controller.inc
if options.entities:
entities = options.entities.split(',')
else:
entities = [module_name]
# Create Controller File
php_code = ""
file_head = ""
for entity in entities:
file_head+="\n * - "+entity+ " Controller"
entity_name = entity if entity <> module_name else ""
entity_fnc_name = entity+"_" if entity <> module_name else ""
mod_ent_fnc_name = module_name +"_"+ entity_fnc_name if entity_fnc_name <> "" else module_name+"_"
entity_title = entity.title() if entity == module_name else module_name.title() + " " + entity_name.title()
php_code+= "// *****************************************************************************\n"
php_code+= "// BEGIN Entity "+entity.title()+"\n"
php_code+= "// *****************************************************************************\n"
# # Create Function
code = []
code.append("$entity = entity_get_controller('"+entity+"')->create();")
code.append("")
code.append("return $entity;")
php_code+= writeFunction(entity_fnc_name+"create","Creates a new "+entity+" object.", code = code)
# # Load Function
code = []
code.append("$ids = isset($id) ? array($id) : array();")
code.append("$conditions = (isset($vid) ? array('vid' => $vid) : array());")
code.append("$entity = "+mod_ent_fnc_name+"load_multiple($ids, $conditions, $reset);")
code.append("return $entity ? reset($entity) : FALSE;")
php_code+= writeFunction(
entity_fnc_name+"load",
"Loads a new "+entity_title+" object.",
params = [('$id','integer','NULL'),('$vid','integer','NULL'),('$reset', '', 'FALSE')],
returns = "\"object\"",
code = code)
# # Load Multiple Function
code = []
code.append("$entities = entity_load('"+entity+"', $ids, $conditions, $reset);")
code.append("return $entities;")
php_code+= writeFunction(
entity_fnc_name+"load_multiple",
"Loads multiple "+entity+" objects.",
params = [('$ids','array of integers','NULL'),
('$conditions','array of key=>value pairs','array()'),
('$reset','boolean','FALSE')],
returns = "array of objects",
code = code)
# # Save function
code = []
code.append("$save = entity_get_controller('"+entity+"')->save($"+entity+", $transaction);")
code.append("return $save;")
php_code+= writeFunction(
entity_fnc_name+"save",
"Save a "+entity_name+" object.",
params = [("&$"+entity_name,entity_title+" Entity Object",""),("$transaction","","NULL")],
code = code)
# # Delete function
code = []
code.append("return "+mod_ent_fnc_name+"delete_multiple(array($id), $transaction);")
php_code+= writeFunction(
entity_fnc_name+"delete",
"Delete a "+entity_name+" object.",
params = [("$id",entity_title+" Entity ID",""),("$transaction","","NULL")],
code = code)
# # Delete Multiple Function
code = []
code.append("$transaction = (!is_null($transaction))? $transaction : db_transaction();")
code.append("")
code.append("return entity_get_controller('"+entity+"')->delete($ids, $transaction)")
php_code+= writeFunction(
entity_fnc_name+"delete_multiple",
" Delete Multiple "+entity+" objects.",
params = [("$ids",entity_title+" Entity IDS",""),("$transaction","","NULL")],
code = code)
php_code = fileHeader(module_name+" Controller Function."+file_head) + php_code
createFile(controller_file, php_code)
# Create Form File
# Set the file header
php_code = fileHeader(module_name+" Form Functions.")
#TODO Create form file functions here (per entity?)
# code = []
# code.append()
# php_code+=writeFunction(
# entity_fnc_name+"form",
# " Edit the entity",
# .....
# )
createFile(form_file, php_code)
# Create JS file
createFile(js_file, "")
createFile(js_form_file, "")
# Create CSS files
createFile(css_file, "")
createFile(css_form_file, "")
main()
Comments
Sorry extra libraries in above code.
You can safely remove the urllib, re, datetime and logging libraries from this python script, I was going to get really fancy with this script, but for now this will do.
Thanks! Should save a lot of
Thanks! Should save a lot of time.
Digit Professionals specialising in Drupal, WordPress & CiviCRM support for publishers in non-profit and related sectors
Missing semicolon on line 260
Using this script mi module.install file was created without a semicolon in the hook_schema funcion.
I believe that line 260 should be:
code =["$schema = array();","","return $schema;"]Thanks for this useful script.
---Luca
Nice script
Would be nice if the template files included more sample code, eventually in a --sample TRUE option. I may do that and post here.
How is that different from
How is that different from Examples module?
Digit Professionals specialising in Drupal, WordPress & CiviCRM support for publishers in non-profit and related sectors