ワイヤード・パンチ

元・大阪人が、岡山の山奥でも生きていけることを証明するためのブログ。

Osclassでユーザ情報にカスタムフィールドを追加する方法。

先日からずっと取り組んでいたものの、全く実装できずに苦しんでいた、Osclassでユーザ情報に対するカスタムフィールド追加。

調べてもその手順、というよりOsclassの情報そのものが少なく、もはや実装不可能と考え込んでいました。

ところが一転、質問サイトにも投稿してみたところ、ついに回答が届き、ようやくカスタムフィールドを実装することができました。

広告

解決のきっかけ。

PHP – osclassでユーザ情報にカスタムフィールドを追加したい。(146183)|teratail

プログラミングのことでわからないことがあれば、とりあえずお世話になるであろう、teratail。

WordPressとかのことであれば、投稿してからその日のうちに回答が来ることも多いでしょう。

でも、今回の質問の場合、投稿してから一週間経っても二週間経っても回答が来ませんでした。

Osclassの利用者がいないこともあってか、質問そのものが少なく、またOsclass用の質門検索タグも、私が要望を出す前には存在していない状態でした。

だから、いくらサイト自体の利用者が多くても、Osclassへの回答が来ることは、もはや望み薄かと思っていました。

ところが昨日、ようやく解決へのきっかけとなる質問が届きました。

この世に神っているんだなぁって…。

今回のOsclassでのサイト制作は、仕事のうえでやっていることであり、他のツールを使っての代案も許されない状況だったので、本当に助かりました。

やることの概要。

  1. データベースのユーザ情報用テーブルに、カスタムフィールド用のカラムを追加する。
  2. ユーザ情報用の配列に、新しいカスタムフィールドを追加する。
  3. 新しいカスタムフィールドの値を保存できるようにする。
  4. 管理画面上で新しいカスタムフィールドを入力できるようにする。
  5. 公開画面上の会員ページで、新しいカスタムフィールドを入力できるようにする。
  6. 公開画面上のプロフィールページで、新しいカスタムフィールドを表示させる。

なお、本来はよろしくないことなのですが、今回はOsclass本体のコアファイルを直接編集して対処することになります。

もしアップデートが来たときに編集内容が上書きされてしまうので、できればテーマかプラグインで対処したいところなのですが、そのための方法がわからないので、仕方ありません。

アップデートせずサイトを運用するよう、管理者に伝えておくしかありません。

データベースのユーザ情報用テーブルに、カスタムフィールド用のカラムを追加する。

前置きはここまでにして、回答をもとに実装方法をまとめることにします。

まずは、カスタムフィールドを収める領域を作るために、phpMyAdminを開いて、ユーザ情報が収められているテーブルに、カスタムフィールド用のカラムを追加しなければいけません。

というか以前まで、テーブルの操作が必要になるという考えを持っていなかったんですね…解決できないわけです。

まず、ユーザ情報に関するテーブルは「oc_t_user」なので、それを開きます。

ここで、もともとは「s_access_ip」というカラムが最後尾だったので、その後ろにカラムを追加しようとしたのですが、「‘dt_access_date’ へのデフォルト値が無効です。」と言われて、追加できませんでした。

なんでdt_access_dateが関係あんの?デフォルト値が無効ってどういう意味?

細かいことはわかりませんが、とにかく下記のリンクに書かれていることを参考にすれば、エラーなくカラムを追加することができました。

mysqlでAlter Tableがうまくいかなかった話

画面上のタブから「SQL」をクリックして、SQL文を直接実行する画面へ移動し、今回は下記のコードで「s_business_hours」というカラムを追加することにしました。

SET sql_mode = '';
ALTER TABLE `oc_t_user` ADD `s_business_hours` VARCHAR(1000) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL AFTER `s_access_ip`;

通常のカラム追加のSQL文の前に、「SET sql_mode = ”;」というSQL文を追加したことになります。

このコードを実行すると、返り値が0ですと言われますが、緑の背景のメッセージなので、いちおう正常な実行です。

コード実行後、画面上のタブから「構造」をまた開いてみると、先程のカラムが追加されているのが確認できるでしょう。

ユーザ情報用の配列に、新しいカスタムフィールドを追加する。

次に、Osclassの各所で使用されると思われる、ユーザ情報の各カラムの名前が収められた配列を編集します。

まず、下記のパスにあるファイルを開きます。

oc-includes\osclass\model\User.php

そこから、下記の部分を探します。

class User extends DAO
{
	/**
		*
		* @var type
		*/
	private static $instance;

	public static function newInstance()
	{
		if( !self::$instance instanceof self ) {
			self::$instance = new self;
		}
		return self::$instance;
	}

	/**
		*
		*/
	function __construct()
	{
		parent::__construct();
		$this->setTableName('t_user');
		$this->setPrimaryKey('pk_i_id');
		$array_fields = array(
			'pk_i_id',
			'dt_reg_date',
			'dt_mod_date',
			's_name',
			's_password',
			's_secret',
			's_username',
			's_email',
			's_website',
			's_phone_land',
			's_phone_mobile',
			'b_enabled',
			'b_active',
			's_pass_code',
			's_pass_date',
			's_pass_ip',
			'fk_c_country_code',
			's_country',
			's_address',
			's_zip',
			'fk_i_region_id',
			's_region',
			'fk_i_city_id',
			's_city',
			'fk_i_city_area_id',
			's_city_area',
			'd_coord_lat',
			'd_coord_long',
			'b_company',
			'i_items',
			'i_comments',
			'dt_access_date'
		);
		$this->setFields($array_fields);
	}

	(後略)

上記コードをみると、さきほどのテーブルのカラムの名前がずらずらと入った、配列があるのがわかるでしょう。

その配列の中に、先程テーブルに追加したカラムを後ろに入れるだけです。


			(前略)
			'i_comments',
			'dt_access_date',
			's_business_hours', // ←追加
		);
		$this->setFields($array_fields);
	}

	(後略)

新しいカスタムフィールドの値を保存できるようにする。

あらゆる画面でユーザ情報保存時に呼び出されると思われる処理があります。

まず、下記のパスにあるファイルを開きます。

oc-includes\osclass\UserActions.php

次に、下記のコードを見つけます。

function prepareData($is_add)
{
	$input = array();

	(中略)

	$input['fk_c_country_code'] = $countryId;
	$input['s_country'] = $countryName;
	$input['fk_i_region_id'] = $regionId;
	$input['s_region']	   = $regionName;
	$input['fk_i_city_id']   = $cityId;
	$input['s_city']		 = $cityName;
	$input['s_city_area']	= Params::getParam('cityArea');
	$input['s_address']	  = Params::getParam('address');
	$input['s_zip']		  = Params::getParam('zip');
	$input['d_coord_lat']	= (Params::getParam('d_coord_lat')  != '') ? Params::getParam('d_coord_lat') : null;
	$input['d_coord_long']   = (Params::getParam('d_coord_long') != '') ? Params::getParam('d_coord_long') : null;
	$input['b_company']	  = (Params::getParam('b_company') != '' && Params::getParam('b_company') != 0) ? 1 : 0;

	return($input);
}

function名に使われているprepareとは、作るとか準備するとかいう意味だそうです。

この関数の中に、新しいカスタムフィールドのカラム名を追加しましょう。

function prepareData($is_add)
{
	$input = array();

	(中略)

	$input['fk_c_country_code'] = $countryId;
	$input['s_country'] = $countryName;
	$input['fk_i_region_id'] = $regionId;
	$input['s_region']	   = $regionName;
	$input['fk_i_city_id']   = $cityId;
	$input['s_city']		 = $cityName;
	$input['s_city_area']	= Params::getParam('cityArea');
	$input['s_address']	  = Params::getParam('address');
	$input['s_zip']		  = Params::getParam('zip');
	$input['d_coord_lat']	= (Params::getParam('d_coord_lat')  != '') ? Params::getParam('d_coord_lat') : null;
	$input['d_coord_long']   = (Params::getParam('d_coord_long') != '') ? Params::getParam('d_coord_long') : null;
	$input['b_company']	  = (Params::getParam('b_company') != '' && Params::getParam('b_company') != 0) ? 1 : 0;

	$input['s_business_hours']	= Params::getParam('s_business_hours'); // ←追加

	return($input);
}

getParamという関数で、フォームの入力値を取得していると思われます。

管理画面上で新しいカスタムフィールドを入力できるようにする。

新しいカスタムフィールドを保存できるようになっても、それを入力できるフォームがないと意味がありません。

というわけで、まずは管理画面側のユーザ情報編集画面のフォームを編集しましょう。

まずは下記のファイルを開きます。

oc-includes\osclass\frm\User.form.class.php

下記コードのclassの中の好きな箇所に、入力ボックスを表示するための関数を追加します。

class UserForm extends Form {

	(前略)

	static public function business_hours_text($user = null) {
		parent::generic_input_text('s_business_hours', (isset($user['s_business_hours'])) ? $user['s_business_hours'] : null);
	}

	static public function corresponding_area_text($user = null) {
		parent::generic_textarea('s_corresponding_area', (isset($user['s_corresponding_area'])) ? $user['s_corresponding_area'] : null);
	}

	(後略)

一行ボックスと複数行ボックスで、それぞれ書き方が異なります。

引数は、各自のカラムに応じて書き換えましょう。

次は、管理画面側の入力フォームを表示する、下記のファイルを開きます。

oc-admin\themes\modern\users\frm.php

そのファイルの中から、下記の部分を探します。

<div class="settings-user">
		(中略)
		<fieldset>
		<div class="form-horizontal">
			(中略2)
		</div>
		</fieldset>
	</form>
</div>

上記のうち、(中略2)となっている箇所が、それぞれの入力ボックスの表示部分となっています。

表示したい場所に、先程追加した関数を実行すればいいでしょう。

<div class="form-row">
	<div class="form-label">営業時間</div>
	<div class="form-controls">

	</div>
</div>
<div class="form-row">
	<div class="form-label">対応地域</div>
	<div class="form-controls">

	</div>
</div>

これで管理画面にて、カスタムフィールドの保存ができるようになるはずです。

公開画面上の会員ページで、新しいカスタムフィールドを入力できるようにする。

管理画面だと管理者しか入れないので、サイトを利用する一般ユーザでも、カスタムフィールドを入力できるようにしないといけません。

使用中のテーマのuser-profile.phpを開き、管理画面のときと似たようなコードを、表示したい箇所に入れましょう。

<div class="control-group">
	<label class="control-label" for="s_business_hours">営業時間</label>
	<div class="controls">

	</div>
</div>
<div class="control-group">
	<label class="control-label" for="s_corresponding_area">対応地域</label>
	<div class="controls">

	</div>
</div>

上記はbenderテーマでの一例です。

公開画面上のプロフィールページで、新しいカスタムフィールドを表示させる。

最後に、入力したカスタムフィールドを、誰でも見れるプロフィールページでも表示されるようにしましょう。

まずは、カスタムフィールドの値を表示するための関数を作ります。

oc-includes\osclass\helpers\hUsers.php

function osc_user_business_hours() {
	return (string) osc_user_field("s_business_hours");
}

そして、使用中のテーマのuser-public-profile.phpで、表示したい部分で関数を実行すればOKです。

これでめでたく、カスタムフィールドの追加から表示までの流れが完了です。

余談。

冒頭でも書いたとおりですが、自力では決して解決できなかった今回の件に対して、回答していただけた方には、本当に圧倒的感謝です。

この件だけで仕事先と大きなトラブルになっており、いつまで経っても気が抜けない毎日ですが、ようやく肩の荷が降りました。

今回は解決できたのでよかったものの、情報が少ないツールなのに急ぎを要求される仕事を受けるのは、絶対にやめましょう。

正直言って今回の件が、在宅フリーランスとしてプログラミングの仕事をやめたくなった原因です。

追記。(2018/10/1)

この処理を入れてからなのかどうか、はっきりしないのですが、新しいユーザを登録しても、なぜかデータベースに登録されていないという事態に陥りました。

oc-includes\osclass\UserActions.php

上記ファイルを開くと、ユーザ登録処理を行うaddという関数があります。

function add()
{
	(略)

	$input = $this->prepareData(true);

	(略)

	$this->manager->insert($input);
	$userId = $this->manager->dao->insertedId();

$inputにはフォームで入力した値が入っており、$userIdには新しいユーザのIDが入ります。

insertという処理を実行後、insertedIdを実行することで、新しいユーザのIDが返ってくると思われるのですが、結果をvar_dumpで確認しても0でした。

成功していればおそらく、最後に作成したユーザのID+1が返ってくると思うのですが、0ということは失敗でしょう。

だから新しいユーザが作成できないのだと思われます。

oc-includes\osclass\classes\database\DAO.php

そして、なぜ0が返ってきてしまうのかは、上記ファイルの下記関数での結果だと思われます。

function insert($values)
{
	if( !$this->checkFieldKeys(array_keys($values)) ) {
		return false;
	}

	$this->dao->from($this->getTableName());
	$this->dao->set($values);
	return $this->dao->insert();
}

(略)

function checkFieldKeys($aKey)
{
	foreach($aKey as $key) {
		if( !in_array($key, $this->getFields()) ) {
			return false;
		}
	}

	return true;
}

insertの中で、さらにcheckFieldKeysを行っており、ここでfalseが返ってきてました。

しかし、なぜここでfalseになってしまうのかは、原因がさっぱりわかりませんでした。

ということでもう、下記のように問題の関数をコメントアウトしてしまって、trueが強制的に返ってくるようにしました。

function checkFieldKeys($aKey)
{
	/*
	foreach($aKey as $key) {
		if( !in_array($key, $this->getFields()) ) {
			return false;
		}
	}
	*/

	return true;
}

すると、新しいユーザがとりあえず作成できるようになりました。

念の為、広告投稿や既存ユーザの編集もやってみましたが、今のところは問題なし。

でも、原因もはっきりしないのにいじっていては、のちのちまた別のバグを生む恐れがありますが、ぼくにはもうOsclassは無理です。

このまま何も問題なく済んでくれることを願うしかありません。