Zac Mullett Engineering Services
Weblog

Archive for the ‘Software’ Category

Unicode file format for YAML fixtures file

Saturday, October 2nd, 2010

Running a doctrine:data-load on my Symfony web project’s data/fixtures.yml file and finding an empty database was my latest infuriation. I narrowed it down to some of the data having a Unicode character (the offending letter: รถ).

Initially I thought it may be the format that the database was configured to communicate or store in. While the collation was the default latin1_swedish_ci, this isn’t the problem because the collation only defines the rule set by which text is compared. I also found no settings restricting the input or storage form.

The problem was the storage format of the data/fixtures.yml file. Despite my text editor (TextPad in this case) being able to interpret the characters correctly in their 8-bit extended ANSI form, the Doctrine processor does not. You simply must save the file as Unicode format and it will then interpret correctly.

Oops moment with YAML “onDelete: SET NULL”

Friday, October 1st, 2010

I’ve begun using the Symfony MVC framework for a website I am developing. When trying to perform a doctrine:build to rebuild the database, I was noticing an error:

SQLSTATE[HY000]: General error: 1005 Can’t create table ‘mta.#sql-b90_1e0′ (errno: 150). Failing Query: “ALTER TABLE mta_album_instance ADD CONSTRAINT mta_album_instance_author_user_id_mta_user_id FOREIGN KEY (author_user_id) REFERENCES mta_user(id) ON DELETE SET NULL”. Failing Query: ALTER TABLE mta_album_instance ADD CONSTRAINT mta_album_instance_author_user_id_mta_user_id FOREIGN KEY (author_user_id) REFERENCES mta_user(id) ON DELETE SET NULL

Initially I was thrown because it writes “Can’t create table” for table that has clearly been created. Also it repeats itself just to make it a little harder to read. This is about adding a foreign key constraint though.

I want to set up my table so that a deletion in the foreign table will set a column to null. In Doctrine YAML this looks like so:

relations:
  MtaUser: { local: author_user_id, foreign: id, onDelete: SET NULL }

From the error output, the reason for the problem wasn’t obvious. It turned out to be that the column had a ‘not null’ attribution. Once this was removed everything was good.

author_user_id: { type: integer, notnull: true }

I hope this helps somebody.

Source Code for Items Assigned To Me Web Part

Monday, September 14th, 2009

The Assigned To Me Web Part displays a summary list of any item currently assigned to you. This web part is useful in cases where your SharePoint site is divided into numerous sub-sites and lists. Items are grouped by list with a sum total of items assigned to you per list.

To download this web part as a compiled WSP package, or for more information, click here:

public class AssignedToMe : System.Web.UI.WebControls.WebParts.WebPart
{
    protected override void Render(System.Web.UI.HtmlTextWriter writer)
    {
        // Controls are made in Render() rather than 
        // CreateChildControls() because the TBODY
        // tag does not appear to exist in the Web.UI
        // namespace and it is required for the SharePoint
        // expander javascript to work

        SPWeb spWebThis = SPControl.GetContextWeb(this.Context);

        List<SPWeb> webs = new List<SPWeb>();
        PopulateWebCollectionRecursive(webs, spWebThis);

        #region Create table and header rows
        Table table = new Table();
        this.Controls.Add(table);
        table.Attributes["class"] = "ms-settingsframe";
        table.Width = Unit.Percentage(100);
        table.BorderStyle = BorderStyle.None;
        table.CellPadding = 1;
        table.CellSpacing = 0;
        table.Style.Add("border-top", "0px solid");

        TableRow rowHeader = new TableRow();
        table.Rows.Add(rowHeader);

        TableCell cellHeaderTitle = new TableCell();
        rowHeader.Cells.Add(cellHeaderTitle);
        cellHeaderTitle.Wrap = false;
        cellHeaderTitle.Attributes["class"] = "ms-vh2-nofilter";
        cellHeaderTitle.Attributes["scope"] = "col";
        cellHeaderTitle.Text = "Item";

        TableCell cellHeaderModified = new TableCell();
        rowHeader.Cells.Add(cellHeaderModified);
        cellHeaderModified.Wrap = false;
        cellHeaderModified.Attributes["class"] = "ms-vh2-nofilter";
        cellHeaderModified.Attributes["scope"] = "col";
        cellHeaderModified.Text = "Modified";

        TableCell cellHeaderModifiedBy = new TableCell();
        rowHeader.Cells.Add(cellHeaderModifiedBy);
        cellHeaderModifiedBy.Wrap = false;
        cellHeaderModifiedBy.Attributes["class"] = "ms-vh2-nofilter";
        cellHeaderModifiedBy.Attributes["scope"] = "col";
        cellHeaderModifiedBy.Text = "Modified By";

        TableCell cellHeaderList = new TableCell();
        rowHeader.Cells.Add(cellHeaderList);
        cellHeaderList.Wrap = false;
        cellHeaderList.Attributes["class"] = "ms-vh2-nofilter";
        cellHeaderList.Attributes["scope"] = "col";
        cellHeaderList.Text = "List";

        TableCell cellHeaderSite = new TableCell();
        rowHeader.Cells.Add(cellHeaderSite);
        cellHeaderSite.Wrap = false;
        cellHeaderSite.Attributes["class"] = "ms-vh2-nofilter";
        cellHeaderSite.Attributes["scope"] = "col";
        cellHeaderSite.Text = "Site";

        table.RenderBeginTag(writer);
        rowHeader.RenderControl(writer);
        #endregion

        int count = 0;
        string rowClass = "";

        int listIndex = 0;
        foreach (SPWeb spWeb in webs)
        {
            foreach (SPList spList in spWeb.Lists)
            {
                try
                {
                    SPField spFieldAssignedTo = spList.Fields.GetFieldByInternalName("AssignedTo");
                    if (spFieldAssignedTo == null)
                        throw new Exception();
                }
                catch
                {
                    continue;
                }

                SPQuery spQuery = new SPQuery();

                spQuery.Query = String.Format(
                    "<Where><Eq><FieldRef Name='{0}' LookupId='TRUE' /><Value Type='User'>{1}"
                    + "</Value></Eq></Where>",
                    "AssignedTo",
                    spWebThis.CurrentUser.ID.ToString());

                SPListItemCollection spListItemCollection = spList.GetItems(spQuery);

                if (spListItemCollection.Count > 0)
                {
                    listIndex++;

                    // This is a (messy) replication of the code used
                    // by SharePoint's expanding/collapsing list viewer 
                    LiteralControl headerLiteral = new LiteralControl(String.Format(
                        "<TBODY id=\"titl{0}_\" groupString=\"\"><TR><TD colspan=\"100\" class=\"ms-gb\""
                        + " style=\"border-bottom: 0; border-top: 0;\" nowrap>"
                        + "<img src=\"/_layouts/images/blank.gif\" alt=\"\" height=1 width=0>"
                        + "<a href=\"javascript:\" onclick=\"javascript:ExpCollGroup('{0}_','img_{0}_');"
                        + "return false;\">"
                        + "<img id=\"img_{0}_\" src=\"/_layouts/images/plus.gif\" alt=\"Expand/Collapse\""
                        + " border=\"0\"></a>&nbsp;"
                        + "<a href=\"javascript:\" onclick=\"javascript:ExpCollGroup('{0}_','img_{0}_');"
                        + "return false;\">"
                        + "{1}</a>&nbsp;({2})</TD></TR></TBODY><TBODY id=\"tbod{0}__\""
                        + " style=\"display: none;\" isLoaded=\"true\">",
                        "1-" + listIndex,
                        spList.Title,
                        spListItemCollection.Count));

                    headerLiteral.RenderControl(writer);

                    int item = 0;
                    foreach (SPListItem spListItem in spListItemCollection)
                    {
                        #region Create controls for basic item information
                        TableRow rowItem = new TableRow();
                        rowItem.Attributes["class"] = rowClass;
                        table.Rows.Add(rowItem);

                        TableCell cellItemTitle = new TableCell();
                        rowItem.Cells.Add(cellItemTitle);
                        cellItemTitle.Attributes["class"] = "ms-vb2";
                        cellItemTitle.VerticalAlign = VerticalAlign.Top;

                        HyperLink anchorItemTitle = new HyperLink();
                        cellItemTitle.Controls.Add(anchorItemTitle);
                        anchorItemTitle.NavigateUrl = spList.Forms[PAGETYPE.PAGE_DISPLAYFORM]
                            .ServerRelativeUrl + "?ID=" + spListItem.ID;
                        string strItemName = "";

                        SPField fieldTitle = spListItem.Fields.GetFieldByInternalName("Title");
                        strItemName = fieldTitle.GetFieldValueAsText(spListItem[fieldTitle.Id]);

                        if (strItemName == null || strItemName.Trim().Length == 0)
                            strItemName = "(No title)";
                        anchorItemTitle.Text = strItemName;

                        TableCell cellItemModified = new TableCell();
                        rowItem.Cells.Add(cellItemModified);
                        cellItemModified.Attributes["class"] = "ms-vb2";
                        cellItemModified.Wrap = false;
                        cellItemModified.VerticalAlign = VerticalAlign.Top;

                        SPField fieldModified = spListItem.Fields.GetFieldByInternalName("Modified");
                        cellItemModified.Text = fieldModified.GetFieldValueAsText(
                            spListItem[fieldModified.Id]);

                        TableCell cellItemModifiedBy = new TableCell();
                        rowItem.Cells.Add(cellItemModifiedBy);
                        cellItemModifiedBy.Attributes["class"] = "ms-vb2";
                        cellItemModifiedBy.Wrap = false;
                        cellItemModifiedBy.VerticalAlign = VerticalAlign.Top;

                        SPField fieldModifiedBy = spListItem.Fields.GetFieldByInternalName("Editor");
                        cellItemModifiedBy.Text = fieldModifiedBy.GetFieldValueAsHtml(
                            spListItem[fieldModifiedBy.Id]);

                        TableCell cellItemList = new TableCell();
                        rowItem.Cells.Add(cellItemList);
                        cellItemList.Attributes["class"] = "ms-vb2";
                        cellItemList.Wrap = false;
                        cellItemList.VerticalAlign = VerticalAlign.Top;

                        HyperLink anchorList = new HyperLink();
                        cellItemList.Controls.Add(anchorList);
                        anchorList.NavigateUrl = spList.Forms[PAGETYPE.PAGE_DISPLAYFORM].ServerRelativeUrl;
                        anchorList.Text = spList.Title;

                        TableCell cellItemSite = new TableCell();
                        rowItem.Cells.Add(cellItemSite);
                        cellItemSite.Attributes["class"] = "ms-vb2";
                        cellItemSite.Wrap = false;
                        cellItemSite.VerticalAlign = VerticalAlign.Top;

                        HyperLink anchorWeb = new HyperLink();
                        cellItemSite.Controls.Add(anchorWeb);
                        anchorWeb.NavigateUrl = spWeb.ServerRelativeUrl;
                        anchorWeb.Text = spWeb.Title;

                        rowItem.RenderControl(writer);
                        #endregion

                        rowClass = (rowClass == "") ? "ms-alternating" : "";
                        count++;
                        item++;
                    }

                    TableRow rowSpacer = new TableRow();
                    table.Rows.Add(rowSpacer);

                    TableCell cellSpacer = new TableCell();
                    cellSpacer.ColumnSpan = table.Rows.Count;
                    cellSpacer.Text = "<img src=\"/_layouts/images/blank.gif\" alt=\"\" height=10 width=0>";
                    rowSpacer.Cells.Add(cellSpacer);

                    rowSpacer.RenderControl(writer);

                    LiteralControl footerLiteral = new LiteralControl(String.Format(
                        "</TBODY><TBODY id=\"foot{0}__\"></TBODY>",
                        "1-" + listIndex));

                    footerLiteral.RenderControl(writer);
                }
            }
        }

        if (count == 0)
        {
            #region Create controls for 'no items'
            TableRow rowItemNone = new TableRow();
            table.Rows.Add(rowItemNone);

            TableCell cellItemNone = new TableCell();
            rowItemNone.Cells.Add(cellItemNone);
            cellItemNone.ColumnSpan = table.Rows.Count;
            cellItemNone.Attributes["class"] = "ms-propertysheet";
            cellItemNone.VerticalAlign = VerticalAlign.Top;
            cellItemNone.Style.Add("padding-left", "5px");
            cellItemNone.Text = "No items";

            rowItemNone.RenderControl(writer);
            #endregion
        }

        table.RenderEndTag(writer);
    }

    private void PopulateWebCollectionRecursive(List<SPWeb> webs, SPWeb thisWeb)
    {
        webs.Add(thisWeb);

        // Important to use .GetSubwebsForCurrentUser() as opposed
        // to the .Webs collection, as the user may not be privileged
        // to certain webs
        foreach (SPWeb subWeb in thisWeb.GetSubwebsForCurrentUser())
            PopulateWebCollectionRecursive(webs, subWeb);
    }
}