Tag Archives: php

Eloquent HasManyThrough 5.5 functionality with version 5.1

The 5.1 version of HasManyThrough is limited; you cannot specify the key on the final table that connects it to the intermediate table.

If you’re unfortunately stuck on 5.1 but want this functionality, the following HasManyThrough should help. Tested with normally loading the relationship (ie modelInstance->relationship) and using with (ie model::with('relationship')->where()), not yet with has or whereHas.

<?php
use Illuminate\Database\Eloquent\Model as Eloquent;
use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Database\Eloquent\Relations\HasManyThrough;


/**
 * A custom version of HasManyThrough upgrading Eloquent 5.1 HasManyThrough to the 5.5 version.
 * This allows us to specify the key on the intermediate table connecting to the final table.
 */
class CustomHasManyThrough extends HasManyThrough {

    /**
     * The "through" parent model instance.
     *
     * @var \Illuminate\Database\Eloquent\Model
     */
    protected $throughParent;

    /**
     * The local key on the intermediary model.
     *
     * @var string
     */
    protected $secondLocalKey;

    /**
     * Create a new has many through relationship instance.
     *
     * @param  \Illuminate\Database\Eloquent\Builder  $query
     * @param  \Illuminate\Database\Eloquent\Model  $farParent
     * @param  \Illuminate\Database\Eloquent\Model  $throughParent
     * @param  string  $firstKey
     * @param  string  $secondKey
     * @param  string  $localKey
     * @param  string  $secondLocalKey
     * @return void
     */
    public function __construct($query, $farParent, $throughParent, $firstKey, $secondKey, $localKey, $secondLocalKey){
        $this->localKey = $localKey;
        $this->firstKey = $firstKey;
        $this->secondKey = $secondKey;
        $this->secondLocalKey = $secondLocalKey;

        $this->farParent = $farParent;        
        $this->throughParent = $throughParent;

        Relation::__construct($query, $throughParent);
    }

    /**
     * Get the fully qualified parent key name.
     *
     * @return string
     */
    public function getQualifiedParentKeyName(){
        return $this->parent->getTable().'.'.$this->secondLocalKey;
    }

    /**
     * Set the constraints for an eager load of the relation.
     *
     * @param  array  $models
     * @return void
     */
    public function addEagerConstraints(array $models)
    {
        $table = $this->parent->getTable();
        $this->query->whereIn($table.'.'.$this->firstKey, $this->getKeys($models, $this->localKey));
    }

    /**
     * Match the eagerly loaded results to their parents.
     *
     * @param  array   $models
     * @param  \Illuminate\Database\Eloquent\Collection  $results
     * @param  string  $relation
     * @return array
     */
    public function match(array $models, \Illuminate\Database\Eloquent\Collection $results, $relation)
    {
        $dictionary = $this->buildDictionary($results);
        // Once we have the dictionary we can simply spin through the parent models to
        // link them up with their children using the keyed dictionary to make the
        // matching very convenient and easy work. Then we'll just return them.
        foreach ($models as $model) {
            $key = $model->getAttribute($this->localKey);
            if (isset($dictionary[$key])) {
                $value = $this->related->newCollection($dictionary[$key]);
                $model->setRelation($relation, $value);
            }
        }
        return $models;
    }
}


class CustomEloquent extends Eloquent {

    /**
     * Replace the Eloquent has-many-through relationship with our custom one.
     *
     * @param  string  $related
     * @param  string  $through
     * @param  string|null  $firstKey
     * @param  string|null  $secondKey
     * @param  string|null  $localKey
     * @return \Illuminate\Database\Eloquent\Relations\HasManyThrough
     */
    public function hasManyThrough($related, $through, $firstKey = null, $secondKey = null, $localKey = null, $secondLocalKey = null){
        $through = new $through;
        $firstKey = $firstKey ?: $this->getForeignKey();
        $secondKey = $secondKey ?: $through->getForeignKey();
        $localKey = $localKey ?: $this->getKeyName();
        $secondLocalKey ?: $through->getKeyName();

        return new CustomHasManyThrough((new $related)->newQuery(), $this, $through, $firstKey, $secondKey, $localKey, $secondLocalKey);
    }
}

Adding php support to nginx (notes)

Already got nginx running with ruby, now I want a php site:

apt-get install php-cgi

configure nginx (mine is in a weird location, /opt/nginx/conf/nginx.conf:

server {
    listen 80;
    server_name my.hostname.local;
    root /path/to/site/public/;
    access_log /path/to/site/log/access.log;
    error_log /path/to/site/log/error.log;
    index index.php;
    location ~ \.php$ {
       try_files $uri =404;
       fastcgi_split_path_info ^(.+\.php)(/.+)$;
       include fastcgi_params;
       fastcgi_index index.php;
       fastcgi_param SCRIPT_FILENAME /path/to/site/public$fastcgi_script_name;
       fastcgi_pass localhost:8020;
    }
}

then start php

php-cgi -b 127.0.0.1:8020

and restart nginx

Getting git to deploy your site in branch folders via post-receive

Aim:  get the site deployed like so; [webroot]/[branch_name]

I’m using this on our development server, so the devs can view all branches on it.

I first set our server up as described in this previous post on deploying with virtualmin.  Then use the following in hooks-receive:

#!/bin/sh
#get the ref name
while read oldrev newrev ref
do
refbranch=”$ref”
done
#remove ref path</h1>
branch=`basename $refbranch`
#add full path
branchpath=”[your_webroot_full_path]/$branch”
#create directory if it doesn’t exist
if [ ! -d “$branchpath” ]; then
mkdir “$branchpath”
echo “Created new folder for branch $branch”
fi
cd “$branchpath”

git –git-dir=[path_to_git_dir] –work-tree=”$branchpath” checkout -f “$branch”
git –git-dir=[path_to_git_dir] –work-tree=”$branchpath” clean -fd
echo “Updated files in $branch directory”

Once you’ve done that, you may want to add a file to the web root so people know what branches they can view.  I’m using the following very simple php script (index.php, in my webroot):

<?php

$dirs = scandir(‘.’);
$remove = array(‘.’,’..’,’.gitignore’,’.project’,’index.php’,’git’);
$html = ”;
foreach($dirs as $dir){
  if(!in_array($dir,$remove)){
    $date = date(‘jS M Y’,filemtime($dir));
    $html .= ‘<a href=”/’ . $dir . ‘”>’ . $dir . ‘</a> – ‘ . $date . ‘<br />’;
  }
}

?>
<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN”
“http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>
<html>
<head>
<title>Development site</title>
</head>

<body>
<p>Please choose your branch (branch name – last modified):<br />
<?php echo $html; ?>
</p>
</body>

</html>

Add to the $remove array any files/directories you do not want showing up.

Transparent tiled watermark using GD with PHP

This is a basic method for dynamically adding tiled watermarks to images on your site.  It uses the .htaccess file to give the images to the PHP script which returns the image plus watermarking.

1) Create the image you want to be the watermark as a png with the opacity you want to be used (we’re not lowering the opacity later), and make sure to add extra space around the image according to how big you want the tiles.

2) Add this script to your site as watermark.php:
[sourcecode]
<?php

$watermark = imagecreatefrompng(‘/path/to/your/watermark.png’);
$imagesrc = ‘/path/to/image/’ . $_GET[‘src’];
$type = mime_content_type($imagesrc);
switch($type){
  case ‘image/jpeg’:
    $image = imagecreatefromjpeg($imagesrc);
    break;
  case ‘image/png’:
    $image = imagecreatefrompng($imagesrc);
    break;
  case ‘image/gif’:
    $image = imagecreatefromgif($imagesrc);
    break;
  default:
    $image = null;
}
if($image){
  # set dimensions
  $image_width = imagesx($image);
  $image_height = imagesy($image);
  imagealphablending($watermark, TRUE);

  # create the tile and overlay
  imagesettile($image,$watermark);
  imagefilledrectangle($image,0,0,$image_width,$image_height,IMG_COLOR_TILED);

  # output image
  header(‘content-type: image/jpeg’);
  imagejpeg($image);

  #clean up
  imagedestroy($image);
  imagedestroy($watermark);
}

?>
[/sourcecode]

3) Add rewrite rules in .htaccess.  Notice the $_GET[‘src’] in the script above; we need to hand this variable to the script.  In this example, anything in my gallery folder, or with the filename starting with wmark- will be passed to the script:
[sourcecode]
RewriteRule ^(.*)wp-content/uploads/wmark-(.*) $1path/to/watermark.php?src=wp-content/uploads/wmark-$2
RewriteRule ^(.*)wp-content/uploads/image-gallery/main_gallery/(.*) $1path/to/watermark.php?src=wp-content/uploads/image-gallery/main_gallery/$2

# If you want to exclude a particular image (excludeme.jpg), add this ABOVE the other rules.  The [L] tells it to ignore other rules
RewriteRule ^wp-content/uploads/excludeme\.jpg$ – [L]

[/sourcecode]

The script will only handle jpg/gif/png file types; if it’s possible that your rewrite rules will pass any other file types to the script, make sure to use (.*\.(gif|jpg|jpeg|png)) if it’s possible instead of just the basic (.*) in your rewrite rules.